/******************************************************************************* * Copyright (c) 2016 Zend Technologies 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: * Zend Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.debug.core.xdebug.dbgp.model; import static org.eclipse.php.internal.debug.core.model.IVariableFacet.Facet.KIND_ARRAY_MEMBER; import java.util.HashSet; import java.util.Set; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.IVariable; import org.eclipse.php.internal.debug.core.PHPDebugCoreMessages; import org.eclipse.php.internal.debug.core.PHPDebugPlugin; import org.eclipse.php.internal.debug.core.model.IPHPDataType; import org.eclipse.php.internal.debug.core.model.IVariableFacet; import org.eclipse.php.internal.debug.core.model.VariablesUtil; import org.eclipse.php.internal.debug.core.xdebug.dbgp.protocol.DBGpResponse; import org.w3c.dom.Node; /** * Abstract DBGp variable implementation. * * @author Bartlomiej Laczkowski */ public abstract class DBGpVariable extends DBGpElement implements IVariable, IVariableFacet, IPHPDataType { public enum Kind { STACK, EVAL; } protected final int fStackLevel; protected final Set<Facet> fFacets = new HashSet<Facet>(); protected DataType fDataType; protected Node fDescriptor; protected String fName; protected String fFullName; protected String fAddress; protected AbstractDBGpValue fValue; protected boolean fHasValueChanged = false; protected boolean fIsDirty = true; /** * @param target */ public DBGpVariable(IDebugTarget target, Node descriptor, int stackLevel, Facet... facets) { super(target); this.fStackLevel = stackLevel; addFacets(facets); update(descriptor); } public DataType getDataType() { return fDataType; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IValueModification#setValue(java.lang. * String) */ @Override public void setValue(String value) throws DebugException { /* * assume never called unless supportsValueModification is true also * assume that will only be called if been verified BUG in eclipse 3.2: * Cell modification doesn't call verify Value and it should. It does if * you use the editor pane. */ if (!verifyValue(value)) { // setValue called, but verifyValue failed Status stat = new Status(Status.WARNING, PHPDebugPlugin.ID, PHPDebugCoreMessages.XDebug_DBGpVariable_0); throw new DebugException(stat); } else { // attempt to set the property if (((DBGpTarget) getDebugTarget()).setProperty(this, value)) { fValue.setValue(value); fireChangeEvent(DebugEvent.CONTENT); } else { // program under debug rejected value change throw new DebugException(new Status(IStatus.ERROR, PHPDebugPlugin.ID, DebugException.TARGET_REQUEST_FAILED, PHPDebugCoreMessages.XDebug_DBGpVariable_1, null)); } } } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IValueModification#setValue(org.eclipse. * debug.core.model.IValue) */ @Override public void setValue(IValue value) throws DebugException { setValue(value.getValueString()); } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IValueModification#supportsValueModification * () */ @Override public boolean supportsValueModification() { return fValue.supportsValueModification(); } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IValueModification#verifyValue(java.lang. * String) */ @Override public boolean verifyValue(String value) throws DebugException { return fValue.verifyValue(value); } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IValueModification#verifyValue(org.eclipse. * debug.core.model.IValue) */ @Override public boolean verifyValue(IValue value) throws DebugException { return verifyValue(value.getValueString()); } /* * (non-Javadoc) * * @see * org.eclipse.php.internal.debug.core.model.IVariableFacet#hasFacet(org. * eclipse.php.internal.debug.core.model.IVariableFacet.Facet) */ @Override public boolean hasFacet(Facet facet) { return fFacets.contains(facet); } /* * (non-Javadoc) * * @see * org.eclipse.php.internal.debug.core.model.IVariableFacet#addFacets(org. * eclipse.php.internal.debug.core.model.IVariableFacet.Facet[]) */ @Override public void addFacets(Facet... facets) { for (Facet facet : facets) this.fFacets.add(facet); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IVariable#getValue() */ @Override public IValue getValue() throws DebugException { return fValue; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IVariable#getName() */ @Override public String getName() throws DebugException { return fName; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() */ @Override public String getReferenceTypeName() throws DebugException { if (getName().equals(VariablesUtil.CLASS_INDICATOR)) return "class"; //$NON-NLS-1$ return fValue.getDataType().getText(); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IVariable#hasValueChanged() */ @Override public boolean hasValueChanged() throws DebugException { return fHasValueChanged; } protected abstract Kind getKind(); protected abstract Node getNode(int page); protected int getStackLevel() { return fStackLevel; } protected String getFullName() { return fFullName; } protected Node getDescriptor() { return fDescriptor; } protected void update(Node descriptor) { // Set up descriptor fDescriptor = descriptor; // Set name fName = DBGpResponse.getAttribute(fDescriptor, "name"); //$NON-NLS-1$ // Set full name (elements chain) fFullName = DBGpResponse.getAttribute(fDescriptor, "fullname"); //$NON-NLS-1$ // Set address fAddress = DBGpResponse.getAttribute(fDescriptor, "address"); //$NON-NLS-1$ // Set facets String facets = DBGpResponse.getAttribute(fDescriptor, "facet"); //$NON-NLS-1$ if (facets.contains("static")) //$NON-NLS-1$ addFacets(Facet.MOD_STATIC); if (facets.contains("public")) //$NON-NLS-1$ addFacets(Facet.MOD_PUBLIC); else if (facets.contains("protected")) //$NON-NLS-1$ addFacets(Facet.MOD_PROTECTED); else if (facets.contains("private")) //$NON-NLS-1$ addFacets(Facet.MOD_PRIVATE); // Adjust name if (hasFacet(KIND_ARRAY_MEMBER)) fName = '[' + fName + ']'; else if (hasFacet(Facet.MOD_STATIC) && fName.startsWith(":")) //$NON-NLS-1$ fName = fName.substring(fName.lastIndexOf(':') + 1); else if (fName.equals("::")) //$NON-NLS-1$ fName = VariablesUtil.CLASS_INDICATOR; // Hopefully this will put the $ at appropriate point in the name if (fFullName.length() > 1 && fName.equals(fFullName.substring(1))) fName = fFullName; // Build value String type = DBGpResponse.getAttribute(fDescriptor, "type"); //$NON-NLS-1$ // Catch previous value string if there is any String previousValueString = null; if (fValue != null) { previousValueString = fValue.fValueString; } fDataType = DataType.find(type); if (fValue != null && fValue.getDataType() == fDataType) { fValue.update(fDescriptor); } else { fValue = (new DBGpValueBuilder()).build(this); } // Check if value has changed if (previousValueString != null) { fHasValueChanged = !previousValueString.equals(fValue.fValueString); } } }