1) Added missing strings for italic, underline and strike through.
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / model / PHPDebugTarget.java
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
7
8  Contributors:
9  IBM Corporation - Initial implementation
10  Vicente Fernando - www.alfersoft.com.ar
11  **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core.model;
13
14 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
15 import net.sourceforge.phpdt.internal.debug.core.PHPDebugCorePlugin;
16 import net.sourceforge.phpdt.internal.debug.core.breakpoints.PHPLineBreakpoint;
17 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
18
19 import org.eclipse.core.resources.IMarkerDelta;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.debug.core.DebugEvent;
22 import org.eclipse.debug.core.DebugException;
23 import org.eclipse.debug.core.DebugPlugin;
24 import org.eclipse.debug.core.IBreakpointManager;
25 import org.eclipse.debug.core.IDebugEventSetListener;
26 import org.eclipse.debug.core.ILaunch;
27 import org.eclipse.debug.core.ILaunchListener;
28 import org.eclipse.debug.core.model.IBreakpoint;
29 import org.eclipse.debug.core.model.IDebugTarget;
30 import org.eclipse.debug.core.model.IMemoryBlock;
31 import org.eclipse.debug.core.model.IProcess;
32 import org.eclipse.debug.core.model.IStackFrame;
33 import org.eclipse.debug.core.model.IThread;
34 import org.eclipse.jface.resource.ImageDescriptor;
35 import org.eclipse.ui.model.IWorkbenchAdapter;
36
37 /**
38  * Debug target for PHP debug model.
39  */
40 public class PHPDebugTarget extends PHPDebugElement implements IPHPDebugTarget, ILaunchListener,
41                 IDebugEventSetListener {
42
43         private IProcess      process;
44         private ILaunch       launch;
45         private PHPThread[]   threads = new PHPThread[0];
46         private PHPDBGProxy   phpDBGProxy;
47
48         private class State {
49                 private boolean isTerminated = false;
50                 private boolean isSuspended  = false;
51
52                 boolean isTerminated() {
53                         return isTerminated;
54                 }
55
56                 boolean isSuspended() {
57                         return isSuspended;
58                 }
59
60                 void setTerminated(boolean terminated) {
61                         this.isTerminated = terminated;
62                 }
63
64                 void setSuspended(boolean suspended) {
65                         if (isTerminated())
66                                 throw new IllegalStateException();
67                         this.isSuspended = suspended;
68                 }
69         }
70
71         private final State state = new State();
72
73         public PHPDebugTarget(ILaunch launch, IProcess process) {
74                 super (null);
75                 if (null == launch && null == process)
76                         throw new IllegalArgumentException();
77                 this.launch = launch;
78                 this.process = process;
79                 // TODO XXX remove breakpoint listener at termination to avoid live leak
80                 IBreakpointManager manager = DebugPlugin.getDefault()
81                                 .getBreakpointManager();
82                 manager.addBreakpointListener(this);
83                 DebugPlugin.getDefault().addDebugEventListener(this);
84                 initialize();
85         }
86
87         protected synchronized void initialize() {
88                 DebugEvent ev = new DebugEvent(this, DebugEvent.CREATE);
89                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
90         }
91
92         public void addThread(PHPThread phpThread) {
93                 int i;
94                 PHPThread[] updatedThreads = new PHPThread[threads.length + 1];
95
96                 for (i = 0; i < threads.length; i++) {
97                         updatedThreads[i] = threads[i];
98                 }
99                 updatedThreads[i] = phpThread;
100                 threads = updatedThreads;
101
102                 fireChangeEvent();
103                 fireThreadCreateEvent(phpThread);
104         }
105
106         public void updateThreads (PHPThread phpThread) {
107                 fireChangeEvent ();
108                 fireThreadCreateEvent (phpThread);
109         }
110
111         private void fireChangeEvent() {
112                 DebugEvent ev = new DebugEvent(this, DebugEvent.CHANGE);
113                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
114         }
115
116         private void fireThreadCreateEvent(PHPThread phpThread) {
117                 DebugEvent ev = new DebugEvent(phpThread, DebugEvent.CREATE);
118                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
119         }
120
121 //      protected PHPThread getThreadById(int id) {
122 //              for (int i = 0; i < threads.length; i++) {
123 //                      if (threads[i].getId() == id) {
124 //                              return threads[i];
125 //                      }
126 //              }
127 //              return null;
128 //      }
129
130         public IThread[] getThreads() {
131                 return threads;
132         }
133
134         public boolean hasThreads() throws DebugException {
135                 return threads.length > 0;
136         }
137
138         public String getName() throws DebugException {
139                 return "PHP Debugger at localhost:" + getPHPDBGProxy().getPort();
140         }
141
142         public boolean supportsBreakpoint(IBreakpoint arg0) {
143                 if (arg0.getModelIdentifier().equals(PHPDebugCorePlugin.PLUGIN_ID)) {
144                         return true;
145                 }
146                 return false;
147         }
148
149         public String getModelIdentifier() {
150                 return PHPDebugCorePlugin.PLUGIN_ID;
151         }
152
153         public IStackFrame[] getStackFrames () throws DebugException {
154                 return (IStackFrame[]) this.phpDBGProxy.getDBGInterface ().getStackList ();
155         }
156
157         public IDebugTarget getDebugTarget() {
158                 return this;
159         }
160
161         public ILaunch getLaunch() {
162                 return launch;
163         }
164
165         public synchronized boolean canTerminate() {
166                 return !isTerminated();
167         }
168
169         public synchronized boolean isTerminated() {
170                 return state.isTerminated();
171         }
172
173         private synchronized void terminateThreads () {
174                 int i;
175
176                 try {
177                         for (i = 0; i < threads.length; i++) {
178                                 threads[i].terminate ();
179                         }
180                 } catch (DebugException e) {
181                 }
182         }
183
184         public synchronized void terminate() {
185                 // This method is synchronized to control a race condition between the
186                 // UI thread that terminates the debugging session, and the slave
187                 // thread that executes PHPLoop.run
188                 if (isTerminated())
189                         // Avoid terminating twice...
190                         return;
191                 state.setTerminated(true);
192                 phpDBGProxy.stop();
193                 terminateThreads ();
194                 this.threads = new PHPThread[0];
195                 fireChangeEvent();
196                 IBreakpointManager manager = DebugPlugin.getDefault()
197                                 .getBreakpointManager();
198                 manager.removeBreakpointListener(this);
199                 DebugPlugin.getDefault().removeDebugEventListener(this);
200         }
201
202         public synchronized boolean canResume() {
203                 if (isTerminated())
204                         return false;
205                 return isSuspended();
206         }
207
208         public synchronized boolean canSuspend() {
209                 if (isTerminated())
210                         return false;
211                 return !isSuspended();
212         }
213
214         public synchronized boolean isSuspended() {
215                 return state.isSuspended();
216         }
217
218         public synchronized void resume() throws DebugException {
219                 if (!isSuspended())
220                         return;
221                 state.setSuspended(false);
222                 this.getPHPDBGProxy().resume();
223                 IThread[] threads = getThreads();
224                 for (int i = 0; i < threads.length; ++i)
225                         threads[i].resume();
226         }
227
228         public synchronized void suspend() throws DebugException {
229                 if (isSuspended())
230                         return;
231                 this.getPHPDBGProxy().pause();
232                 state.setSuspended(true);
233                 IThread[] threads = getThreads();
234                 for (int i = 0; i < threads.length; ++i)
235                         threads[i].suspend();
236         }
237
238         public void breakpointAdded(IBreakpoint breakpoint) {
239                 this.getPHPDBGProxy().addBreakpoint(breakpoint);
240         }
241
242         public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta arg1) {
243                 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
244         }
245
246         /**
247          * The method will be called when the user enables/disables
248          * breakpoints. In this case we add or remove the breakpoint.
249          * It's also called when leaving the breakpoint properties dialog
250          * (skip count and breakpoint condition) with the OK button.
251          *
252          * This method is also called whenever a source file has changed.
253          * In this case we terminate since the source will be out of sync with the debugger.
254          * TODO Is it correct to call this method when a sourcefile is modified?
255          *
256          */
257         public void breakpointChanged (IBreakpoint breakpoint, IMarkerDelta arg1) {
258                 PHPLineBreakpoint bp;
259                 bp = (PHPLineBreakpoint) breakpoint;
260
261                 try {
262                         if (breakpoint.isEnabled ()     &&                                                                      // Check if breakpoint state changed from disabled to enabled
263                                 !arg1.getAttribute ("org.eclipse.debug.core.enabled", false)) {
264                                 this.getPHPDBGProxy().addBreakpoint(breakpoint);
265                         }
266                         else if (!breakpoint.isEnabled () &&                                                    // Check if breakpoint state changed from enabled to disabled
267                             arg1.getAttribute ("org.eclipse.debug.core.enabled", true)) {
268                                 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
269                         }
270                         else if (bp.getChangeID() != arg1.getAttribute ("net.sourceforge.phpeclipse.debug.changeID", 0)) {
271                                 if (breakpoint.isEnabled()) {                                                           // If the breakpoint is already enabled
272                                         this.getPHPDBGProxy().removeBreakpoint(breakpoint);             // we remove this breakpoint first
273                                         this.getPHPDBGProxy().addBreakpoint(breakpoint);                // and then we add again (else DBG would have two breakpoints!).
274                                 }
275                                 else {
276                                         this.getPHPDBGProxy().removeBreakpoint(breakpoint);
277                                 }
278                         }
279                         else {                                                                                                                  // All other cases will terminate the debugger
280                                 terminate ();
281                         }
282                 } catch (CoreException e) {
283                         // Do nothing
284                 }
285         }
286
287         public boolean canDisconnect() {
288                 return false;
289         }
290
291         public void disconnect() throws DebugException {
292         }
293
294         public boolean isDisconnected() {
295                 return false;
296         }
297
298         public boolean supportsStorageRetrieval() {
299                 return false;
300         }
301
302         public IMemoryBlock getMemoryBlock(long arg0, long arg1)
303                         throws DebugException {
304                 return null;
305         }
306
307         public Object getAdapter(Class arg0) {
308                 if (IWorkbenchAdapter.class.equals(arg0)) {
309                         return new IWorkbenchAdapter() {
310                                 public Object[] getChildren(Object o) {
311                                         Object[] children = null;
312                                         IThread[] threads = getThreads();
313                                         if (null != threads) {
314                                                 children = new Object[threads.length];
315                                                 for (int i = 0; i < threads.length; ++i)
316                                                         children[i] = threads[i];
317                                         }
318                                         return children;
319                                 }
320
321                                 public ImageDescriptor getImageDescriptor(Object object) {
322                                         return null;
323                                 }
324
325                                 public String getLabel(Object o) {
326                                         String label = "(Unable to look up name... check error log)";
327                                         try {
328                                                 label = getName();
329                                         } catch (DebugException x) {
330                                                 PHPeclipsePlugin.log(label, x);
331                                         }
332                                         return label;
333                                 }
334
335                                 public Object getParent(Object o) {
336                                         return PHPDebugTarget.this.getLaunch();
337                                 }
338                         };
339                 }
340                 else {
341                     if (arg0 == PHPDebugElement.class) {
342                         return this;
343                     }
344
345                     return super.getAdapter(arg0);
346                 }
347         }
348
349         public IProcess getProcess() {
350                 return process;
351         }
352
353         public void setProcess(IProcess process) {
354                 this.process = process;
355         }
356
357         public PHPDBGProxy getPHPDBGProxy() {
358                 return phpDBGProxy;
359         }
360
361         public void setPHPDBGProxy(PHPDBGProxy phpDBGProxy) {
362                 this.phpDBGProxy = phpDBGProxy;
363         }
364
365         /**
366          * @see ILaunchListener#launchRemoved(ILaunch)
367          */
368         public void launchRemoved(ILaunch launch) {
369                 if (!isTerminated()) {
370                         return;
371                 }
372                 if (launch.equals(getLaunch())) {
373                         // This target has been deregistered, but it hasn't successfully
374                         // terminated.
375                         // Update internal state to reflect that it is disconnected
376                         terminate();
377                 }
378         }
379
380         /**
381          * @see ILaunchListener#launchAdded(ILaunch)
382          */
383         public void launchAdded(ILaunch launch) {
384         }
385
386         /**
387          * @see ILaunchListener#launchChanged(ILaunch)
388          */
389         public void launchChanged(ILaunch launch) {
390         }
391
392         /**
393          * When a debug target or process terminates, terminate DBG Proxy.
394          *
395          * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[])
396          */
397         public void handleDebugEvents(DebugEvent[] events) {
398                 for (int i = 0; i < events.length; i++) {
399                         DebugEvent event = events[i];
400                         if (event.getKind() == DebugEvent.TERMINATE) {
401                                 Object source = event.getSource();
402                                 if (source instanceof PHPDebugTarget
403                                                 || source instanceof IDebugTarget) {
404                                         getPHPDBGProxy().stop();
405                                 } else if (source instanceof IProcess) {
406                                         if (getDebugTarget().getProcess() == (IProcess) source) {
407                                                 getPHPDBGProxy().stop();
408                                         }
409                                 }
410                         } else if (event.getKind() == DebugEvent.SUSPEND) {
411                                 getPHPDBGProxy().pause();
412                         }
413                 }
414         }
415 }