8cfe6d86752e16d5ba3213156aa286b8fdbbd13b
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation 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 API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16
17 import net.sourceforge.phpdt.core.ICompilationUnit;
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IJavaModel;
20 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
21 import net.sourceforge.phpdt.core.IJavaProject;
22 import net.sourceforge.phpdt.core.IMember;
23 import net.sourceforge.phpdt.core.IOpenable;
24 import net.sourceforge.phpdt.core.IParent;
25 import net.sourceforge.phpdt.core.ISourceRange;
26 import net.sourceforge.phpdt.core.ISourceReference;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
29 import net.sourceforge.phpdt.core.jdom.IDOMNode;
30 import net.sourceforge.phpdt.internal.corext.Assert;
31
32 import org.eclipse.core.resources.IResource;
33 import org.eclipse.core.resources.IResourceStatus;
34 import org.eclipse.core.resources.ResourcesPlugin;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IAdaptable;
37 import org.eclipse.core.runtime.IPath;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.Path;
40 import org.eclipse.core.runtime.PlatformObject;
41 import org.eclipse.core.runtime.jobs.ISchedulingRule;
42 import net.sourceforge.phpdt.internal.core.JavaElementInfo;
43
44 import net.sourceforge.phpdt.internal.core.JavaModelManager;
45 import net.sourceforge.phpdt.internal.core.util.Util;
46
47 /**
48  * Root of Java element handle hierarchy.
49  *
50  * @see IJavaElement
51  */
52 public abstract class JavaElement extends PlatformObject implements IJavaElement {
53
54         public static final char JEM_JAVAPROJECT= '=';
55         public static final char JEM_PACKAGEFRAGMENTROOT= Path.SEPARATOR;
56         public static final char JEM_PACKAGEFRAGMENT= '<';
57         public static final char JEM_FIELD= '^';
58         public static final char JEM_METHOD= '~';
59         public static final char JEM_INITIALIZER= '|';
60         public static final char JEM_COMPILATIONUNIT= '{';
61         public static final char JEM_CLASSFILE= '(';
62         public static final char JEM_TYPE= '[';
63         public static final char JEM_PACKAGEDECLARATION= '%';
64         public static final char JEM_IMPORTDECLARATION= '#';
65
66         /**
67          * A count to uniquely identify this element in the case
68          * that a duplicate named element exists. For example, if
69          * there are two fields in a compilation unit with the
70          * same name, the occurrence count is used to distinguish
71          * them.  The occurrence count starts at 1 (thus the first 
72          * occurrence is occurrence 1, not occurrence 0).
73          */
74         protected int occurrenceCount = 1;
75
76
77         /**
78          * This element's type - one of the constants defined
79          * in IJavaLanguageElementTypes.
80          */
81         //protected int fLEType = 0;
82
83         /**
84          * This element's parent, or <code>null</code> if this
85          * element does not have a parent.
86          */
87         protected IJavaElement parent;
88
89         /**
90          * This element's name, or an empty <code>String</code> if this
91          * element does not have a name.
92          */
93         protected String name;
94
95         protected static final Object NO_INFO = new Object();
96         
97         /**
98          * Constructs a handle for a java element with
99          * the given parent element and name.
100          *
101          * @param parent The parent of java element
102          * @param name The name of java element
103          *
104          * @exception IllegalArgumentException if the type is not one of the valid
105          *              Java element type constants
106          *
107          */
108         protected JavaElement(JavaElement parent, String name) throws IllegalArgumentException {
109                 this.parent = parent;
110                 this.name = name;
111         }
112         /**
113          * @see IOpenable
114          */
115         public void close() throws JavaModelException {
116                 JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
117         }
118         /**
119          * This element is being closed.  Do any necessary cleanup.
120          */
121         protected abstract void closing(Object info) throws JavaModelException;
122         /*
123          * Returns a new element info for this element.
124          */
125         protected abstract Object createElementInfo();
126         /**
127          * Returns true if this handle represents the same Java element
128          * as the given handle. By default, two handles represent the same
129          * element if they are identical or if they represent the same type
130          * of element, have equal names, parents, and occurrence counts.
131          *
132          * <p>If a subclass has other requirements for equality, this method
133          * must be overridden.
134          *
135          * @see Object#equals
136          */
137         public boolean equals(Object o) {
138                 
139                 if (this == o) return true;
140         
141                 // Java model parent is null
142                 if (this.parent == null) return super.equals(o);
143         
144                 // assume instanceof check is done in subclass
145                 JavaElement other = (JavaElement) o;            
146                 return this.occurrenceCount == other.occurrenceCount &&
147                                 this.name.equals(other.name) &&
148                                 this.parent.equals(other.parent);
149         }
150         /**
151          * Returns true if this <code>JavaElement</code> is equivalent to the given
152          * <code>IDOMNode</code>.
153          */
154         protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
155                 return false;
156         }
157         /**
158          * @see IJavaElement
159          */
160         public boolean exists() {
161                 
162                 try {
163                         getElementInfo();
164                         return true;
165                 } catch (JavaModelException e) {
166                 }
167                 return false;
168         }
169         
170         /**
171          * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
172          * or <code>null</code> if there is no corresponding node.
173          */
174         public IDOMNode findNode(IDOMCompilationUnit dom) {
175                 int type = getElementType();
176                 if (type == IJavaElement.COMPILATION_UNIT || 
177                         type == IJavaElement.FIELD || 
178                         type == IJavaElement.IMPORT_DECLARATION || 
179                         type == IJavaElement.INITIALIZER || 
180                         type == IJavaElement.METHOD || 
181                         type == IJavaElement.PACKAGE_DECLARATION || 
182                         type == IJavaElement.TYPE) {
183                         ArrayList path = new ArrayList();
184                         IJavaElement element = this;
185                         while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
186                                 if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
187                                         // the DOM does not have import containers, so skip them
188                                         path.add(0, element);
189                                 }
190                                 element = element.getParent();
191                         }
192                         if (path.size() == 0) {
193                                 try {
194                                         if (equalsDOMNode(dom)) {
195                                                 return dom;
196                                         } else {
197                                                 return null;
198                                         }
199                                 } catch(JavaModelException e) {
200                                         return null;
201                                 }
202                         }
203                         return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild());
204                 } else {
205                         return null;
206                 }
207         }
208         /**
209          */
210         protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
211         
212                 try {
213                         if (equalsDOMNode(node)) {
214                                 if (position == (path.size() - 1)) {
215                                         return node;
216                                 } else {
217                                         if (node.getFirstChild() != null) {
218                                                 position++;
219                                                 return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild());
220                                         } else {
221                                                 return null;
222                                         }
223                                 }
224                         } else if (node.getNextNode() != null) {
225                                 return followPath(path, position, node.getNextNode());
226                         } else {
227                                 return null;
228                         }
229                 } catch (JavaModelException e) {
230                         return null;
231                 }
232         
233         }
234         /**
235          * @see IJavaElement
236          */
237         public IJavaElement getAncestor(int ancestorType) {
238                 
239                 IJavaElement element = this;
240                 while (element != null) {
241                         if (element.getElementType() == ancestorType)  return element;
242                         element= element.getParent();
243                 }
244                 return null;                            
245         }
246         /**
247          * Generates the element infos for this element, its ancestors (if they are not opened) and its children (if it is an Openable).
248          * Puts the newly created element info in the given map.
249          */
250         protected abstract void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException;
251         
252         /**
253          * @see IParent 
254          */
255         public IJavaElement[] getChildren() throws JavaModelException {
256                 return ((JavaElementInfo)getElementInfo()).getChildren();
257         }
258         /**
259          * Returns a collection of (immediate) children of this node of the
260          * specified type.
261          *
262          * @param type - one of constants defined by IJavaLanguageElementTypes
263          */
264         public ArrayList getChildrenOfType(int type) throws JavaModelException {
265                 IJavaElement[] children = getChildren();
266                 int size = children.length;
267                 ArrayList list = new ArrayList(size);
268                 for (int i = 0; i < size; ++i) {
269                         JavaElement elt = (JavaElement)children[i];
270                         if (elt.getElementType() == type) {
271                                 list.add(elt);
272                         }
273                 }
274                 return list;
275         }
276         /**
277          * @see IMember
278          */
279 //      public IClassFile getClassFile() {
280 //              return null;
281 //      }
282         /**
283          * @see IMember
284          */
285         public ICompilationUnit getCompilationUnit() {
286                 return null;
287         }
288         /**
289          * Returns the info for this handle.  
290          * If this element is not already open, it and all of its parents are opened.
291          * Does not return null.
292          * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
293          * @exception JavaModelException if the element is not present or not accessible
294          */
295         public Object getElementInfo() throws JavaModelException {
296                 return getElementInfo(null);
297         }
298         /**
299          * Returns the info for this handle.  
300          * If this element is not already open, it and all of its parents are opened.
301          * Does not return null.
302          * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
303          * @exception JavaModelException if the element is not present or not accessible
304          */
305         public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
306
307                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
308                 Object info = manager.getInfo(this);
309                 if (info != null) return info;
310                 return openWhenClosed(createElementInfo(), monitor);
311         }
312         /**
313          * @see IAdaptable
314          */
315         public String getElementName() {
316                 return name;
317         }
318
319         /**
320          * @see IJavaElement
321          */
322         public String getHandleIdentifier() {
323                 return getHandleMemento();
324         }
325         /**
326          * @see JavaElement#getHandleMemento()
327          */
328         public String getHandleMemento(){
329                 StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
330                 buff.append(getHandleMementoDelimiter());
331                 buff.append(getElementName());
332                 return buff.toString();
333         }
334         /**
335          * Returns the <code>char</code> that marks the start of this handles
336          * contribution to a memento.
337          */
338         protected abstract char getHandleMementoDelimiter();
339         /**
340          * @see IJavaElement
341          */
342         public IJavaModel getJavaModel() {
343                 IJavaElement current = this;
344                 do {
345                         if (current instanceof IJavaModel) return (IJavaModel) current;
346                 } while ((current = current.getParent()) != null);
347                 return null;
348         }
349
350         /**
351          * @see IJavaElement
352          */
353         public IJavaProject getJavaProject() {
354                 IJavaElement current = this;
355                 do {
356                         if (current instanceof IJavaProject) return (IJavaProject) current;
357                 } while ((current = current.getParent()) != null);
358                 return null;
359         }
360         /**
361          * Returns the occurrence count of the handle.
362          */
363         protected int getOccurrenceCount() {
364                 return occurrenceCount;
365         }
366         /*
367          * @see IJavaElement
368          */
369         public IOpenable getOpenable() {
370                 return this.getOpenableParent();        
371         }
372         /**
373          * Return the first instance of IOpenable in the parent
374          * hierarchy of this element.
375          *
376          * <p>Subclasses that are not IOpenable's must override this method.
377          */
378         public IOpenable getOpenableParent() {
379                 
380                 return (IOpenable)parent;
381         }
382         /**
383          * @see IJavaElement
384          */
385         public IJavaElement getParent() {
386                 return parent;
387         }
388         
389         /*
390          * @see IJavaElement#getPrimaryElement()
391          */
392         public IJavaElement getPrimaryElement() {
393                 return getPrimaryElement(true);
394         }
395         /*
396          * Returns the primary element. If checkOwner, and the cu owner is primary,
397          * return this element.
398          */
399         public IJavaElement getPrimaryElement(boolean checkOwner) {
400                 return this;
401         }
402         /**
403          * Returns the element that is located at the given source position
404          * in this element.  This is a helper method for <code>ICompilationUnit#getElementAt</code>,
405          * and only works on compilation units and types. The position given is
406          * known to be within this element's source range already, and if no finer
407          * grained element is found at the position, this element is returned.
408          */
409         protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
410                 if (this instanceof ISourceReference) {
411                         IJavaElement[] children = getChildren();
412                         int i;
413                         for (i = 0; i < children.length; i++) {
414                                 IJavaElement aChild = children[i];
415                                 if (aChild instanceof SourceRefElement) {
416                                         SourceRefElement child = (SourceRefElement) children[i];
417                                         ISourceRange range = child.getSourceRange();
418                                         if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
419                                                 if (child instanceof IParent) {
420                                                         return child.getSourceElementAt(position);
421                                                 } else {
422                                                         return child;
423                                                 }
424                                         }
425                                 }
426                         }
427                 } else {
428                         // should not happen
429                         Assert.isTrue(false);
430                 }
431                 return this;
432         }
433         /**
434          * Returns the SourceMapper facility for this element, or
435          * <code>null</code> if this element does not have a
436          * SourceMapper.
437          */
438 //      public SourceMapper getSourceMapper() {
439 //              return ((JavaElement)getParent()).getSourceMapper();
440 //      }
441         /* (non-Javadoc)
442          * @see org.eclipse.jdt.core.IJavaElement#getSchedulingRule()
443          */
444         public ISchedulingRule getSchedulingRule() {
445                 IResource resource = getResource();
446                 if (resource == null) {
447                         class NoResourceSchedulingRule implements ISchedulingRule {
448                                 public IPath path;
449                                 public NoResourceSchedulingRule(IPath path) {
450                                         this.path = path;
451                                 }
452                                 public boolean contains(ISchedulingRule rule) {
453                                         if (rule instanceof NoResourceSchedulingRule) {
454                                                 return this.path.isPrefixOf(((NoResourceSchedulingRule)rule).path);
455                                         } else {
456                                                 return false;
457                                         }
458                                 }
459                                 public boolean isConflicting(ISchedulingRule rule) {
460                                         if (rule instanceof NoResourceSchedulingRule) {
461                                                 IPath otherPath = ((NoResourceSchedulingRule)rule).path;
462                                                 return this.path.isPrefixOf(otherPath) || otherPath.isPrefixOf(this.path);
463                                         } else {
464                                                 return false;
465                                         }
466                                 }
467                         }
468                         return new NoResourceSchedulingRule(getPath());
469                 } else {
470                         return resource;
471                 }
472         }
473         /**
474          * @see IParent 
475          */
476         public boolean hasChildren() throws JavaModelException {
477                 // if I am not open, return true to avoid opening (case of a Java project, a compilation unit or a class file).
478                 // also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
479                 Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(this);
480                 if (elementInfo instanceof JavaElementInfo) {
481                         return ((JavaElementInfo)elementInfo).getChildren().length > 0;
482                 } else {
483                         return true;
484                 }
485         }
486
487         /**
488          * Returns the hash code for this Java element. By default,
489          * the hash code for an element is a combination of its name
490          * and parent's hash code. Elements with other requirements must
491          * override this method.
492          */
493         public int hashCode() {
494                 if (this.parent == null) return super.hashCode();
495                 return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
496         }
497         
498         /**
499          * Returns true if this element is an ancestor of the given element,
500          * otherwise false.
501          */
502         protected boolean isAncestorOf(IJavaElement e) {
503                 IJavaElement parent= e.getParent();
504                 while (parent != null && !parent.equals(this)) {
505                         parent= parent.getParent();
506                 }
507                 return parent != null;
508         }
509         
510         /**
511          * @see IJavaElement
512          */
513         public boolean isReadOnly() {
514                 return false;
515         }
516         /**
517          * @see IJavaElement
518          */
519         public boolean isStructureKnown() throws JavaModelException {
520                 return ((JavaElementInfo)getElementInfo()).isStructureKnown();
521         }
522         /**
523          * Creates and returns and not present exception for this element.
524          */
525         protected JavaModelException newNotPresentException() {
526                 return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
527         }
528         /**
529          * Opens this element and all parents that are not already open.
530          *
531          * @exception JavaModelException this element is not present or accessible
532          */
533 //      protected void openHierarchy() throws JavaModelException {
534 //              if (this instanceof IOpenable) {
535 //                      ((Openable) this).openWhenClosed(null);
536 //              } else {
537 //                      Openable openableParent = (Openable)getOpenableParent();
538 //                      if (openableParent != null) {
539 //                              JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
540 //                              if (openableParentInfo == null) {
541 //                                      openableParent.openWhenClosed(null);
542 //                              } else {
543 //                                      throw newNotPresentException();
544 //                              }
545 //                      }
546 //              }
547 //      }
548         /**
549          * This element has just been opened.  Do any necessary setup.
550          */
551         protected void opening(Object info) {
552         }
553         /*
554          * Opens an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
555          * Returns the created element info.
556          */
557         protected Object openWhenClosed(Object info, IProgressMonitor monitor) throws JavaModelException {
558                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
559                 boolean hadTemporaryCache = manager.hasTemporaryCache();
560                 try {
561                         HashMap newElements = manager.getTemporaryCache();
562                         generateInfos(info, newElements, monitor);
563                         if (info == null) {
564                                 info = newElements.get(this);
565                         }
566                         if (info == null) { // a source ref element could not be opened
567                                 // close any buffer that was opened for the openable parent
568                                 Iterator iterator = newElements.keySet().iterator();
569                                 while (iterator.hasNext()) {
570                                         IJavaElement element = (IJavaElement)iterator.next();
571                                         if (element instanceof Openable) {
572                                                 ((Openable)element).closeBuffer();
573                                         }
574                                 }
575                                 throw newNotPresentException();
576                         }
577                         if (!hadTemporaryCache) {
578                                 manager.putInfos(this, newElements);
579                         }
580                 } finally {
581                         if (!hadTemporaryCache) {
582                                 manager.resetTemporaryCache();
583                         }
584                 }
585                 return info;
586         }
587         /**
588          */
589         public String readableName() {
590                 return this.getElementName();
591         }
592         /**
593          * Removes all cached info from the Java Model, including all children,
594          * but does not close this element.
595          */
596 //      protected void removeInfo() {
597 //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
598 //              if (info != null) {
599 //                      if (this instanceof IParent) {
600 //                              IJavaElement[] children = ((JavaElementInfo)info).getChildren();
601 //                              for (int i = 0, size = children.length; i < size; ++i) {
602 //                                      JavaElement child = (JavaElement) children[i];
603 //                                      child.removeInfo();
604 //                              }
605 //                      }
606 //                      JavaModelManager.getJavaModelManager().removeInfo(this);
607 //              }
608 //      }
609 //      /**
610 //       * Returns a copy of this element rooted at the given project.
611 //       */
612 //      public abstract IJavaElement rootedAt(IJavaProject project);
613         /**
614          * Runs a Java Model Operation
615          */
616         public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
617                 try {
618                         if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
619                                 operation.run(monitor);
620                         } else {
621                                 // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
622                                 ResourcesPlugin.getWorkspace().run(operation, monitor);
623                         }
624                 } catch (CoreException ce) {
625                         if (ce instanceof JavaModelException) {
626                                 throw (JavaModelException)ce;
627                         } else {
628                                 if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
629                                         Throwable e= ce.getStatus().getException();
630                                         if (e instanceof JavaModelException) {
631                                                 throw (JavaModelException) e;
632                                         }
633                                 }
634                                 throw new JavaModelException(ce);
635                         }
636                 }
637         }
638         /**
639          * Sets the occurrence count of the handle.
640          */
641         protected void setOccurrenceCount(int count) {
642                 occurrenceCount = count;
643         }
644         protected String tabString(int tab) {
645                 StringBuffer buffer = new StringBuffer();
646                 for (int i = tab; i > 0; i--)
647                         buffer.append("  "); //$NON-NLS-1$
648                 return buffer.toString();
649         }
650         /**
651          * Debugging purposes
652          */
653         public String toDebugString() {
654                 StringBuffer buffer = new StringBuffer();
655                 this.toStringInfo(0, buffer, NO_INFO);
656                 return buffer.toString();
657         }
658         /**
659          *  Debugging purposes
660          */
661         public String toString() {
662                 StringBuffer buffer = new StringBuffer();
663                 toString(0, buffer);
664                 return buffer.toString();
665         }
666         /**
667          *  Debugging purposes
668          */
669         protected void toString(int tab, StringBuffer buffer) {
670         //      Object info = this.toStringInfo(tab, buffer);
671                 Object info = null;
672                 if (tab == 0) {
673                         this.toStringAncestors(buffer);
674                 }
675                 this.toStringChildren(tab, buffer, info);
676         }
677         /**
678          *  Debugging purposes
679          */
680         public String toStringWithAncestors() {
681                 StringBuffer buffer = new StringBuffer();
682                 this.toStringInfo(0, buffer, NO_INFO);
683                 this.toStringAncestors(buffer);
684                 return buffer.toString();
685         }
686         /**
687          *  Debugging purposes
688          */
689         protected void toStringAncestors(StringBuffer buffer) {
690                 JavaElement parent = (JavaElement)this.getParent();
691                 if (parent != null && parent.getParent() != null) {
692                         buffer.append(" [in "); //$NON-NLS-1$
693                         parent.toStringInfo(0, buffer, NO_INFO);
694                         parent.toStringAncestors(buffer);
695                         buffer.append("]"); //$NON-NLS-1$
696                 }
697         }
698         /**
699          *  Debugging purposes
700          */
701         protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
702                 if (info == null || !(info instanceof JavaElementInfo)) return;
703                 IJavaElement[] children = ((JavaElementInfo)info).getChildren();
704                 for (int i = 0; i < children.length; i++) {
705                         buffer.append("\n"); //$NON-NLS-1$
706                         ((JavaElement)children[i]).toString(tab + 1, buffer);
707                 }
708         }
709         /**
710          *  Debugging purposes
711          */
712 //      public Object toStringInfo(int tab, StringBuffer buffer) {
713 //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
714 //              this.toStringInfo(tab, buffer, info);
715 //              return info;
716 //      }
717         /**
718          *  Debugging purposes
719          */
720         protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
721                 buffer.append(this.tabString(tab));
722                 buffer.append(getElementName());
723                 if (info == null) {
724                         buffer.append(" (not open)"); //$NON-NLS-1$
725                 }
726         }
727 }