| /******************************************************************************* |
| * Copyright (c) 2004, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * 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<IMemoryBlock, CTabFolder> fTabFolderForMemoryBlock = new Hashtable<>(); |
| private Hashtable<CTabFolder, IMemoryBlock> fMemoryBlockFromTabFolder = new Hashtable<>(); |
| |
| private ViewPaneRenderingMgr fRenderingMgr; |
| |
| private IMemoryRenderingSite fRenderingSite; |
| private Set<IMemoryRendering> fAddedRenderings = new HashSet<>(); |
| private Set<IMemoryBlock> 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) |
| */ |
| @Override |
| public void memoryBlocksAdded(final IMemoryBlock[] memoryBlocks) { |
| Display.getDefault().asyncExec(() -> { |
| |
| 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) |
| */ |
| @Override |
| public void memoryBlocksRemoved(final IMemoryBlock[] memoryBlocks) { |
| Display.getDefault().asyncExec(() -> { |
| 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 = 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) |
| */ |
| @Override |
| 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$ |
| |
| @Override |
| 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 = 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 != fTabFolderForMemoryBlock.get(memBlock)) { |
| setTabFolder(fTabFolderForMemoryBlock.get(memBlock)); |
| fViewPaneCanvas.layout(); |
| } |
| } else { // otherwise, add a new one |
| CTabFolder folder = createTabFolder(fViewPaneCanvas); |
| |
| fTabFolderForMemoryBlock.put(memBlock, folder); |
| fMemoryBlockFromTabFolder.put(folder, memBlock); |
| setTabFolder(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(() -> { |
| |
| if (isDisposed()) { |
| return; |
| } |
| |
| if (fAddedRenderings.contains(rendering)) { |
| return; |
| } |
| |
| IMemoryBlock memoryblk = rendering.getMemoryBlock(); |
| |
| CTabFolder tabFolder = 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(() -> { |
| 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 i1 = 0; i1 < tabs.length; i1++) { |
| IMemoryViewTab viewTab1 = (IMemoryViewTab) tabs[i1].getData(); |
| |
| if (tabs[i1].isDisposed()) { |
| continue; |
| } |
| |
| if (viewTab1.getRendering().getMemoryBlock() == memory) { |
| if (viewTab1.getRendering() == rendering) { |
| foundTab = true; |
| disposeTab(tabs[i1]); |
| 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<CTabFolder> enumeration = fTabFolderForMemoryBlock.elements(); |
| while (enumeration.hasMoreElements()) { |
| CTabFolder otherTabFolder = enumeration.nextElement(); |
| tabs = otherTabFolder.getItems(); |
| IMemoryViewTab viewTab2 = null; |
| for (int i2 = 0; i2 < tabs.length; i2++) { |
| viewTab2 = (IMemoryViewTab) tabs[i2].getData(); |
| if (viewTab2.getRendering().getMemoryBlock() == memory) { |
| if (viewTab2.getRendering() == rendering) { |
| foundTab = true; |
| disposeTab(tabs[i2]); |
| 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 = 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 = 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(); |
| } |
| |
| @Override |
| 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); |
| } |
| |
| @Override |
| protected void removeListeners() { |
| super.removeListeners(); |
| fParent.getSite().getSelectionProvider().removeSelectionChangedListener(this); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt |
| * .events.SelectionEvent) |
| */ |
| @Override |
| 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) |
| */ |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| |
| @Override |
| 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() |
| */ |
| @Override |
| 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) |
| */ |
| @Override |
| 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() { |
| @Override |
| public void close(CTabFolderEvent event) { |
| if (event.item.getData() instanceof MemoryViewTab) { |
| RenderingViewPane.this.removeMemoryRendering(((MemoryViewTab) event.item.getData()).getRendering()); |
| } |
| event.doit = false; |
| } |
| }); |
| return folder; |
| } |
| |
| @Override |
| 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(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 = 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); |
| } |
| } |
| } |
| |
| @Override |
| 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); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| 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 |
| * () |
| */ |
| @Override |
| 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) |
| */ |
| @Override |
| 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) |
| */ |
| @Override |
| 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() |
| */ |
| @Override |
| public IMemoryRenderingSite getMemoryRenderingSite() { |
| return fRenderingSite; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getId() |
| */ |
| @Override |
| public String getId() { |
| return getPaneId(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getRenderings() |
| */ |
| @Override |
| public IMemoryRendering[] getRenderings() { |
| return fRenderingMgr.getRenderings(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * org.eclipse.debug.ui.memory.IMemoryRenderingContainer#getActiveRendering |
| * () |
| */ |
| @Override |
| 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 = fTabFolderForMemoryBlock.get(memoryblk); |
| if (tabFolder != null) { |
| Display.getDefault().asyncExec(() -> { |
| int index = getIndexOfCreateRenderingTab(tabFolder); |
| if (index >= 0) { |
| tabFolder.setSelection(index); |
| } |
| }); |
| } |
| } |
| |
| public void contextActivated(final ISelection selection) { |
| |
| UIJob job = new UIJob("contextActivated") { //$NON-NLS-1$ |
| @Override |
| 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) |
| */ |
| @Override |
| 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; |
| } |
| } |