org.eclipse.debug.internal.ui.views.memory.RenderingViewPane.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.debug.internal.ui.views.memory.RenderingViewPane.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *     WindRiver - Bug 192028 [Memory View] Memory view does not 
 *                 display memory blocks that do not reference IDebugTarget
 *     ARM - Bug 192028 [Memory View] Memory view does not 
 *                 display memory blocks that do not reference IDebugTarget
 *     WindRiver - Bug 216509 [Memory View] typo, s/isMeomryBlockRemoved/isMemoryBlockRemoved
 *     Wind River Systems - Ted Williams - [Memory View] Memory View: Workflow Enhancements (Bug 215432)
 *******************************************************************************/
package org.eclipse.debug.internal.ui.views.memory;

import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.views.memory.renderings.CreateRendering;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.memory.IMemoryRendering;
import org.eclipse.debug.ui.memory.IMemoryRenderingContainer;
import org.eclipse.debug.ui.memory.IMemoryRenderingSite;
import org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService;
import org.eclipse.debug.ui.memory.IResettableMemoryRendering;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Adapter;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.UIJob;

/**
 * Represents a rendering view pane in the Memory View.
 * This hosts the memory view tabs in the view.
 * @since 3.1
 *
 */
public class RenderingViewPane extends AbstractMemoryViewPane implements IMemoryRenderingContainer {

    public static final String RENDERING_VIEW_PANE_ID = DebugUIPlugin.getUniqueIdentifier()
            + ".MemoryView.RenderingViewPane"; //$NON-NLS-1$

    private Hashtable fTabFolderForMemoryBlock = new Hashtable();
    private Hashtable fMemoryBlockFromTabFolder = new Hashtable();

    private ViewPaneRenderingMgr fRenderingMgr;

    private IMemoryRenderingSite fRenderingSite;
    private Set fAddedRenderings = new HashSet();
    private Set fAddedMemoryBlocks = new HashSet();

    private boolean fCanAddRendering = true;
    private boolean fCanRemoveRendering = true;

    /**
     * @param parent is the view hosting this view pane
     * @param paneId is the identifier assigned by the Memory View
     * 
     * Pane id is assigned with the following format.  
     * Rendering view pane created has its id assigned to 
     * org.eclipse.debug.ui.MemoryView.RenderingViewPane.#.  
     * # is a number indicating the order of which the rendering view
     * pane is created.  First rendering view pane created will have its
     * id assigned to org.eclipse.debug.ui.MemoryView.RenderingViewPane.1.
     * Second rendering view pane created will have its id assigned to
     * org.eclipse.debug.ui.MemoryView.RenderingViewPane.2. and so on.
     * View pane are created from left to right by the Memory View.
     * 
     */
    public RenderingViewPane(IViewPart parent) {
        super(parent);

        if (parent instanceof IMemoryRenderingSite)
            fRenderingSite = (IMemoryRenderingSite) parent;
        else {
            DebugUIPlugin.logErrorMessage("Parent for the rendering view pane is invalid."); //$NON-NLS-1$
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.core.memory.IMemoryBlockListener#MemoryBlockAdded(org.eclipse.debug.core.model.IMemoryBlock)
     */
    public void memoryBlocksAdded(final IMemoryBlock[] memoryBlocks) {
        Display.getDefault().asyncExec(new Runnable() {
            public void run() {

                if (isDisposed())
                    return;

                // check condition before doing anything
                if (memoryBlocks == null || memoryBlocks.length <= 0)
                    return;

                for (int i = 0; i < memoryBlocks.length; i++) {
                    IMemoryBlock memory = memoryBlocks[i];

                    if (!fTabFolderForMemoryBlock.containsKey(memory)) {
                        createFolderForMemoryBlock(memory);
                    }
                    fAddedMemoryBlocks.add(memory);
                    updateToolBarActionsEnablement();
                }
            }
        });
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.core.memory.IMemoryBlockListener#MemoryBlockRemoved(org.eclipse.debug.core.model.IMemoryBlock)
     */
    public void memoryBlocksRemoved(final IMemoryBlock[] memoryBlocks) {
        Display.getDefault().asyncExec(new Runnable() {
            public void run() {
                for (int j = 0; j < memoryBlocks.length; j++) {
                    IMemoryBlock mbRemoved = memoryBlocks[j];
                    if (fTabFolderForMemoryBlock == null) {
                        return;
                    }

                    // get all renderings from this memory block and remove them from the view
                    IMemoryRendering[] renderings = fRenderingMgr.getRenderingsFromMemoryBlock(mbRemoved);

                    for (int k = 0; k < renderings.length; k++) {
                        removeMemoryRendering(renderings[k]);
                    }

                    // remove a the tab folder if the memory block is removed
                    CTabFolder tabFolder = (CTabFolder) fTabFolderForMemoryBlock.get(mbRemoved);

                    if (tabFolder == null)
                        continue;

                    fTabFolderForMemoryBlock.remove(mbRemoved);
                    fMemoryBlockFromTabFolder.remove(tabFolder);
                    IMemoryBlockRetrieval retrieve = MemoryViewUtil.getMemoryBlockRetrieval(mbRemoved);
                    if (retrieve != null) {
                        if (fTabFolderForDebugView.contains(tabFolder)) {
                            fTabFolderForDebugView.remove(MemoryViewUtil.getHashCode(retrieve));
                        }
                    }

                    if (!tabFolder.isDisposed()) {
                        // dispose all view tabs belonging to the tab folder
                        CTabItem[] items = tabFolder.getItems();

                        for (int i = 0; i < items.length; i++) {
                            disposeTab(items[i]);
                        }

                        // dispose the tab folder
                        tabFolder.dispose();

                        // if this is the top control
                        if (tabFolder == fStackLayout.topControl) {

                            // if memory view is visible and have a selection
                            // follow memory view's selection

                            ISelection selection = DebugUIPlugin.getActiveWorkbenchWindow().getSelectionService()
                                    .getSelection(IDebugUIConstants.ID_MEMORY_VIEW);
                            IMemoryBlock mbToSelect = getMemoryBlock(selection);

                            if (mbToSelect != null) {
                                // memory view may not have got the event and is still displaying
                                // the deleted memory block
                                if (mbToSelect != mbRemoved)
                                    handleMemoryBlockSelection(null, mbToSelect);
                                else if ((MemoryViewUtil.getMemoryBlockManager()
                                        .getMemoryBlocks(retrieve).length > 0)) {
                                    mbToSelect = MemoryViewUtil.getMemoryBlockManager()
                                            .getMemoryBlocks(retrieve)[0];
                                    handleMemoryBlockSelection(null, mbToSelect);
                                } else {
                                    emptyFolder();
                                }
                            } else if (MemoryViewUtil.getMemoryBlockManager()
                                    .getMemoryBlocks(retrieve).length > 0) { // get to the next folder
                                mbToSelect = MemoryViewUtil.getMemoryBlockManager().getMemoryBlocks(retrieve)[0];
                                handleMemoryBlockSelection(null, mbToSelect);
                            } else {
                                emptyFolder();

                            }
                        }

                        // if not the top control
                        // no need to do anything
                    }

                    fAddedMemoryBlocks.remove(mbRemoved);
                    updateToolBarActionsEnablement();
                }
            }
        });

    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
        if (isDisposed())
            return;

        // do not schedule job if any of these conditions are true
        if (part == RenderingViewPane.this)
            return;

        if (!(selection instanceof IStructuredSelection))
            return;

        if (selection == AbstractMemoryViewPane.EMPTY)
            return;

        UIJob job = new UIJob("RenderingViewPane selectionChanged") { //$NON-NLS-1$

            public IStatus runInUIThread(IProgressMonitor monitor) {
                try {

                    if (isDisposed())
                        return Status.OK_STATUS;

                    if (selection.isEmpty()) {
                        // if the event comes from Memory View
                        // pick empty tab folder as the memory view is no longer displaying anything
                        if (part.getSite().getId().equals(IDebugUIConstants.ID_MEMORY_VIEW)) {
                            if (part == getMemoryRenderingSite().getSite().getPart()) {
                                IMemoryViewTab lastViewTab = getTopMemoryTab();

                                if (lastViewTab != null)
                                    lastViewTab.setEnabled(false);

                                emptyFolder();
                            }
                        }

                        // do not do anything if there is no selection
                        // In the case when a debug adpater fires a debug event incorrectly, Launch View sets
                        // selection to nothing.  If the view tab is disabled, it erases all the "delta" information
                        // in the content.  This may not be desirable as it will cause memory to show up as
                        // unchanged when it's actually changed.  Do not disable the view tab until there is a 
                        // valid selection.

                        return Status.OK_STATUS;
                    }

                    // back up current view tab
                    IMemoryViewTab lastViewTab = getTopMemoryTab();

                    if (!(selection instanceof IStructuredSelection))
                        return Status.OK_STATUS;

                    Object elem = ((IStructuredSelection) selection).getFirstElement();

                    if (elem instanceof IMemoryBlock) {
                        // if the selection event comes from this view
                        if (part == getMemoryRenderingSite()) {
                            // find the folder associated with the given IMemoryBlockRetrieval
                            IMemoryBlock memBlock = (IMemoryBlock) elem;

                            // should never get here... added code for safety
                            if (fTabFolderForMemoryBlock == null) {
                                if (lastViewTab != null)
                                    lastViewTab.setEnabled(false);

                                emptyFolder();
                                return Status.OK_STATUS;
                            }

                            handleMemoryBlockSelection(lastViewTab, memBlock);
                        }
                    }
                } catch (SWTException se) {
                    DebugUIPlugin.log(se);
                }
                return Status.OK_STATUS;
            }
        };
        job.setSystem(true);
        job.schedule();
    }

    public void handleMemoryBlockSelection(final IMemoryViewTab lastViewTab, final IMemoryBlock memBlock) {
        // Do not check if the debug target of mb is removed
        // We should not get into this method if the debug target of the memory block is terminated
        // Memory Block Manager gets the terminate event and would have removed all memory blocks
        // associated with the debug target
        // Therefore, we will never try to set a selection to a memory block whose target is terminated

        // check current memory block
        CTabFolder currentFolder = (CTabFolder) fStackLayout.topControl;
        if (currentFolder != null && !currentFolder.isDisposed()) {
            IMemoryBlock currentBlk = (IMemoryBlock) fMemoryBlockFromTabFolder.get(currentFolder);
            if (currentBlk != null) {
                if (currentBlk == memBlock)
                    return;
            }
        }

        if (getTopMemoryTab() != null) {
            if (getTopMemoryTab().getRendering().getMemoryBlock() == memBlock) {
                return;
            }
        }

        // if we've got a tabfolder to go with the IMemoryBlock, display
        // it
        if (fTabFolderForMemoryBlock.containsKey(memBlock)) {
            if (fStackLayout.topControl != (CTabFolder) fTabFolderForMemoryBlock.get(memBlock)) {
                setTabFolder((CTabFolder) fTabFolderForMemoryBlock.get(memBlock));
                fViewPaneCanvas.layout();
            }
        } else { // otherwise, add a new one
            CTabFolder folder = createTabFolder(fViewPaneCanvas);

            fTabFolderForMemoryBlock.put(memBlock, folder);
            fMemoryBlockFromTabFolder.put(folder, memBlock);
            setTabFolder((CTabFolder) fTabFolderForMemoryBlock.get(memBlock));
            fViewPaneCanvas.layout();
            fAddedMemoryBlocks.add(memBlock);

            newCreateRenderingForFolder(memBlock, folder);
        }

        // restore view tabs
        IMemoryRendering[] renderings = fRenderingMgr.getRenderingsFromMemoryBlock(memBlock);
        CTabFolder toDisplay = (CTabFolder) fStackLayout.topControl;

        // if only CreateRendering is present, restore renderings
        if (isRestoreViewTabs(toDisplay)) {
            restoreViewTabs(renderings);
        }

        // disable last view tab as it becomes hidden
        IMemoryViewTab newViewTab = getTopMemoryTab();

        if (lastViewTab != null && lastViewTab != newViewTab) {
            lastViewTab.setEnabled(false);
        }

        if (newViewTab != null) {
            // if new view tab is not already enabled, enable it
            if (!newViewTab.isEnabled()) {
                // if the view tab is visible, enable it
                if (fVisible) {
                    newViewTab.setEnabled(fVisible);
                }
            }
        }

        IMemoryViewTab viewTab = getTopMemoryTab();
        if (viewTab != null)
            setRenderingSelection(viewTab.getRendering());

        //set toolbar actions enabled/disabled
        updateToolBarActionsEnablement();
    }

    private boolean isRestoreViewTabs(CTabFolder folder) {
        if (canAddRendering())
            return (folder.getItemCount() == 1 && getTopMemoryTab().getRendering() instanceof CreateRendering);
        else
            return (folder.getItemCount() == 0);
    }

    private int getIndexOfCreateRenderingTab(CTabFolder folder) {
        for (int i = 0; i < folder.getItemCount(); i++)
            if (folder.getItem(i).getData() instanceof MemoryViewTab
                    && ((MemoryViewTab) folder.getItem(i).getData()).getRendering() instanceof CreateRendering)
                return i;

        return -1;
    }

    public void memoryBlockRenderingAdded(final IMemoryRendering rendering) {

        Display.getDefault().asyncExec(new Runnable() {
            public void run() {

                if (isDisposed())
                    return;

                if (fAddedRenderings.contains(rendering))
                    return;

                IMemoryBlock memoryblk = rendering.getMemoryBlock();

                CTabFolder tabFolder = (CTabFolder) fTabFolderForMemoryBlock.get(memoryblk);

                if (tabFolder == null) {
                    tabFolder = createFolderForMemoryBlock(memoryblk);
                }

                if (tabFolder == fStackLayout.topControl) {
                    // disable current view tab
                    if (getTopMemoryTab() != null) {
                        deactivateRendering(getTopMemoryTab());
                        getTopMemoryTab().setEnabled(false);
                    }
                }
                fAddedRenderings.add(rendering);

                int index = getIndexOfCreateRenderingTab(tabFolder);
                if (index < 0)
                    index = 0;
                CTabItem tab = createTab(tabFolder, index);

                MemoryViewTab viewTab = new MemoryViewTab(tab, rendering, getInstance());
                tabFolder.setSelection(tabFolder.indexOf(tab));

                if (tabFolder == fStackLayout.topControl) {
                    setRenderingSelection(viewTab.getRendering());

                    // disable top view tab if the view pane is not visible
                    IMemoryViewTab top = getTopMemoryTab();
                    if (top != null)
                        top.setEnabled(fVisible);
                } else {
                    deactivateRendering(viewTab);
                    viewTab.setEnabled(false);
                }

                updateToolBarActionsEnablement();
            }
        });
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.core.memory.IMemoryRenderingListener#MemoryBlockRenderingRemoved(org.eclipse.debug.internal.core.memory.IMemoryRendering)
     */
    public void memoryBlockRenderingRemoved(final IMemoryRendering rendering) {
        final IMemoryBlock memory = rendering.getMemoryBlock();

        // need to run the following code on the UI Thread to avoid invalid thread access exception
        Display.getDefault().asyncExec(new Runnable() {
            public void run() {
                if (!fAddedRenderings.contains(rendering))
                    return;

                fAddedRenderings.remove(rendering);

                CTabFolder tabFolder = (CTabFolder) fStackLayout.topControl;

                if (tabFolder.isDisposed())
                    return;

                CTabItem[] tabs = tabFolder.getItems();
                boolean foundTab = false;
                for (int i = 0; i < tabs.length; i++) {
                    IMemoryViewTab viewTab = (IMemoryViewTab) tabs[i].getData();

                    if (tabs[i].isDisposed())
                        continue;

                    if (viewTab.getRendering().getMemoryBlock() == memory) {
                        if (viewTab.getRendering() == rendering) {
                            foundTab = true;
                            disposeTab(tabs[i]);
                            break;
                        }

                    }
                }

                // if a tab is not found in the current top control
                // this deletion is a result of a debug target termination
                // find memory from other folder and dispose the view tab
                if (!foundTab) {
                    Enumeration enumeration = fTabFolderForMemoryBlock.elements();
                    while (enumeration.hasMoreElements()) {
                        CTabFolder otherTabFolder = (CTabFolder) enumeration.nextElement();
                        tabs = otherTabFolder.getItems();
                        IMemoryViewTab viewTab = null;
                        for (int i = 0; i < tabs.length; i++) {
                            viewTab = (IMemoryViewTab) tabs[i].getData();
                            if (viewTab.getRendering().getMemoryBlock() == memory) {
                                if (viewTab.getRendering() == rendering) {
                                    foundTab = true;
                                    disposeTab(tabs[i]);
                                    break;
                                }
                            }
                        }
                    }
                }
                IMemoryViewTab top = getTopMemoryTab();

                // update selection
                if (top != null)
                    setRenderingSelection(top.getRendering());

                updateToolBarActionsEnablement();
            }
        });

    }

    /**
     * @param viewTab
     */
    protected void setRenderingSelection(IMemoryRendering rendering) {

        if (rendering != null) {
            fSelectionProvider.setSelection(new StructuredSelection(rendering));
        }
    }

    private void restoreViewTabs(IMemoryRendering[] renderings) {
        for (int i = 0; i < renderings.length; i++) {
            memoryBlockRenderingAdded(renderings[i]);
        }
    }

    private void handleDebugElementSelection(final IMemoryViewTab lastViewTab, final IAdaptable element) {
        // get current memory block retrieval and debug target
        IMemoryBlockRetrieval currentRetrieve = null;

        // get tab folder
        CTabFolder tabFolder = (CTabFolder) fStackLayout.topControl;

        // get memory block
        IMemoryBlock currentBlock = (IMemoryBlock) fMemoryBlockFromTabFolder.get(tabFolder);

        if (currentBlock != null) {
            currentRetrieve = MemoryViewUtil.getMemoryBlockRetrieval(currentBlock);

            // backup current retrieve and tab folder
            if (currentRetrieve != null && tabFolder != null) {
                fTabFolderForDebugView.put(MemoryViewUtil.getHashCode(currentRetrieve), tabFolder);
            }
        }

        // find the folder associated with the given IMemoryBlockRetrieval
        IMemoryBlockRetrieval retrieve = MemoryViewUtil.getMemoryBlockRetrieval(element);

        // if debug target has changed
        // switch to that tab folder
        if (retrieve != null && retrieve != currentRetrieve) {
            Integer key = MemoryViewUtil.getHashCode(retrieve);
            CTabFolder folder = (CTabFolder) fTabFolderForDebugView.get(key);

            if (folder != null) {
                setTabFolder(folder);
                fTabFolderForDebugView.put(key, folder);
                fViewPaneCanvas.layout();
            } else {
                // find out if there is any memory block for this debug target
                // and set up tab folder for the memory blocks
                IMemoryBlock blocks[] = MemoryViewUtil.getMemoryBlockManager().getMemoryBlocks(retrieve);

                if (blocks.length > 0) {
                    handleMemoryBlockSelection(null, blocks[0]);
                } else {
                    emptyFolder();
                    fTabFolderForDebugView.put(key, fEmptyTabFolder);
                    fViewPaneCanvas.layout();
                }
            }
        }

        // disable last view tab as it becomes hidden
        IMemoryViewTab newViewTab = getTopMemoryTab();

        if (lastViewTab != null && lastViewTab != newViewTab) {
            lastViewTab.setEnabled(false);
        }

        if (newViewTab != null) {
            // if new view tab is not already enabled, enable it
            if (!newViewTab.isEnabled()) {
                // if the view tab is visible, enable it
                if (fVisible) {
                    newViewTab.setEnabled(fVisible);
                }
            }

            // should only change selection if the new view tab is different
            if (lastViewTab != newViewTab)
                setRenderingSelection(newViewTab.getRendering());
        }
        //set toolbar actions enabled/disabled
        updateToolBarActionsEnablement();
    }

    protected void addListeners() {
        super.addListeners();

        // must directly listen for selection events from parent's selection provider
        // to ensure that we get the selection event from the tree viewer pane even
        // if the view does not have focuse
        fParent.getSite().getSelectionProvider().addSelectionChangedListener(this);
    }

    protected void removeListeners() {
        super.removeListeners();
        fParent.getSite().getSelectionProvider().removeSelectionChangedListener(this);
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
     */
    public void widgetSelected(SelectionEvent e) {

        if (getTopMemoryTab() == null)
            return;

        IMemoryRendering rendering = getTopMemoryTab().getRendering();

        if (rendering != null) {
            fSelectionProvider.setSelection(new StructuredSelection(rendering));
        }

    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
     */
    public void widgetDefaultSelected(SelectionEvent e) {
    }

    public Object getCurrentSelection() {
        if (getTopMemoryTab() != null)
            if (getTopMemoryTab().getRendering() != null)
                return getTopMemoryTab().getRendering();
        return null;
    }

    /* (non-Javadoc)
     * @see com.ibm.debug.extended.ui.IMemoryView#getAllViewTabs()
     */
    public IMemoryViewTab[] getAllViewTabs() {

        // otherwise, find the view tab to display
        CTabFolder folder = (CTabFolder) fStackLayout.topControl;
        CTabItem[] items = folder.getItems();

        IMemoryViewTab[] viewTabs = new IMemoryViewTab[folder.getItemCount()];

        for (int i = 0; i < items.length; i++) {
            viewTabs[i] = (IMemoryViewTab) items[i].getData();
        }

        return viewTabs;
    }

    /* (non-Javadoc)
     * @see com.ibm.debug.extended.ui.IMemoryView#moveToTop(com.ibm.debug.extended.ui.IMemoryViewTab)
     */
    public void moveToTop(IMemoryViewTab viewTab) {

        IMemoryViewTab lastViewTab = getTopMemoryTab();

        if (viewTab == lastViewTab)
            return;

        // otherwise, find the view tab to display
        CTabFolder folder = (CTabFolder) fStackLayout.topControl;
        CTabItem[] items = folder.getItems();

        for (int i = 0; i < items.length; i++) {
            IMemoryViewTab tab = (IMemoryViewTab) items[i].getData();
            if (viewTab == tab) {

                boolean isEnabled = lastViewTab.isEnabled();

                // switch to that viewTab
                lastViewTab.setEnabled(false);
                folder.setSelection(i);

                setRenderingSelection(tab.getRendering());

                getTopMemoryTab().setEnabled(isEnabled && fVisible);
                break;
            }
        }
    }

    private CTabFolder createTabFolder(Composite parent) {
        CTabFolder folder = new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT);

        ColorRegistry reg = JFaceResources.getColorRegistry();
        Color c1 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$
                c2 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$
        folder.setSelectionBackground(new Color[] { c1, c2 }, new int[] { 100 }, true);
        folder.setSelectionForeground(reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$
        folder.setSimple(PlatformUI.getPreferenceStore()
                .getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS));
        folder.setBorderVisible(true);
        folder.setFont(fViewPaneCanvas.getFont());

        folder.addCTabFolder2Listener(new CTabFolder2Adapter() {
            public void close(CTabFolderEvent event) {
                if (event.item.getData() instanceof MemoryViewTab)
                    RenderingViewPane.this
                            .removeMemoryRendering(((MemoryViewTab) event.item.getData()).getRendering());
                event.doit = false;
            }
        });
        return folder;
    }

    public void restoreViewPane() {

        // get current selection from memory view

        ISelection selection = null;
        if (fParent.getSite().getSelectionProvider() != null)
            selection = fParent.getSite().getSelectionProvider().getSelection();

        IMemoryBlock memoryBlock = null;
        if (selection != null) {
            memoryBlock = getMemoryBlock(selection);
        }

        if (memoryBlock == null) {
            // get selection from this view
            selection = fSelectionProvider.getSelection();

            if (MemoryViewUtil.isValidSelection(selection)) {
                Object elem = ((IStructuredSelection) selection).getFirstElement();

                if (!(elem instanceof IMemoryBlock))
                    return;

                memoryBlock = (IMemoryBlock) elem;
            }
        }

        if (memoryBlock == null) {
            // get a memory block from current debug context
            IAdaptable context = DebugUITools.getPartDebugContext(fParent.getSite());
            if (context != null) {
                IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(context);

                if (retrieval != null) {
                    IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager()
                            .getMemoryBlocks(retrieval);
                    if (blocks.length > 0)
                        memoryBlock = blocks[0];
                }
            }
        }

        if (memoryBlock != null) {
            if (!fTabFolderForMemoryBlock.containsKey(memoryBlock)) {
                // create tab folder if a tab folder does not already exist
                // for the memory block
                CTabFolder folder = createTabFolder(fViewPaneCanvas);

                fTabFolderForMemoryBlock.put(memoryBlock, folder);
                fMemoryBlockFromTabFolder.put(folder, memoryBlock);
                setTabFolder((CTabFolder) fTabFolderForMemoryBlock.get(memoryBlock));
                IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(memoryBlock);
                if (retrieval != null)
                    fTabFolderForDebugView.put(MemoryViewUtil.getHashCode(retrieval),
                            fTabFolderForMemoryBlock.get(memoryBlock));
                else
                    DebugUIPlugin.logErrorMessage("Memory block retrieval for memory block is null."); //$NON-NLS-1$

                fViewPaneCanvas.layout();
                fAddedMemoryBlocks.add(memoryBlock);

                // every time we create a folder, we have to create a CreateRendering
                newCreateRenderingForFolder(memoryBlock, folder);
            }

            if (fTabFolderForMemoryBlock.containsKey(memoryBlock)) {
                CTabFolder toDisplay = (CTabFolder) fTabFolderForMemoryBlock.get(memoryBlock);

                if (toDisplay != null) {
                    setTabFolder(toDisplay);
                    IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(memoryBlock);

                    if (retrieval != null)
                        fTabFolderForDebugView.put(MemoryViewUtil.getHashCode(retrieval), toDisplay);
                    else
                        DebugUIPlugin.logErrorMessage("Memory block retrieval is null for memory block."); //$NON-NLS-1$

                    fViewPaneCanvas.layout();

                    // restore view tabs
                    IMemoryRendering[] renderings = fRenderingMgr.getRenderingsFromMemoryBlock(memoryBlock);

                    // if only CreateRendering is present, restore renderings
                    if (isRestoreViewTabs(toDisplay)) {
                        restoreViewTabs(renderings);
                    }
                }
            }

            // disable current storag block

            IMemoryViewTab top = getTopMemoryTab();

            if (top != null)
                top.setEnabled(fVisible);
        }
    }

    public void dispose() {
        super.dispose();

        fTabFolderForMemoryBlock.clear();
        fTabFolderForMemoryBlock = null;

        fMemoryBlockFromTabFolder.clear();
        fMemoryBlockFromTabFolder = null;

        fRenderingMgr.dispose();
        fRenderingMgr = null;

        fAddedMemoryBlocks.clear();
        fAddedRenderings.clear();
    }

    public Control createViewPane(Composite parent, String paneId, String label, boolean canAddRendering,
            boolean canRemoveRendering) {
        return doCreateViewPane(parent, paneId, label, canAddRendering, canRemoveRendering);
    }

    public Control createViewPane(Composite parent, String paneId, String label) {
        return doCreateViewPane(parent, paneId, label, true, true);
    }

    /**
     * @param parent
     * @param paneId
     * @param label
     * @param canAddRendering
     * @param canRemoveRendering
     * @return
     */
    private Control doCreateViewPane(Composite parent, String paneId, String label, boolean canAddRendering,
            boolean canRemoveRendering) {
        Control control = super.createViewPane(parent, paneId, label);
        fCanAddRendering = canAddRendering;
        fCanRemoveRendering = canRemoveRendering;
        fRenderingMgr = new ViewPaneRenderingMgr(this);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
                IDebugUIConstants.PLUGIN_ID + ".MemoryRenderingView_context"); //$NON-NLS-1$
        return control;
    }

    public IAction[] getActions() {
        return new IAction[0];
    }

    // enable/disable toolbar action 
    protected void updateToolBarActionsEnablement() {
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.ui.views.memory.AbstractMemoryViewPane#emptyFolder()
     */
    protected void emptyFolder() {
        super.emptyFolder();
        updateToolBarActionsEnablement();
        fSelectionProvider.setSelection(AbstractMemoryViewPane.EMPTY);
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.ui.views.memory.IRenderingViewPane#addMemoryRendering(org.eclipse.debug.internal.ui.views.memory.IMemoryRendering)
     */
    public void addMemoryRendering(IMemoryRendering rendering) {

        if (rendering == null)
            return;

        memoryBlockRenderingAdded(rendering);
        fRenderingMgr.addMemoryBlockRendering(rendering);

    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.ui.views.memory.IRenderingViewPane#removeMemoryRendering(org.eclipse.debug.internal.ui.views.memory.IMemoryRendering)
     */
    public void removeMemoryRendering(IMemoryRendering rendering) {

        if (rendering == null)
            return;

        memoryBlockRenderingRemoved(rendering);

        if (fRenderingMgr != null)
            fRenderingMgr.removeMemoryBlockRendering(rendering);

    }

    private RenderingViewPane getInstance() {
        return this;
    }

    private IMemoryBlock getMemoryBlock(ISelection selection) {
        if (!(selection instanceof IStructuredSelection))
            return null;

        //only single selection of PICLDebugElements is allowed for this action
        if (selection.isEmpty() || ((IStructuredSelection) selection).size() > 1) {
            return null;
        }

        Object elem = ((IStructuredSelection) selection).getFirstElement();

        if (elem instanceof IMemoryBlock)
            return (IMemoryBlock) elem;
        else if (elem instanceof IMemoryRendering)
            return ((IMemoryRendering) elem).getMemoryBlock();
        else
            return null;
    }

    private void deactivateRendering(IMemoryViewTab viewTab) {
        if (viewTab == null)
            return;

        if (!viewTab.isDisposed()) {
            viewTab.getRendering().deactivated();
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.ui.views.memory.IRenderingViewPane#getMemoryRenderingSite()
     */
    public IMemoryRenderingSite getMemoryRenderingSite() {
        return fRenderingSite;
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getId()
     */
    public String getId() {
        return getPaneId();
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getRenderings()
     */
    public IMemoryRendering[] getRenderings() {
        return fRenderingMgr.getRenderings();
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getActiveRendering()
     */
    public IMemoryRendering getActiveRendering() {
        if (getTopMemoryTab() == null)
            return null;
        return getTopMemoryTab().getRendering();
    }

    /**
     * Reset the memory renderings within this view pane.
     * @param memoryBlock - reset renderings associated with the given memory block
     * @param resetVisible - reset what's currently visible if the parameter is true.
     * Otherwise, the view pane will reset all renderings associated with the given 
     * memory block.
     */
    public void resetRenderings(IMemoryBlock memoryBlock, boolean resetVisible) {
        // if we only reset what's visible and the view pane is not visible
        // do nothing.
        if (resetVisible && !isVisible())
            return;

        if (resetVisible) {
            IMemoryRendering rendering = getActiveRendering();
            if (rendering != null) {
                if (rendering.getMemoryBlock() == memoryBlock) {
                    if (rendering instanceof IResettableMemoryRendering) {
                        IResettableMemoryRendering resettableRendering = (IResettableMemoryRendering) rendering;
                        try {
                            resettableRendering.resetRendering();
                        } catch (DebugException e) {
                            // do not pop up error message
                            // error message is annoying where there are multiple rendering
                            // panes and renderings to reset
                        }
                    }
                }
            }
        } else {
            // get all renderings associated with the given memory block
            IMemoryRendering[] renderings = fRenderingMgr.getRenderingsFromMemoryBlock(memoryBlock);

            // back up current synchronization provider
            IMemoryRendering originalProvider = null;
            IMemoryRenderingSynchronizationService service = getMemoryRenderingSite().getSynchronizationService();
            if (service != null)
                originalProvider = service.getSynchronizationProvider();

            for (int i = 0; i < renderings.length; i++) {
                if (renderings[i] instanceof IResettableMemoryRendering) {
                    try {

                        // This is done to allow user to select multiple memory monitors and 
                        // reset their renderings.
                        // In this case, a hidden rendering will not be the sync provider to the sync
                        // service.  When the reset happens, the top visible address and selected
                        // address is not updated in the sync service.  When the rendering later
                        // becomes visible, the rendering gets the sync info from the sync service
                        // and will try to sync up with old information, giving user the impression
                        // that the rendering was never reset.  By forcing the rendering that we
                        // are trying to reset as the synchronization provider, we ensure that
                        // the rendering is able to update its sync info even though the rendering
                        // is currently hidden.
                        if (service != null)
                            service.setSynchronizationProvider(renderings[i]);
                        ((IResettableMemoryRendering) renderings[i]).resetRendering();
                    } catch (DebugException e) {
                        // do not pop up error message
                        // error message is annoying where there are multiple rendering
                        // panes and renderings to reset
                    }
                }
            }

            // restore synchronization provider
            if (service != null)
                service.setSynchronizationProvider(originalProvider);
        }
    }

    public void showCreateRenderingTab() {
        IMemoryRendering activeRendering = RenderingViewPane.this.getActiveRendering();
        if (activeRendering == null)
            return;

        IMemoryBlock memoryblk = activeRendering.getMemoryBlock();

        final CTabFolder tabFolder = (CTabFolder) fTabFolderForMemoryBlock.get(memoryblk);
        if (tabFolder != null) {
            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    int index = getIndexOfCreateRenderingTab(tabFolder);
                    if (index >= 0)
                        tabFolder.setSelection(index);
                }
            });
        }
    }

    public void contextActivated(final ISelection selection) {

        UIJob job = new UIJob("contextActivated") { //$NON-NLS-1$
            public IStatus runInUIThread(IProgressMonitor monitor) {
                if (isDisposed())
                    return Status.OK_STATUS;

                IMemoryViewTab lastViewTab = getTopMemoryTab();

                if (MemoryViewUtil.isValidSelection(selection)) {
                    if (!(selection instanceof IStructuredSelection))
                        return Status.OK_STATUS;

                    Object elem = ((IStructuredSelection) selection).getFirstElement();

                    if (elem instanceof IAdaptable) {
                        handleDebugElementSelection(lastViewTab, (IAdaptable) elem);
                    }
                } else {
                    if (lastViewTab != null)
                        lastViewTab.setEnabled(false);

                    if (fStackLayout.topControl != fEmptyTabFolder)
                        emptyFolder();

                }
                return Status.OK_STATUS;
            }
        };
        job.setSystem(true);
        job.schedule();
    }

    /**
     * @param memory
     */
    private CTabFolder createFolderForMemoryBlock(IMemoryBlock memory) {
        CTabFolder folder = createTabFolder(fViewPaneCanvas);

        fTabFolderForMemoryBlock.put(memory, folder);
        fMemoryBlockFromTabFolder.put(folder, memory);

        IMemoryBlockRetrieval retrieval = MemoryViewUtil.getMemoryBlockRetrieval(memory);
        if (retrieval != null) {
            fTabFolderForDebugView.put(MemoryViewUtil.getHashCode(retrieval), folder);
        } else {
            DebugUIPlugin.logErrorMessage("Memory block retrieval for memory block is null"); //$NON-NLS-1$
        }

        newCreateRenderingForFolder(memory, folder);

        return folder;
    }

    private void newCreateRenderingForFolder(IMemoryBlock memory, CTabFolder folder) {

        if (!canAddRendering())
            return;

        CTabItem newItem = new CTabItem(folder, SWT.NONE);
        CreateRendering rendering = new CreateRendering(getInstance());
        rendering.init(getInstance(), memory);
        new MemoryViewTab(newItem, rendering, getInstance());
        folder.setSelection(0);
    }

    /* (non-Javadoc)
     * @see org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextListener#contextEvent(org.eclipse.debug.internal.ui.contexts.provisional.DebugContextEvent)
     */
    public void debugContextChanged(DebugContextEvent event) {
        if ((event.getFlags() & DebugContextEvent.ACTIVATED) > 0) {
            contextActivated(event.getContext());
        }
    }

    /**
     * @return whether this container allows user to add rendering manually
     * @since 3.4
     */
    public boolean canAddRendering() {
        return fCanAddRendering;
    }

    /**
     * @return whether this container allows user to remove rendering manually
     * @since 3.4
     */
    public boolean canRemoveRendering() {
        return fCanRemoveRendering;
    }

    /**
     * @param tabFolder
     * @param index
     * @return
     */
    private CTabItem createTab(CTabFolder tabFolder, int index) {
        int swtStyle = SWT.CLOSE;
        if (!canRemoveRendering())
            swtStyle = SWT.NONE;
        CTabItem tab = new CTabItem(tabFolder, swtStyle, index);
        return tab;
    }
}