/*******************************************************************************
* Copyright (c) 2012 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.internal.debug.ui.commands;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.IDebugView;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.tcf.internal.debug.ui.model.TCFChildren;
import org.eclipse.tcf.internal.debug.ui.model.TCFModelProxy;
import org.eclipse.tcf.internal.debug.ui.model.TCFNode;
import org.eclipse.tcf.internal.debug.ui.model.TCFNodeExecContext;
import org.eclipse.tcf.internal.debug.ui.model.TCFNodeRegister;
import org.eclipse.tcf.internal.debug.ui.model.TCFNodeStackFrame;
import org.eclipse.tcf.services.IRegisters;
import org.eclipse.tcf.util.TCFTask;
import org.eclipse.ui.IPartService;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.menus.IWorkbenchContribution;
import org.eclipse.ui.services.IServiceLocator;
public class RegisterVectorDisplayMenu extends CompoundContributionItem implements IWorkbenchContribution {
private static final int MAX_REG_REPRESENTATIONS = 100;
private IServiceLocator service_locator;
private ArrayList<String> elements;
private Map<String,Map<String,String>> modes;
@Override
public void initialize(IServiceLocator service_locator) {
this.service_locator = service_locator;
}
private Object[] getSelectedRegisters() {
ISelectionService service = (ISelectionService) service_locator.getService(ISelectionService.class);
if (service != null) {
ISelection selection = service.getSelection();
if (selection instanceof IStructuredSelection) {
return ((IStructuredSelection)selection).toArray();
}
}
return new Object[0];
}
@Override
protected IContributionItem[] getContributionItems() {
final IWorkbenchPart part = getPart();
if (part == null) return null;
final Object[] selection = getSelectedRegisters();
final TCFNode node = getRootNode(part);
if (node == null) return null;
if (!(node instanceof TCFNodeExecContext) && !(node instanceof TCFNodeStackFrame)) return null;
IContributionItem[] items = new TCFTask<IContributionItem[]>(node.getChannel()) {
public void run() {
modes = new LinkedHashMap<String,Map<String,String>>();
for (Object obj : selection) {
if (obj instanceof TCFNodeRegister) {
TCFNodeRegister reg = (TCFNodeRegister)obj;
AtomicBoolean grp = new AtomicBoolean();
if (!reg.isRepresentationGroup(grp, this)) return;
if (!grp.get()) continue;
TCFChildren children = reg.getChildren();
if (!children.validate(this)) return;
for (TCFNode child_node : children.toArray()) {
TCFNodeRegister child_reg = (TCFNodeRegister)child_node;
if (!child_reg.getContext().validate(this)) return;
IRegisters.RegistersContext child_ctx = child_reg.getContext().getData();
String reg_name = child_ctx.getName();
if (reg_name.matches("w[0-9]+")) {
String mode = reg_name.substring(1, reg_name.length()) + "bits";
Map<String,String> map = modes.get(mode);
if (map == null) modes.put(mode, map = new HashMap<String,String>());
map.put(reg.getID(), child_ctx.getID());
}
}
}
}
// if several registers are selected in the register view, we need to show only the common possibilities
for (Iterator<Map<String,String>> i = modes.values().iterator(); i.hasNext();) {
Map<String,String> map = i.next();
for (Object obj : selection) {
if (!(obj instanceof TCFNodeRegister)) continue;
if (map.containsKey(((TCFNodeRegister)obj).getID())) continue;
i.remove();
break;
}
}
elements = new ArrayList<String>(modes.keySet());
elements.add(0, elements.size() == 0 ? "No vector display options available" : "none");
IContributionItem[] items = new IContributionItem[elements.size()];
for (int i = 0; i < items.length; i++) {
final int n = i;
items[i] = new ContributionItem() {
@Override
public void fill(final Menu menu, int index) {
final MenuItem item = new MenuItem(menu, elements.size() <= 1 ? SWT.NULL : SWT.RADIO);
item.setText(elements.get(n));
item.setSelection(getRepresentation() == n);
item.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
if (item.getSelection()) setRepresentation(n);
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
};
}
done(items);
}
}.getE();
return (items);
}
private IWorkbenchPart getPart() {
IPartService partService = (IPartService)service_locator.getService(IPartService.class);
if (partService != null) return partService.getActivePart();
return null;
}
private TCFNode getRootNode(IWorkbenchPart part) {
IWorkbenchPartSite site = part.getSite();
if (site == null || IDebugUIConstants.ID_DEBUG_VIEW.equals(site.getId())) {
return null;
}
if (part instanceof IDebugView) {
Object input = ((IDebugView)part).getViewer().getInput();
if (input instanceof TCFNode) return (TCFNode)input;
}
return null;
}
private ITreeModelViewer getViewer() {
IWorkbenchPart part = getPart();
if (part instanceof IDebugView) {
return (ITreeModelViewer)((IDebugView)part).getViewer();
}
return null;
}
private int getRepresentation() {
IWorkbenchPart part = getPart();
if (part == null) return 0;
TCFNodeRegister node = null;
for (Object obj : getSelectedRegisters()) {
if (obj instanceof TCFNodeRegister) {
node = (TCFNodeRegister)obj;
break;
}
}
if (node == null) return 0;
final String id = node.getID();
final IPresentationContext ctx = getViewer().getPresentationContext();
return new TCFTask<Integer>(node.getChannel()) {
@SuppressWarnings("unchecked")
public void run() {
Map<String,String> representation = (Map<String,String>)ctx.getProperty(
TCFNodeRegister.PROPERTY_REG_REPRESENTATION);
if (representation != null) {
String rep_id = representation.get(id);
if (rep_id != null) {
for (Map.Entry<String,Map<String,String>> e : modes.entrySet()) {
if (rep_id.equals(e.getValue().get(id))) {
done(elements.indexOf(e.getKey()));
return;
}
}
}
}
done(0);
}
}.getE();
}
private void setRepresentation(final int n) {
final IWorkbenchPart part = getPart();
if (part == null) return;
final TCFNode node = getRootNode(part);
if (node == null) return;
final Object[] selection = getSelectedRegisters();
ITreeModelViewer viewer = getViewer();
final IPresentationContext ctx = viewer.getPresentationContext();
new TCFTask<Object>(node.getChannel()) {
@SuppressWarnings({ "unchecked", "serial" })
public void run() {
Map<String,String> representation = (Map<String,String>)ctx.getProperty(
TCFNodeRegister.PROPERTY_REG_REPRESENTATION);
if (representation == null) {
representation = new LinkedHashMap<String,String>() {
@Override
protected boolean removeEldestEntry(Map.Entry<String,String> eldest) {
return size() > MAX_REG_REPRESENTATIONS;
}
};
ctx.setProperty(TCFNodeRegister.PROPERTY_REG_REPRESENTATION, representation);
}
Map<String,String> map = modes.get(elements.get(n));
TCFModelProxy[] proxies = node.getModel().getModelProxies(ctx);
for (Object obj : selection) {
if (obj instanceof TCFNodeRegister) {
TCFNodeRegister reg = (TCFNodeRegister)obj;
String id = reg.getID();
String rep_id = map != null ? map.get(id) : null;
if (rep_id == null) representation.remove(id);
else representation.put(id, rep_id);
for (int i = 0; i < proxies.length; i++) {
proxies[i].addDelta(reg, IModelDelta.CONTENT);
TCFNode n = node.getModel().getNode(rep_id);
if (n != null) proxies[i].expand(n);
}
}
}
done(null);
}
};
}
}