1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 IBM Corporation - Initial implementation
10 Vicente Fernando - www.alfersoft.com.ar
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core.model;
14 import java.util.Arrays;
15 import java.util.Vector;
17 import net.sourceforge.phpdt.internal.debug.core.PHPDBGBase;
18 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
20 import org.eclipse.core.runtime.IAdaptable;
21 import org.eclipse.debug.core.DebugEvent;
22 import org.eclipse.debug.core.DebugException;
23 import org.eclipse.debug.core.ILaunch;
24 import org.eclipse.debug.core.model.IDebugTarget;
25 import org.eclipse.debug.core.model.IRegisterGroup;
26 import org.eclipse.debug.core.model.IStackFrame;
27 import org.eclipse.debug.core.model.IThread;
28 import org.eclipse.debug.core.model.IVariable;
32 * TODO Remove the variables array and use only the varList vector
33 * Have also to change hasVariables
35 public class PHPStackFrame extends PHPDebugElement implements IStackFrame, Comparable {
37 private PHPThread thread; // The thread to which this stackframe belongs
38 private String file; // The file name???
39 private int lineNumber;
42 private int scope_id; // scope id
43 private PHPVariable[] variables; // The array of variables TODO: better introduce a vector?
44 private Vector varList = new Vector();
45 private String description; // The source file name with the full path on target/remote system
46 private boolean fUpToDate; // Indicates whether the variable list within this stackframe is
48 private boolean fAvailable; // Needed when updating the stackframe list, shows whether the stackframe
49 // is within the list which was received from dbg
61 public PHPStackFrame(PHPThread thread, String file, int line, int index,
62 String desc, int modno, int scope_id) {
65 this.lineNumber = line;
69 this.description = desc;
71 this.scope_id = scope_id;
72 this.fUpToDate = false;
82 public PHPStackFrame (PHPThread thread, String file, int line, int index) {
85 this.lineNumber = line;
89 this.fUpToDate = false;
96 public int getScopeID() {
103 public void setScopeID(int scope_id) {
104 this.scope_id = scope_id;
111 public IThread getThread () {
118 public void setThread (PHPThread thread) {
119 this.thread = thread;
125 private void setUpToDate (boolean upToDate) {
126 fUpToDate = upToDate;
132 private boolean isUpToDate () {
139 public void setAvailable (boolean available) {
140 fAvailable = available;
146 public boolean isAvailable () {
152 * @see IAdaptable#getAdapter(Class)
154 public Object getAdapter(Class adapter) {
155 if (adapter == PHPStackFrame.class) {
159 return super.getAdapter(adapter);
166 private void resetHasChangedInfo (Vector varList) {
171 for (n = 0; n < varList.size (); n++) { // For every variable in 'DBG list'
172 var = (PHPVariable) varList.get (n); // Get the variable
173 val = (PHPValue) var.getValue (); // Get the variable's value
176 if (val.hasVariables ()) { // Do we have other variables within the value
177 if (!hasRecursion (var)) { // Is this variable (value) branch recursive?
178 resetHasChangedInfo (val.getChildVariables ()); // No, go into branch
182 catch (DebugException e) { // That's, because of the hasVariables method
185 var.setValueChanged (false); // Reset the 'has changed' flag
190 * Go up the tree of PHPVariables
191 * look whether the PHPValue is a reference to a parent PHPValue
193 * TODO Check where this recursion can come from.
194 * Whether this back reference is legal or a bug.
199 * <li> false if the PHPValue is not a child of itself
200 * <li> true if the PHPValue is
203 private boolean hasRecursion (PHPVariable var) {
204 PHPVariable parentVar;
207 val = (PHPValue) var.getValue (); // Get the PHPValue from the current PHPVariable
209 while (var != null) { // As long as we have PHPVariable
210 parentVar = var.getParent (); // Get the parent PHPVariable
212 if (parentVar != null) { // Is there a parent?
213 if (parentVar.getValue ().equals (val)) { // Get the PHPValue for the parent PHPVariable and check
214 // whether it is the same
215 return true; // Return, if we have recursion
222 return false; // No recursion found
226 * This method updates the 'static' variables list.
227 * It does a replication between the 'static' list (the variable list which
228 * is a member of this DBG interface object) and the DBG variable list
229 * (the list of variables which is received from PHP via DBG with the current suspend)
230 * Replication is done in the following way:
232 * <li> It looks for new variables within the DBG variables list and
233 * adds them to the 'static' list.
234 * <li> It looks for changed variables copies the current value to the variable within
235 * the 'static list' and mark these variables as 'hasChanged' (which uses the UI
236 * for showing the variable with a different color).
237 * <li> It looks for variables within the 'static' list, and removes them
238 * from the 'static' list in case the do not appear within the DBG list.
241 * @param varListOld The 'static' list of variables which are to be updated.
242 * @param varListNew The new list of (current) variables from DBG.
244 private void updateVariableList (Vector varListOld, Vector varListNew)
246 PHPVariable varOld; // The variable from the 'static' list
247 PHPVariable varNew; // The variable from the DBG list
248 PHPValue valOld; // The value of the current variable from 'static' list
249 PHPValue valNew; // The value of the current variable from DBG list
250 int n; // Index for the DBG list
251 int o; // Index for the static list
253 // Add the variables (and childs) to the static list if they are new
254 // and update the values of variables which are already existend within
255 // the 'static' list.
257 for (n = 0; n < varListNew.size (); n++) { // For every variable in 'DBG list'
258 varNew = (PHPVariable) varListNew.get (n); // Get the DBG variable
260 for (o = 0; o < varListOld.size (); o++) { // For every variable in static list
261 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
263 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list?
264 valOld = (PHPValue) varOld.getValue (); // Get the value from 'static'
265 valNew = (PHPValue) varNew.getValue (); // Get the value from DBG
268 if (valOld.hasVariables () || // If the 'static' value has child variables
269 valNew.hasVariables ()) { // or if the DBG value has child variables
270 if (!hasRecursion (varOld) &&
271 !hasRecursion (varNew)) { // Both branches should not have a recursion
272 updateVariableList (valOld.getChildVariables (), // Update the variable list for the child variables
273 valNew.getChildVariables ());
276 else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed?
277 valOld.setValueString (valNew.getValueString ()); // Yes, set the 'static' value (variable) to the new value
278 varOld.setValueChanged (true); // and set the 'has changed' flag, so that the variable view
279 // could show the user the changed status with a different
283 // varOld.setValueChanged (false); // Reset the 'has changed' flag
286 catch (DebugException e) { // That's, because of the hasVariables method
289 break; // Found the variable,
293 if (o == varListOld.size ()) { // Did we found the variable within the static list?
294 varListOld.add (varNew); // No, then add the DBG variable to the static list
298 // Look for the variables we can remove from the 'static' list
300 for (o = 0; o < varListOld.size (); o++) { // For every variable in 'static' list
301 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
303 for (n = 0; n < varListNew.size (); n++) { // For all variables in 'DBG' list
304 varNew = (PHPVariable) varListNew.get (n); // Get the variable from the 'DBG' list
306 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the 'static' list variable within the 'DBG' list?
307 break; // Yes we found the variable, then leave the loop
311 if (n == varListNew.size ()) { // Did not find the 'static' list variable within the 'DBG' list?
312 varListOld.remove (o); // then remove the 'static' list variable from list
313 o -= 1; // Adjust the 'static' list index
320 * This function returns the array of PHPVariables for this stackframe
321 * The PHPVariables should not change (newly build up) between two steps
323 * A PHPVariable with the same name but with different object ID is
324 * handled as a new variable.
326 * TODO Remove the intermediate storage array
328 * @return The array of PHPVariables for this stackframe.
330 public IVariable[] getVariables() throws DebugException {
332 resetHasChangedInfo(varList);
333 updateVariableList(varList, this.getPHPDBGProxy().readVariables(this));
336 variables = (PHPVariable[]) varList.toArray(new PHPVariable[varList.size()]);
337 Arrays.sort(variables, new PHPVariableComparator());
340 return variables; // Give the array back to user interface
346 private PHPVariable findVariable (Vector varList, String varname) {
347 PHPVariable variable;
351 for (i = 0; i < varList.size (); i++) { // For all variables
352 variable = (PHPVariable) varList.get (i); // Get the variable
353 value = (PHPValue) variable.getValue (); // Get the value of the variable
356 if (value.hasVariables ()) { // Does the variable/value have children
357 if (!hasRecursion (variable)) { // Don't follow recursive variable/values
358 variable = findVariable (value.getChildVariables (), varname);
360 if (variable != null) {
365 else if ((variable.getName ()).equals (varname)) { //
369 catch (DebugException e) { // That's, because of the hasVariables method
377 * This method is called from the UI (e.g. from PHPDebugHover
378 * to find the variable the mouse is pointing to)
380 * @param s The variable name we are looking for.
383 public IVariable findVariable (String s) throws DebugException {
384 if (!isUpToDate ()) {
385 resetHasChangedInfo (varList);
386 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
389 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
392 return (findVariable (varList, s)); // Prefix the variable name with $
398 public boolean hasVariables () throws DebugException {
400 // return (varList.size () > 0);
403 public int getLineNumber() {
407 public void setLineNumber(int line) {
411 public int getCharStart() throws DebugException {
416 public int getCharEnd() throws DebugException {
421 public String getName() {
422 StringBuffer name = new StringBuffer();
424 if (!this.getDescription().equals ("")) {
425 name.append (this.getDescription ());
428 name.append (this.getFileName ());
431 name.append (" [line ");
432 name.append (this.getLineNumber ());
435 return name.toString();
438 public String getFileName() {
442 public void setDescription(String desc) {
443 this.description= desc;
446 public String getDescription() {
447 return this.description;
450 public IRegisterGroup[] getRegisterGroups() throws DebugException {
454 public boolean hasRegisterGroups() throws DebugException {
458 public String getModelIdentifier() {
459 return this.getThread().getModelIdentifier();
462 public IDebugTarget getDebugTarget() {
463 return this.getThread().getDebugTarget();
466 public ILaunch getLaunch() {
467 return this.getDebugTarget().getLaunch();
470 public boolean canStepInto() {
474 public boolean canStepOver() {
478 public boolean canStepReturn() {
482 public boolean isStepping() {
489 public void stepInto () throws DebugException {
494 thread.prepareForResume (DebugEvent.STEP_INTO); // Don't know why, but this is necessary
495 this.getPHPDBGProxy ().readStepIntoEnd (PHPStackFrame.this);
497 // Commented out sending the RESUME event because it was already sent by prepareForResume.
498 // The second RESUME event leads only to a little flickering within the variables view.
499 // It is also not clear why this event was necessary in eclipse < 3.2
500 // Also sending a SUSPEND event here leads to a total rebuild of the variables view.
501 // (eclipse 3.2 has a build in timeout of 500 ms which leads to a auto suspend, with
502 // no flickering... but why???)
504 //ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_INTO);
505 //DebugPlugin.getDefault().fireDebugEventSet (new DebugEvent[] { ev });
511 public void stepOver () throws DebugException {
516 thread.prepareForResume (DebugEvent.STEP_OVER);
517 this.getPHPDBGProxy ().readStepOverEnd (PHPStackFrame.this) ;
519 // See comment within the previous stepInto method.
521 //ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_OVER);
522 //DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
528 public void stepReturn () throws DebugException {
533 thread.prepareForResume (DebugEvent.STEP_RETURN);
534 this.getPHPDBGProxy ().readStepReturnEnd (PHPStackFrame.this) ;
536 //ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_RETURN);
537 //DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
541 public boolean canResume() {
542 return this.getThread().canResume();
545 public boolean canSuspend() {
546 return this.getThread().canSuspend();
549 public boolean isSuspended() {
550 return this.getThread().isSuspended();
553 public void resume() throws DebugException {
555 this.getThread().resume();
558 public void suspend() throws DebugException {
561 public boolean canTerminate() {
562 return this.getThread().canTerminate();
565 public boolean isTerminated() {
566 return this.getThread().isTerminated();
569 public void terminate() throws DebugException {
570 getPHPDBGProxy().stop();
573 public int getIndex() {
577 public void setIndex (int index) {
581 public PHPDBGProxy getPHPDBGProxy() {
582 PHPDebugTarget DebugTarget;
584 DebugTarget = (PHPDebugTarget) thread.getDebugTarget ();
586 return DebugTarget.getPHPDBGProxy ();
589 public void setFile(String file) {
593 public int getModNo() {
598 * This function is needed when sorting the stackframes by their index numbers.
600 * @param obj The stackframe which this one is compared to.
603 * <li> -1 if the index of this stackframe is less.
604 * <li> 0 if the index of both stackfream is equal (should no happen).
605 * <li> 1 if the index of this stackfram is greater.
608 public int compareTo (Object obj)
610 if (index < ((PHPStackFrame) obj).getIndex ()) {
613 else if (index > ((PHPStackFrame) obj).getIndex ()) {