/***************************************************************** * Copyright (c) 2011, 2014 Texas Instruments 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: * Winnie Lai (Texas Instruments) - Individual Element Number Format (Bug 202556) * Marc Khouzam (Ericsson) - Base available formats on each element (Bug 439624) *****************************************************************/ package org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants; import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils; import org.eclipse.cdt.dsf.ui.concurrent.SimpleDisplayExecutor; import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext; import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider; import org.eclipse.cdt.dsf.ui.viewmodel.update.ICacheEntry; import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProviderExtension2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; /** * Dynamic menu contribution that shows available number formats in the current * selection of the view. * * @since 2.2 */ public class ElementNumberFormatsContribution extends NumberFormatsContribution { static class SelectFormatAction extends Action { private final IElementFormatProvider fProvider; private final IPresentationContext fContext; private final IVMNode[] fNodes; private final Object fViewerInput; private final TreePath[] fElementPaths; private final String fFormatId; SelectFormatAction(IElementFormatProvider provider, IPresentationContext context, IVMNode[] nodes, Object viewerInput, TreePath[] elementPaths, String formatId) { super(formatId == null ? MessagesForNumberFormat.ElementNumberFormatContribution_RestoreToPreference_label : FormattedValueVMUtil.getFormatLabel(formatId), formatId == null ? AS_PUSH_BUTTON : AS_RADIO_BUTTON); fProvider = provider; fContext = context; fNodes = nodes; fViewerInput = viewerInput; fElementPaths = elementPaths; fFormatId = formatId; } @Override public void run() { if (fFormatId == null) { fProvider.setActiveFormat(fContext, fNodes, fViewerInput, fElementPaths, fFormatId); return; } if (isChecked()) { fProvider.setActiveFormat(fContext, fNodes, fViewerInput, fElementPaths, fFormatId); } } } protected static IContributionItem[] NO_ITEMS = new IContributionItem[] { new ContributionItem() { @Override public void fill(Menu menu, int index) { MenuItem item = new MenuItem(menu, SWT.NONE); item.setEnabled(false); item.setText(MessagesForNumberFormat.NumberFormatContribution_EmptyFormatsList_label); } @Override public boolean isEnabled() { return false; } } }; @Override protected IContributionItem[] getContributionItems() { ISelection selection = VMHandlerUtils.getSelection(fServiceLocator); if (selection == null || selection.isEmpty() || selection instanceof ITreeSelection == false) { return NO_ITEMS; } IVMProvider provider = VMHandlerUtils.getVMProviderForSelection(selection); if (provider instanceof IElementFormatProvider == false) { return NO_ITEMS; } IPresentationContext context = provider.getPresentationContext(); Object viewerInput = VMHandlerUtils.getViewerInput(context); TreePath[] elementPaths = ((ITreeSelection) selection).getPaths(); List<String> availableFormats = getAvailableFormats(provider, viewerInput, elementPaths); if (availableFormats.size() == 0) { return NO_ITEMS; } IVMNode[] nodes = new IVMNode[elementPaths.length]; final List<SelectFormatAction> actions = new ArrayList<SelectFormatAction>(availableFormats.size()); for (String formatId : availableFormats) { actions.add(new SelectFormatAction((IElementFormatProvider) provider, context, nodes, viewerInput, elementPaths, formatId)); } final String[] elementActiveFormats = new String[elementPaths.length]; CountingRequestMonitor crm = new CountingRequestMonitor(SimpleDisplayExecutor.getSimpleDisplayExecutor(Display.getDefault()), null) { @Override protected void handleCompleted() { String activeFormat = null; for (int i = 0; i < elementActiveFormats.length; i++) { if (i == 0) { activeFormat = elementActiveFormats[i]; } else if (activeFormat != null && activeFormat.equals(elementActiveFormats[i]) == false) { activeFormat = null; break; } } if (activeFormat != null) { for (int i = 0; i < actions.size(); i++) { if (activeFormat.equals(actions.get(i).fFormatId)) { actions.get(i).setChecked(true); break; } } } } }; for (int i = 0; i < elementPaths.length; i++) { Object segment = elementPaths[i].getLastSegment(); if (segment instanceof IVMContext) { nodes[i] = ((IVMContext) segment).getVMNode(); } else { nodes[i] = null; } final int index = i; ((IElementFormatProvider) provider).getActiveFormat(context, nodes[i], viewerInput, elementPaths[i], new DataRequestMonitor<String>(ImmediateExecutor.getInstance(), crm) { @Override protected void handleSuccess() { elementActiveFormats[index] = this.getData(); super.handleSuccess(); } }); } crm.setDoneCount(elementPaths.length); int count = actions.size(); IContributionItem[] items = new IContributionItem[count]; for (int i = 0; i < items.length; i++) { items[i] = new ActionContributionItem(actions.get(i)); } return items; } /** * Get the available formats for all elements in the selection. If all elements have the same * available formats, return that list; if not, return the default list. */ private List<String> getAvailableFormats(IVMProvider provider, Object viewerInput, TreePath[] paths) { if (provider instanceof ICachingVMProviderExtension2) { ICachingVMProviderExtension2 cachingProvider = (ICachingVMProviderExtension2)provider; String[] formats = null; for (TreePath path : paths) { IVMNode node = VMHandlerUtils.getVMNode(viewerInput, path); if (node != null) { ICacheEntry cacheEntry = cachingProvider.getCacheEntry(node, viewerInput, path); if (cacheEntry != null && cacheEntry.getProperties() != null) { String[] entryFormats = (String[]) cacheEntry.getProperties().get(IDebugVMConstants.PROP_FORMATTED_VALUE_AVAILABLE_FORMATS); if (entryFormats == null) { // At least one element has no formats. Use the default ones. return FORMATS; } if (formats == null) { // First set of formats formats = entryFormats; } else { // Found another set of formats. Make sure it is the same as the set we already have. // If not, return the default set of formats. if (!Arrays.equals(formats, entryFormats)) { return FORMATS; } } } } } if (formats != null) { return Arrays.asList(formats); } } return FORMATS; } }