blob: 28a2f9e07bbae5066c3aa9ce34c493d57292c5df [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2007 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
*******************************************************************************/
package org.eclipse.debug.internal.ui.views.memory.renderings;
import java.math.BigInteger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IMemoryBlockExtension;
import org.eclipse.debug.core.model.MemoryByte;
import org.eclipse.debug.internal.ui.DebugUIMessages;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.memory.provisional.AbstractAsyncTableRendering;
import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil;
import org.eclipse.debug.ui.memory.MemoryRenderingElement;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.swt.widgets.TableItem;
/**
* @since 3.1
*
*/
// TODO: if we want "true" flexible hierarchy, also need to allow clients
// to plug cell modifier in case the element is not MemorySegment
public class AsyncTableRenderingCellModifier implements ICellModifier {
private AbstractAsyncTableRendering fRendering;
private boolean fMBSupportsValueModification = false;
private ICellModifier fCustomModifier;
public AsyncTableRenderingCellModifier(AbstractAsyncTableRendering rendering, ICellModifier customModifier) {
fRendering = rendering;
fCustomModifier = customModifier;
Job job = new Job("AsyncTableRenderingCellModifier"){ //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
fMBSupportsValueModification = fRendering.getMemoryBlock().supportsValueModification();
return Status.OK_STATUS;
}};
job.setSystem(true);
job.schedule();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object,
* java.lang.String)
*/
public boolean canModify(Object element, String property) {
boolean canModify = true;
try {
if (!(element instanceof MemorySegment))
return false;
if (!isValueModificationSupported()) {
return false;
}
MemorySegment line = (MemorySegment) element;
if (TableRenderingLine.P_ADDRESS.equals(property)) {
return false;
}
// property is stored as number of addressable unit away from the
// line address
// to calculate offset to the memory line array, offset =
// numberofAddressableUnit * addressableSize
int addressableSize = getAddressableSize();
int offset = Integer.valueOf(property, 16).intValue() * addressableSize;
MemoryByte[] bytes = line.getBytes(offset, fRendering.getBytesPerColumn());
if (fCustomModifier != null)
{
BigInteger address = line.getAddress().add(BigInteger.valueOf(offset));
MemoryRenderingElement mElement = new MemoryRenderingElement(fRendering, address, bytes);
return fCustomModifier.canModify(mElement, null);
}
for (int i = 0; i < bytes.length; i++) {
if (!bytes[i].isWritable()) {
canModify = false;
}
}
return canModify;
} catch (NumberFormatException e) {
canModify = false;
return canModify;
}
}
/**
* @return
*/
private int getAddressableSize() {
int addressableSize = fRendering.getAddressableSize();
if (addressableSize < 1)
addressableSize = 1;
return addressableSize;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object,
* java.lang.String)
*/
public Object getValue(Object element, String property) {
// give back the value of the column
if (!(element instanceof MemorySegment))
return null;
MemorySegment line = (MemorySegment) element;
try {
if (TableRenderingLine.P_ADDRESS.equals(property))
return line.getAddress();
int offsetToLineBuffer = Integer.valueOf(property, 16).intValue() * getAddressableSize();
MemoryByte[] memory = line.getBytes(offsetToLineBuffer, fRendering.getBytesPerColumn());
int offsetFromLineAddress = Integer.valueOf(property, 16).intValue();
BigInteger address = line.getAddress().add(BigInteger.valueOf(offsetFromLineAddress));
if (fCustomModifier != null)
{
MemoryRenderingElement mElement = new MemoryRenderingElement(fRendering, address, memory);
return fCustomModifier.getValue(mElement, null);
}
// ask the rendering for a string representation of the bytes
return fRendering.getString(fRendering.getRenderingId(), address, memory);
} catch (NumberFormatException e) {
return "00"; //$NON-NLS-1$
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object,
* java.lang.String, java.lang.Object)
*/
public void modify(Object element, final String property, final Object value) {
MemorySegment segment = null;
if (element instanceof TableItem) {
Object data = ((TableItem)element).getData();
if (data != null && data instanceof MemorySegment)
segment = (MemorySegment)data;
} else if (element instanceof MemorySegment){
segment = (MemorySegment) element;
}
if (segment == null)
return;
final MemorySegment line = segment;
Job job = new Job("Set Values"){ //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
try {
// calculate offset to update
final IMemoryBlock memoryBlk = fRendering.getMemoryBlock();
// number of addressable units from the line's start address
int offsetFromLineAddress = Integer.valueOf(property, 16).intValue();
// this offset is number of addressable unit from memory block's base address
final BigInteger offsetFromMBBase = getOffset(memoryBlk, line.getAddress(), offsetFromLineAddress);
// property is number of addressable unit from line address
// to calculate proper offset in the memoryViewLine's array
// offset = numberOfAddressableUnit * addressableSize
int offsetToLineBuffer = Integer.valueOf(property, 16).intValue() * getAddressableSize();
MemoryByte[] oldArray = line.getBytes(offsetToLineBuffer, fRendering.getBytesPerColumn());
// address is line address + addressable unit into the line
BigInteger address = line.getAddress();
address = address.add(BigInteger.valueOf(offsetFromLineAddress));
if (fCustomModifier != null) {
MemoryRenderingElement mElement = new MemoryRenderingElement(fRendering, address, oldArray);
fCustomModifier.modify(mElement, null, value);
return Status.OK_STATUS;
}
if (!(value instanceof String))
{
DebugUIPlugin.logErrorMessage("Cell modifier cannot handle non-string values."); //$NON-NLS-1$
return Status.OK_STATUS;
}
byte[] bytes = null;
String oldValue = (String) getValue(line, property);
if (!oldValue.equals(value)) {
bytes = fRendering.getBytes(fRendering.getRenderingId(), address, oldArray, (String) value);
if (bytes == null)
return Status.OK_STATUS;
if (bytes.length == 0)
return Status.OK_STATUS;
if (bytes.length <= oldArray.length) {
boolean changed = false;
// check that the bytes returned has actually changed
for (int i = 0; i < bytes.length; i++) {
if (bytes[i] != oldArray[i].getValue()) {
changed = true;
break;
}
}
if (!changed)
return Status.OK_STATUS;
}
} else {
// return if value has not changed
return Status.OK_STATUS;
}
final byte[] newByteValues = bytes;
if (memoryBlk instanceof IMemoryBlockExtension)
((IMemoryBlockExtension) memoryBlk).setValue(offsetFromMBBase, newByteValues);
else
memoryBlk.setValue(offsetFromMBBase.longValue(), newByteValues);
} catch (DebugException e) {
MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title, DebugUIMessages.MemoryViewCellModifier_failed, e);
} catch (NumberFormatException e) {
MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title, DebugUIMessages.MemoryViewCellModifier_failed + "\n" + DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null); //$NON-NLS-1$
}
return Status.OK_STATUS;
}};
job.setSystem(true);
job.schedule();
}
private BigInteger getOffset(IMemoryBlock memory, BigInteger lineAddress, int lineOffset) throws DebugException {
BigInteger memoryAddr;
if (memory instanceof IMemoryBlockExtension) {
memoryAddr = ((IMemoryBlockExtension) memory).getBigBaseAddress();
} else {
memoryAddr = BigInteger.valueOf(memory.getStartAddress());
}
if (memoryAddr == null)
memoryAddr = new BigInteger("0"); //$NON-NLS-1$
return lineAddress.subtract(memoryAddr).add(BigInteger.valueOf(lineOffset));
}
private boolean isValueModificationSupported()
{
return fMBSupportsValueModification;
}
}