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.PHPDBGProxy;
19 import org.eclipse.debug.core.DebugEvent;
20 import org.eclipse.debug.core.DebugException;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.ILaunch;
23 import org.eclipse.debug.core.model.IDebugTarget;
24 import org.eclipse.debug.core.model.IRegisterGroup;
25 import org.eclipse.debug.core.model.IStackFrame;
26 import org.eclipse.debug.core.model.IThread;
27 import org.eclipse.debug.core.model.IVariable;
31 * TODO Remove the variables array and use only the varList vector
32 * Have also to change hasVariables
34 public class PHPStackFrame extends PHPDebugElement implements IStackFrame, Comparable{
36 private PHPThread thread; // The thread to which this stackframe belongs
37 private String file; // The file name???
38 private int lineNumber; //
41 private PHPVariable[] variables; // The array of variables TODO: better introduce a vector?
42 private Vector varList = new Vector ();
43 private String description; // The source file name with the full path on target/remote system
44 private boolean fUpToDate; // Indicates whether the variable list within this stackframe is
46 private boolean fAvailable; // Needed when updating the stackframe list, shows whether the stackframe
47 // is within the list which was received from dbg
58 public PHPStackFrame (PHPThread thread, String file, int line, int index, String desc, int modno) {
61 this.lineNumber = line;
65 this.description = desc;
67 this.fUpToDate = false;
77 public PHPStackFrame (PHPThread thread, String file, int line, int index) {
80 this.lineNumber = line;
84 this.fUpToDate = false;
90 public IThread getThread () {
97 public void setThread (PHPThread thread) {
104 private void setUpToDate (boolean upToDate) {
105 fUpToDate = upToDate;
111 private boolean isUpToDate () {
118 public void setAvailable (boolean available) {
119 fAvailable = available;
125 public boolean isAvailable () {
131 * @see IAdaptable#getAdapter(Class)
133 public Object getAdapter(Class adapter) {
134 if (adapter == PHPStackFrame.class) {
138 return super.getAdapter(adapter);
145 private void resetHasChangedInfo (Vector varList) {
150 for (n = 0; n < varList.size (); n++) { // For every variable in 'DBG list'
151 var = (PHPVariable) varList.get (n); // Get the variable
152 val = (PHPValue) var.getValue (); // Get the variable's value
155 if (val.hasVariables ()) { // Do we have other variables within the value
156 if (!hasRecursion (var)) { // Is this variable (value) branch recursive?
157 resetHasChangedInfo (val.getChildVariables ()); // No, go into branch
161 catch (DebugException e) { // That's, because of the hasVariables method
164 var.setValueChanged (false); // Reset the 'has changed' flag
169 * Go up the tree of PHPVariables
170 * look whether the PHPValue is a reference to a parent PHPValue
172 * TODO Check where this recursion can come from.
173 * Whether this back reference is legal or a bug.
178 * <li> false if the PHPValue is not a child of itself
179 * <li> true if the PHPValue is
182 private boolean hasRecursion (PHPVariable var) {
183 PHPVariable parentVar;
186 val = (PHPValue) var.getValue (); // Get the PHPValue from the current PHPVariable
188 while (var != null) { // As long as we have PHPVariable
189 parentVar = var.getParent (); // Get the parent PHPVariable
191 if (parentVar != null) { // Is there a parent?
192 if (parentVar.getValue ().equals (val)) { // Get the PHPValue for the parent PHPVariable and check
193 // whether it is the same
194 return true; // Return, if we have recursion
201 return false; // No recursion found
205 * This method updates the 'static' variables list.
206 * It does a replication between the 'static' list (the variable list which
207 * is a member of this DBG interface object) and the DBG variable list
208 * (the list of variables which is received from PHP via DBG with the current suspend)
209 * Replication is done in the following way:
211 * <li> It looks for new variables within the DBG variables list and
212 * adds them to the 'static' list.
213 * <li> It looks for changed variables copies the current value to the variable within
214 * the 'static list' and mark these variables as 'hasChanged' (which uses the UI
215 * for showing the variable with a different color).
216 * <li> It looks for variables within the 'static' list, and removes them
217 * from the 'static' list in case the do not appear within the DBG list.
220 * @param varListOld The 'static' list of variables which are to be updated.
221 * @param varListNew The new list of (current) variables from DBG.
223 private void updateVariableList (Vector varListOld, Vector varListNew)
225 PHPVariable varOld; // The variable from the 'static' list
226 PHPVariable varNew; // The variable from the DBG list
227 PHPValue valOld; // The value of the current variable from 'static' list
228 PHPValue valNew; // The value of the current variable from DBG list
229 int n; // Index for the DBG list
230 int o; // Index for the static list
232 // Add the variables (and childs) to the static list if they are new
233 // and update the values of variables which are already existend within
234 // the 'static' list.
236 for (n = 0; n < varListNew.size (); n++) { // For every variable in 'DBG list'
237 varNew = (PHPVariable) varListNew.get (n); // Get the DBG variable
239 for (o = 0; o < varListOld.size (); o++) { // For every variable in static list
240 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
242 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list?
243 valOld = (PHPValue) varOld.getValue (); // Get the value from 'static'
244 valNew = (PHPValue) varNew.getValue (); // Get the value from DBG
247 if (valOld.hasVariables () || // If the 'static' value has child variables
248 valNew.hasVariables ()) { // or if the DBG value has child variables
249 if (!hasRecursion (varOld) &&
250 !hasRecursion (varNew)) { // Both branches should not have a recursion
251 updateVariableList (valOld.getChildVariables (), // Update the variable list for the child variables
252 valNew.getChildVariables ());
255 else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed?
256 valOld.setValueString (valNew.getValueString ()); // Yes, set the 'static' value (variable) to the new value
257 varOld.setValueChanged (true); // and set the 'has changed' flag, so that the variable view
258 // could show the user the changed status with a different
262 // varOld.setValueChanged (false); // Reset the 'has changed' flag
265 catch (DebugException e) { // That's, because of the hasVariables method
268 break; // Found the variable,
272 if (o == varListOld.size ()) { // Did we found the variable within the static list?
273 varListOld.add (varNew); // No, then add the DBG variable to the static list
277 // Look for the variables we can remove from the 'static' list
279 for (o = 0; o < varListOld.size (); o++) { // For every variable in 'static' list
280 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
282 for (n = 0; n < varListNew.size (); n++) { // For all variables in 'DBG' list
283 varNew = (PHPVariable) varListNew.get (n); // Get the variable from the 'DBG' list
285 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the 'static' list variable within the 'DBG' list?
286 break; // Yes we found the variable, then leave the loop
290 if (n == varListNew.size ()) { // Did not find the 'static' list variable within the 'DBG' list?
291 varListOld.remove (o); // then remove the 'static' list variable from list
292 o -= 1; // Adjust the 'static' list index
300 * This function returns the array of PHPVariables for this stackframe
301 * The PHPVariables should not change (newly build up) between two steps
303 * A PHPVariable with the same name but with different object ID is
304 * handled as a new variable.
306 * TODO Remove the intermediate storage array
308 * @return The array of PHPVariables for this stackframe.
310 public IVariable[] getVariables() throws DebugException {
311 if (!isUpToDate ()) {
312 resetHasChangedInfo (varList);
313 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
316 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
317 Arrays.sort(variables, new PHPVariableComparator());
320 return variables; // Give the array back to user interface
326 private PHPVariable findVariable (Vector varList, String varname) {
327 PHPVariable variable;
331 for (i = 0; i < varList.size (); i++) { // For all variables
332 variable = (PHPVariable) varList.get (i); // Get the variable
333 value = (PHPValue) variable.getValue (); // Get the value of the variable
336 if (value.hasVariables ()) { // Does the variable/value have children
337 if (!hasRecursion (variable)) { // Don't follow recursive variable/values
338 variable = findVariable (value.getChildVariables (), varname);
340 if (variable != null) {
345 else if ((variable.getName ()).equals (varname)) { //
349 catch (DebugException e) { // That's, because of the hasVariables method
357 * This method is called from the UI (e.g. from PHPDebugHover
358 * to find the variable the mouse is pointing to)
360 * @param s The variable name we are looking for.
363 public IVariable findVariable (String s) throws DebugException {
364 if (!isUpToDate ()) {
365 resetHasChangedInfo (varList);
366 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
369 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
372 return (findVariable (varList, s)); // Prefix the variable name with $
378 public boolean hasVariables () throws DebugException {
380 // return (varList.size () > 0);
383 public int getLineNumber() {
387 public void setLineNumber(int line) {
391 public int getCharStart() throws DebugException {
396 public int getCharEnd() throws DebugException {
401 public String getName() {
402 StringBuffer name = new StringBuffer();
404 if (!this.getDescription().equals ("")) {
405 name.append (this.getDescription ());
408 name.append (this.getFileName ());
411 name.append (" [line ");
412 name.append (this.getLineNumber ());
415 return name.toString();
418 public String getFileName() {
422 public void setDescription(String desc) {
423 this.description= desc;
426 public String getDescription() {
427 return this.description;
430 public IRegisterGroup[] getRegisterGroups() throws DebugException {
434 public boolean hasRegisterGroups() throws DebugException {
438 public String getModelIdentifier() {
439 return this.getThread().getModelIdentifier();
442 public IDebugTarget getDebugTarget() {
443 return this.getThread().getDebugTarget();
446 public ILaunch getLaunch() {
447 return this.getDebugTarget().getLaunch();
450 public boolean canStepInto() {
454 public boolean canStepOver() {
458 public boolean canStepReturn() {
462 public boolean isStepping() {
469 public void stepInto () throws DebugException {
474 thread.prepareForResume (DebugEvent.STEP_INTO); // Don't know why, but this is necessary
475 this.getPHPDBGProxy ().readStepIntoEnd (PHPStackFrame.this);
477 // Commented out sending the RESUME event because it was already sent by prepareForResume.
478 // The second RESUME event leads only to a little flickering within the variables view.
479 // It is also not clear why this event was necessary in eclipse < 3.2
480 // Also sending a SUSPEND event here leads to a total rebuild of the variables view.
481 // (eclipse 3.2 has a build in timeout of 500 ms which leads to a auto suspend, with
482 // no flickering... but why???)
484 //ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_INTO);
485 //DebugPlugin.getDefault().fireDebugEventSet (new DebugEvent[] { ev });
491 public void stepOver () throws DebugException {
496 thread.prepareForResume (DebugEvent.STEP_OVER);
497 this.getPHPDBGProxy ().readStepOverEnd (PHPStackFrame.this) ;
499 // See comment within the previous stepInto method.
501 //ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_OVER);
502 //DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
508 public void stepReturn () throws DebugException {
513 thread.prepareForResume (DebugEvent.STEP_RETURN);
514 this.getPHPDBGProxy ().readStepReturnEnd (PHPStackFrame.this) ;
516 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_RETURN);
517 DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
521 public boolean canResume() {
522 return this.getThread().canResume();
525 public boolean canSuspend() {
526 return this.getThread().canSuspend();
529 public boolean isSuspended() {
530 return this.getThread().isSuspended();
533 public void resume() throws DebugException {
535 this.getThread().resume();
538 public void suspend() throws DebugException {
541 public boolean canTerminate() {
542 return this.getThread().canTerminate();
545 public boolean isTerminated() {
546 return this.getThread().isTerminated();
549 public void terminate() throws DebugException {
550 getPHPDBGProxy().stop();
553 public int getIndex() {
557 public void setIndex (int index) {
561 public PHPDBGProxy getPHPDBGProxy() {
562 PHPDebugTarget DebugTarget;
564 DebugTarget = (PHPDebugTarget) thread.getDebugTarget ();
566 return DebugTarget.getPHPDBGProxy ();
569 public void setFile(String file) {
573 public int getModNo() {
578 * This function is needed when sorting the stackframes by their index numbers.
580 * @param obj The stackframe which this one is compared to.
583 * <li> -1 if the index of this stackframe is less.
584 * <li> 0 if the index of both stackfream is equal (should no happen).
585 * <li> 1 if the index of this stackfram is greater.
588 public int compareTo (Object obj)
590 if (index < ((PHPStackFrame) obj).getIndex ()) {
593 else if (index > ((PHPStackFrame) obj).getIndex ()) {