/** * */ package org.csstudio.sds.ui.internal.viewer; import org.eclipse.gef.ui.parts.GraphicalViewerImpl; import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.internal.ObjectPluginAction; /** * Patched graphical viewer implementation. * * @author swende * */ public class PatchedGraphicalViewer extends ScrollingGraphicalViewer { private MenuManager contextMenu; /** * The original implementation in * {@link GraphicalViewerImpl#setContextMenu(MenuManager)} registers a menu * listener on the context menu. This causes a memory leak, because that * listener is never removed. */ @Override public void setContextMenu(MenuManager manager) { // code from AbstractEditPartViewer base class (=super.super) if (contextMenu != null) { contextMenu.dispose(); } contextMenu = manager; if (getControl() != null && !getControl().isDisposed()) { getControl().setMenu(contextMenu.createContextMenu(getControl())); } // code from GraphicalViewerImpl (=super) // ... is left out // ... and rewritten here if (contextMenu != null) { final IMenuListener menuListener = new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { flush(); } }; contextMenu.addMenuListener(menuListener); final Control control = getControl(); if (control != null) { control.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { contextMenu.removeMenuListener(menuListener); control.removeDisposeListener(this); } }); } } } /** * Patch selections. Return amended selections that keep only weak * references to their underlying objects. This is part of a workaround for * a memory leak which is caused by popup menu actions that are contributed * via extension point 'org.eclipse.ui.popupMenus' and as * 'objectContribution'. Those actions will references the latest workbench * selection for as long as a new selection occurs (see * {@link ObjectPluginAction#selectionChanged(ISelection)}. In certain * situations this behaviour prevents garbage collection of SDS displays. */ @Override public ISelection getSelection() { IStructuredSelection selection = (IStructuredSelection) super .getSelection(); if (selection != null) { return new WeakStructuredSelection(selection); } else { return null; } } }