X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java index 91d1868..67aacaf 100644 --- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java +++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java @@ -6,11 +6,13 @@ */ package net.sourceforge.phpeclipse.xdebug.php.model; -import java.net.MalformedURLException; -import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.Vector; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils; -import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.XDebugResponse; +import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugResponse; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; @@ -19,6 +21,8 @@ import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.model.IWorkbenchAdapter; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -30,19 +34,19 @@ import org.w3c.dom.NodeList; */ public class XDebugThread extends XDebugElement implements IThread, IDebugEventSetListener { private XDebugStackFrame[] fStackFrames; - - private IBreakpoint[] fBreakpoints; - - /* Whether this thread is stepping */ - private boolean fStepping = false; - private boolean fTerminated = false; - - private int fStepCount = 0; - private int fCurrentStepCount = 0; - + private IBreakpoint[] fBreakpoints; + + private boolean fStepping = false; // Whether this thread is stepping + private boolean fTerminated = false; + + private int fStepCount = 0; + private int fCurrentStepCount = 0; + + private Vector stackListOld = new Vector(); // The 'static' list of stack frames + /** * Constructs a new thread for the given target - * + * * @param target VM */ public XDebugThread(XDebugTarget target) { @@ -50,102 +54,271 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS DebugPlugin.getDefault().addDebugEventListener(this); fStackFrames = null; } - + + /** + * + */ + public void setStackFrames (XDebugStackFrame[] frames) { + this.fStackFrames = frames; + } + public void incrementStepCounter() { fStepCount++; } + + /** + * + * @param arg0 + * @return + */ + public Object getAdapter (Class arg0) { + if (IWorkbenchAdapter.class.equals (arg0)) { + return new IWorkbenchAdapter() { + public Object[] getChildren(Object o) { + try { + return getStackFrames (); + } catch (DebugException x) { + PHPeclipsePlugin.log ("Unable to get stack frames.", x); + } + + return new Object[0]; + } + + public ImageDescriptor getImageDescriptor(Object object) { + return null; + } + + public String getLabel(Object o) { + throw new UnsupportedOperationException(); + } + + public Object getParent(Object o) { + return getDebugTarget(); + } + }; + } + return super.getAdapter(arg0); + } + + /** + * Reset the availability flag for all stackframes in the list. + * + * @param list The list of old stackframes + */ + private void resetAvailability (Vector list) { + int i; + + for (i = 0; i < list.size (); i++) { + ((XDebugStackFrame) list.get(i)).setAvailable (false); // + } + } + + /** + * Check whether the new stackframe is in the list of old stackframes. + * Test for identical stackframe (identical means same description and same line number). + * + * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list + * @param list The list of old stackframes + * @return + * - true if we have found the identical stackframe within the list + * - false if we did not find the identical stackframe within the list + */ + private boolean isStackFrameInList (XDebugStackFrame stackFrameNew, Vector list) { + int i; + XDebugStackFrame stackFrameOld; + + for (i = 0; i < list.size (); i++) { + stackFrameOld = (XDebugStackFrame) list.get (i); // + + if (stackFrameNew.getFullName ().equals (stackFrameOld.getFullName ()) && + stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) && + stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes? + stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames + stackFrameOld.setLevel (stackFrameNew.getLevel ()); + stackFrameOld.setUpToDate (false); // Need to update the variables + + return true; // The stackframe was found in the list + } + } + + return false; + } + + /** + * Check whether the new stackframe is in the list of old stackframes. + * Test for exact stackframe (exact means same description and same line number). + * + * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list + * @param list The list of old stackframes + * @return + * - true if we have exactly this stackframe within the list + * - false if we did not find the exact stackframe within the list + */ + private void markIdenticalStackFrames (Vector oldList, Vector newList) { + int i; + XDebugStackFrame stackFrameNew; + + resetAvailability (oldList); // Reset the availability flag of the old stack frames + resetAvailability (newList); // Reset the availability flag of the old stack frames + + for (i = 0; i < newList.size (); i++) { // For all stackList entries + stackFrameNew = (XDebugStackFrame) newList.get (i); + + if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list + stackFrameNew.setAvailable (true); // + // +// break; + } + } + } + + /** + * + * The stackList contains the currently read stackframes which were sent + * from DBG. The DBG interface holds a list of the active stack frames. + * This method replicates the 'static' stackframe list with the DBG stackframe list + * Replication is done in the following way: + * + * + * Removes the unused stackframes from the list, or adds stackframes which + * are not yet in the list. + * + * + * @param stackList + */ + private void updateStackFrameList (Vector stackList) { + int i; + int n; + XDebugStackFrame stackFrameNew; + XDebugStackFrame stackFrameOld; + XDebugStackFrame[] newStackList; + + markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list + // of old stack frames + + for (i = 0; i < stackList.size (); i++) { // For all stackList entries + stackFrameNew = (XDebugStackFrame) stackList.get(i); + + for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list + stackFrameOld = (XDebugStackFrame) stackListOld.get (n); // + + if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it + continue; + } + + if (stackFrameNew.getFullName ().equals (stackFrameOld.getFullName ()) && // Did we find the sent stackframe within the list of old stackframes? + stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes? + stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ()); + stackFrameOld.setLevel (stackFrameNew.getLevel ()); + stackFrameOld.setUpToDate (false); // Need to update the variables + + stackFrameOld.setAvailable (true); // And mark this stack frame as available + stackFrameNew.setAvailable (true); // And mark this stack frame as available + + break; // Yes, then break; + } + } + + if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list? + stackFrameNew.setAvailable (true); // Mark the stack frame as available and + stackListOld.add (stackFrameNew); // then add the new stackframe + } + } + + // And now for removing unused stackframes from list + + for (n = 0; n < stackListOld.size(); n++) { + stackFrameOld = (XDebugStackFrame) stackListOld.get(n); + + if (!stackFrameOld.isAvailable()) { + stackListOld.remove(n--); + } + } + + Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers. + // + newStackList = new XDebugStackFrame[stackListOld.size ()]; + newStackList = (XDebugStackFrame[]) stackListOld.toArray (newStackList); + +// DBGStackList = newStackList; + fStackFrames = newStackList; + } + + public IStackFrame[] getStackFrames() throws DebugException { if (!isSuspended()) { return new IStackFrame[0]; } - - if (fStepCount > fCurrentStepCount) { - XDebugResponse dr = ((XDebugTarget) getDebugTarget()).getStackFrames(); - XDebugStackFrame[] newStackFrames = _getStackFrames(dr); - - /*if (fStackFrames != null) { - if (newStackFrames.length >= fStackFrames.length) { - int delta = newStackFrames.length - fStackFrames.length + 1; - - for (int i = fStackFrames.length - 1; i >= 0; i--) { - if (fStackFrames[i].equals(newStackFrames[newStackFrames.length - delta])) { - int b = 2; b++; - //((XDebugStackFrame) newStackFrames[newStackFrames.length - delta]).evaluateChange((XDebugStackFrame) fStackFrames[i]); - } else if (fStackFrames[i].isSameStackFrame(newStackFrames[newStackFrames.length - delta])) { - int b = 2; b++; - //((XDebugStackFrame) newStackFrames[newStackFrames.length - delta]).evaluateChange((XDebugStackFrame) fStackFrames[i]); - } - - delta ++; - } - } else { - fStackFrames = newStackFrames; - } - } else { - fStackFrames = newStackFrames; - }*/ - fCurrentStepCount++; + if (fStepCount > fCurrentStepCount) { // Do we need to update the list of stackframes + XDebugResponse dr = ((XDebugTarget) getDebugTarget()).getStackFrames(); // Get the stackframes list from XDebug + XDebugStackFrame[] newStackFrames = _getStackFrames(dr); // Parse the stackframes list - fStackFrames = newStackFrames; + updateStackFrameList (new Vector (Arrays.asList(newStackFrames))); // update the 'static' list of stackframes + + fCurrentStepCount++; // } return fStackFrames; } - - + + private XDebugStackFrame[] _getStackFrames(XDebugResponse lastResponse) { if (lastResponse.isError()) { return new XDebugStackFrame[0]; } - - Node response = lastResponse.getParentNode(); - NodeList frames = response.getChildNodes(); - XDebugStackFrame[] theFrames = new XDebugStackFrame[frames.getLength()]; + + Node response = lastResponse.getParentNode(); + NodeList frames = response.getChildNodes(); + XDebugStackFrame[] theFrames = new XDebugStackFrame[frames.getLength()]; + for (int i = 0; i < frames.getLength(); i++) { - Node stackNode = frames.item(i); - XDebugStackFrame frame = new XDebugStackFrame(this/*fThread*/, i); - String level =PHPDebugUtils.getAttributeValue(stackNode,"level"); - if (!"".equals(level)) - frame.setLevel(Integer.parseInt(level)); - - frame.setType(PHPDebugUtils.getAttributeValue(stackNode,"type")); - String fileName=PHPDebugUtils.unescapeString(PHPDebugUtils.getAttributeValue(stackNode,"filename")); - String lineNo=PHPDebugUtils.getAttributeValue(stackNode,"lineno"); - - if (!"".equals(lineNo)) - frame.setLineNumber(Integer.parseInt(lineNo)); - - frame.setWhere(PHPDebugUtils.getAttributeValue(stackNode,"where")); - - try { - frame.setFullName(new URL(fileName)); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - + Node stackNode = frames.item(i); + String fileName = PHPDebugUtils.unescapeString(PHPDebugUtils.getAttributeValue(stackNode,"filename")); + String lineNo = PHPDebugUtils.getAttributeValue(stackNode,"lineno"); + + XDebugStackFrame frame = new XDebugStackFrame (this, + i, + PHPDebugUtils.getAttributeValue(stackNode,"type"), + Integer.parseInt(lineNo), + PHPDebugUtils.getAttributeValue(stackNode,"where"), + fileName); + frame.incrementStepCounter(); - + theFrames[i] = frame; } return theFrames; } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IThread#hasStackFrames() */ public boolean hasStackFrames() throws DebugException { - return isSuspended(); + if (fStackFrames == null) { + return false; + } + + return fStackFrames.length > 0; } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IThread#getPriority() */ public int getPriority() throws DebugException { return 0; } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IThread#getTopStackFrame() */ @@ -154,10 +327,10 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS if (frames.length > 0) { return frames[0]; } - - return null; + + return null; } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IThread#getName() */ @@ -174,68 +347,68 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS } return fBreakpoints; } - + /** * Sets the breakpoints this thread is suspended at, or null * if none. - * + * * @param breakpoints the breakpoints this thread is suspended at, or null * if none */ protected void setBreakpoints(IBreakpoint[] breakpoints) { fBreakpoints = breakpoints; } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canResume() */ public boolean canResume() { return isSuspended(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() */ public boolean canSuspend() { return !isTerminated() && !isSuspended(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() */ public boolean isSuspended() { - return fTarget.isSuspended(); + return getDebugTarget().isSuspended(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#resume() */ public void resume() throws DebugException { - fBreakpoints=null; - fTarget.resume(); + fBreakpoints = null; + getDebugTarget().resume(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#suspend() */ public void suspend() throws DebugException { - fTarget.suspend(); + getDebugTarget().suspend(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepInto() */ public boolean canStepInto() { return isSuspended(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepOver() */ public boolean canStepOver() { return isSuspended(); } - + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepReturn() */ @@ -258,24 +431,24 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS * @see org.eclipse.debug.core.model.IStep#stepInto() */ public void stepInto() throws DebugException { - fBreakpoints=null; - fTarget.step_into(); + fBreakpoints = null; + ((XDebugTarget) getDebugTarget()).step_into(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#stepOver() */ public void stepOver() throws DebugException { - fBreakpoints=null; - fTarget.step_over(); + fBreakpoints = null; + ((XDebugTarget) getDebugTarget()).step_over(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#stepReturn() */ public void stepReturn() throws DebugException { - fBreakpoints=null; - fTarget.step_out(); + fBreakpoints = null; + ((XDebugTarget) getDebugTarget()).step_out(); } /* (non-Javadoc) @@ -296,17 +469,17 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS * @see org.eclipse.debug.core.model.ITerminate#terminate() */ public void terminate() throws DebugException { - fTarget.getDebugConnection().stop(); + ((XDebugTarget) getDebugTarget()).getDebugConnection().stop(); fTerminated = true; } - + public void terminated() throws DebugException { fTerminated = true; } /** * Sets whether this thread is stepping - * + * * @param stepping whether stepping */ protected void setStepping(boolean stepping) { @@ -315,10 +488,30 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS public void handleDebugEvents(DebugEvent[] events) { DebugEvent de = events[0]; - System.out.println(de.toString()); + System.out.println(de.toString()); } public void removeEventListeners() { DebugPlugin.getDefault().removeDebugEventListener(this); } -} \ No newline at end of file + + /** + * Fires a RESUME event for this element with + * the given detail. + * + * @param detail event detail code + */ + public void fireResumeEvent(int detail) { + fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail)); + } + + /** + * Fires a SUSPEND event for this element with + * the given detail. + * + * @param detail event detail code + */ + public void fireSuspendEvent (int detail) { + fireEvent (new DebugEvent (this, DebugEvent.SUSPEND, detail)); + } +}