Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 311734
Collapse All | Expand All

(-)PHPDocumentationHoverStyleSheet.css (+34 lines)
Added Link Here
1
/* Font definitions */
2
html         { font-family: sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; }
3
body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt { font-size: 1em; }
4
pre          { font-family: monospace; }
5
6
/* Margins */
7
body	     { overflow: auto; margin-top: 0px; margin-bottom: 0.5em; margin-left: 0.3em; margin-right: 0px; }
8
h1           { margin-top: 0.3em; margin-bottom: 0.04em; }	
9
h2           { margin-top: 2em; margin-bottom: 0.25em; }
10
h3           { margin-top: 1.7em; margin-bottom: 0.25em; }
11
h4           { margin-top: 2em; margin-bottom: 0.3em; }
12
h5           { margin-top: 0px; margin-bottom: 0px; }
13
p            { margin-top: 1em; margin-bottom: 1em; }
14
pre          { margin-left: 0.6em; }
15
ul	         { margin-top: 0px; margin-bottom: 1em; }
16
li	         { margin-top: 0px; margin-bottom: 0px; } 
17
li p	     { margin-top: 0px; margin-bottom: 0px; } 
18
ol	         { margin-top: 0px; margin-bottom: 1em; }
19
dl	         { margin-top: 0px; margin-bottom: 1em; }
20
dt	         { margin-top: 0px; margin-bottom: 0px; font-weight: bold; }
21
dd	         { margin-top: 0px; margin-bottom: 0px; }
22
23
/* Styles and colors */
24
a:link	     { color: #0000FF; }
25
a:hover	     { color: #000080; }
26
a:visited    { text-decoration: underline; }
27
a.header:link    { text-decoration: none; color: InfoText }
28
a.header:visited { text-decoration: none; color: InfoText }
29
a.header:hover   { text-decoration: underline; color: #000080; }
30
h4           { font-style: italic; }
31
strong	     { font-weight: bold; }
32
em	         { font-style: italic; }
33
var	         { font-style: italic; }
34
th	         { font-weight: bold; }
(-)build.properties (+1 lines)
Lines 15-20 Link Here
15
               .,\
15
               .,\
16
               icons/,\
16
               icons/,\
17
               plugin.properties,\
17
               plugin.properties,\
18
               PHPDocumentationHoverStyleSheet.css,\
18
               templates/,\
19
               templates/,\
19
               META-INF/,\
20
               META-INF/,\
20
               about.html,\
21
               about.html,\
(-)src/org/eclipse/php/internal/ui/PHPUiPlugin.java (-3 / +19 lines)
Lines 45-50 Link Here
45
import org.eclipse.php.internal.ui.util.ImageDescriptorRegistry;
45
import org.eclipse.php.internal.ui.util.ImageDescriptorRegistry;
46
import org.eclipse.php.internal.ui.util.PHPManualSiteDescriptor;
46
import org.eclipse.php.internal.ui.util.PHPManualSiteDescriptor;
47
import org.eclipse.php.internal.ui.util.ProblemMarkerManager;
47
import org.eclipse.php.internal.ui.util.ProblemMarkerManager;
48
import org.eclipse.php.internal.ui.viewsupport.ImagesOnFileSystemRegistry;
48
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.ui.*;
50
import org.eclipse.ui.*;
50
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
51
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
Lines 95-100 Link Here
95
	private PHPFoldingStructureProviderRegistry fFoldingStructureProviderRegistry;
96
	private PHPFoldingStructureProviderRegistry fFoldingStructureProviderRegistry;
96
	private PHPEditorTextHoverDescriptor[] fPHPEditorTextHoverDescriptors;
97
	private PHPEditorTextHoverDescriptor[] fPHPEditorTextHoverDescriptors;
97
	private PHPManualSiteDescriptor[] fPHPManualSiteDescriptors;
98
	private PHPManualSiteDescriptor[] fPHPManualSiteDescriptors;
99
	private ImagesOnFileSystemRegistry fImagesOnFSRegistry;
98
100
99
	/**
101
	/**
100
	 * The AST provider.
102
	 * The AST provider.
Lines 143-151 Link Here
143
145
144
				if (PlatformUI.isWorkbenchRunning()) {
146
				if (PlatformUI.isWorkbenchRunning()) {
145
					new InitializeAfterLoadJob().schedule(); // must be last
147
					new InitializeAfterLoadJob().schedule(); // must be last
146
																// call in
148
					// call in
147
																// start()
149
					// start()
148
																// method
150
					// method
149
				}
151
				}
150
				return Status.OK_STATUS;
152
				return Status.OK_STATUS;
151
			}
153
			}
Lines 538-541 Link Here
538
		}
540
		}
539
		return fActiveFormatter;
541
		return fActiveFormatter;
540
	}
542
	}
543
544
	/**
545
	 * Returns the image registry that keeps its images on the local file
546
	 * system.
547
	 * 
548
	 * @return the image registry
549
	 */
550
	public ImagesOnFileSystemRegistry getImagesOnFSRegistry() {
551
		if (fImagesOnFSRegistry == null) {
552
			fImagesOnFSRegistry = new ImagesOnFileSystemRegistry();
553
		}
554
		return fImagesOnFSRegistry;
555
	}
556
541
}
557
}
(-)src/org/eclipse/php/internal/ui/documentation/PHPDocumentationContentAccess.java (+1297 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.documentation;
2
3
import java.text.MessageFormat;
4
import java.util.*;
5
6
import org.eclipse.dltk.ast.references.SimpleReference;
7
import org.eclipse.dltk.ast.references.TypeReference;
8
import org.eclipse.dltk.ast.references.VariableReference;
9
import org.eclipse.dltk.core.*;
10
import org.eclipse.dltk.internal.core.util.MethodOverrideTester;
11
import org.eclipse.dltk.ui.ScriptElementLabels;
12
import org.eclipse.php.core.compiler.PHPFlags;
13
import org.eclipse.php.internal.core.ast.nodes.Identifier;
14
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocBlock;
15
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocTag;
16
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
17
import org.eclipse.php.internal.ui.PHPUiPlugin;
18
import org.eclipse.php.internal.ui.corext.util.SuperTypeHierarchyCache;
19
20
/**
21
 * Helper to get the content of a Javadoc comment as HTML.
22
 * 
23
 * <p>
24
 * <strong>This is work in progress. Parts of this will later become API through
25
 * {@link JavadocContentAccess}</strong>
26
 * </p>
27
 * 
28
 * @since 3.4
29
 */
30
@SuppressWarnings({ "restriction", "unchecked", "rawtypes" })
31
public class PHPDocumentationContentAccess {
32
33
	private static final String BLOCK_TAG_START = "<dl>"; //$NON-NLS-1$
34
	private static final String BLOCK_TAG_END = "</dl>"; //$NON-NLS-1$
35
36
	private static final String BlOCK_TAG_ENTRY_START = "<dd>"; //$NON-NLS-1$
37
	private static final String BlOCK_TAG_ENTRY_END = "</dd>"; //$NON-NLS-1$
38
39
	private static final String PARAM_NAME_START = "<b>"; //$NON-NLS-1$
40
	private static final String PARAM_NAME_END = "</b> "; //$NON-NLS-1$
41
	private static final int PARAMETER_TYPE_TYPE = 1;
42
	private static final int PARAMETER_NAME_TYPE = 2;
43
	private static final int PARAMETER_DESCRIPTION_TYPE = 3;
44
45
	/**
46
	 * Implements the "Algorithm for Inheriting Method Comments" as specified
47
	 * for <a href=
48
	 * "http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.html#inheritingcomments"
49
	 * >1.4.2</a>, <a href=
50
	 * "http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javadoc.html#inheritingcomments"
51
	 * >1.5</a>, and <a href=
52
	 * "http://java.sun.com/javase/6/docs/technotes/tools/windows/javadoc.html#inheritingcomments"
53
	 * >1.6</a>.
54
	 * 
55
	 * <p>
56
	 * Unfortunately, the implementation is broken in Javadoc implementations
57
	 * since 1.5, see <a
58
	 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6376959">Sun's
59
	 * bug</a>.
60
	 * </p>
61
	 * 
62
	 * <p>
63
	 * We adhere to the spec.
64
	 * </p>
65
	 */
66
	private static abstract class InheritDocVisitor {
67
		public static final Object STOP_BRANCH = new Object() {
68
			public String toString() {
69
				return "STOP_BRANCH";} //$NON-NLS-1$
70
		};
71
		public static final Object CONTINUE = new Object() {
72
			public String toString() {
73
				return "CONTINUE";} //$NON-NLS-1$
74
		};
75
76
		/**
77
		 * Visits a type and decides how the visitor should proceed.
78
		 * 
79
		 * @param currType
80
		 *            the current type
81
		 * @return <ul>
82
		 *         <li>{@link #STOP_BRANCH} to indicate that no Javadoc has been
83
		 *         found and visiting super types should stop here</li>
84
		 *         <li>{@link #CONTINUE} to indicate that no Javadoc has been
85
		 *         found and visiting super types should continue</li>
86
		 *         <li>an {@link Object} or <code>null</code>, to indicate that
87
		 *         visiting should be cancelled immediately. The returned value
88
		 *         is the result of
89
		 *         {@link #visitInheritDoc(IType, ITypeHierarchy)}</li>
90
		 *         </ul>
91
		 * @throws ModelException
92
		 *             unexpected problem
93
		 * @see #visitInheritDoc(IType, ITypeHierarchy)
94
		 */
95
		public abstract Object visit(IType currType) throws ModelException;
96
97
		/**
98
		 * Visits the super types of the given <code>currentType</code>.
99
		 * 
100
		 * @param currentType
101
		 *            the starting type
102
		 * @param typeHierarchy
103
		 *            a super type hierarchy that contains
104
		 *            <code>currentType</code>
105
		 * @return the result from a call to {@link #visit(IType)}, or
106
		 *         <code>null</code> if none of the calls returned a result
107
		 * @throws ModelException
108
		 *             unexpected problem
109
		 */
110
		public Object visitInheritDoc(IType currentType,
111
				ITypeHierarchy typeHierarchy) throws ModelException {
112
			ArrayList visited = new ArrayList();
113
			visited.add(currentType);
114
			// Object result = visitInheritDocInterfaces(visited, currentType,
115
			// typeHierarchy);
116
			// if (result != InheritDocVisitor.CONTINUE)
117
			// return result;
118
			Object result;
119
			IType[] superClasses = typeHierarchy.getSuperclass(currentType);
120
			for (IType superClass : superClasses) {
121
				while (superClass != null && !visited.contains(superClass)) {
122
					result = visit(superClass);
123
					if (result == InheritDocVisitor.STOP_BRANCH) {
124
						return null;
125
					} else if (result == InheritDocVisitor.CONTINUE) {
126
						visited.add(superClass);
127
						result = visitInheritDocInterfaces(visited, superClass,
128
								typeHierarchy);
129
						if (result != InheritDocVisitor.CONTINUE)
130
							return result;
131
						else
132
							superClasses = typeHierarchy
133
									.getSuperclass(superClass);
134
					} else {
135
						return result;
136
					}
137
				}
138
			}
139
			return null;
140
		}
141
142
		/**
143
		 * Visits the super interfaces of the given type in the given hierarchy,
144
		 * thereby skipping already visited types.
145
		 * 
146
		 * @param visited
147
		 *            set of visited types
148
		 * @param currentType
149
		 *            type whose super interfaces should be visited
150
		 * @param typeHierarchy
151
		 *            type hierarchy (must include <code>currentType</code>)
152
		 * @return the result, or {@link #CONTINUE} if no result has been found
153
		 * @throws ModelException
154
		 *             unexpected problem
155
		 */
156
		private Object visitInheritDocInterfaces(ArrayList visited,
157
				IType currentType, ITypeHierarchy typeHierarchy)
158
				throws ModelException {
159
			ArrayList toVisitChildren = new ArrayList();
160
			IType[] superInterfaces = typeHierarchy.getSuperclass(currentType);
161
			for (int i = 0; i < superInterfaces.length; i++) {
162
				IType superInterface = superInterfaces[i];
163
				if (visited.contains(superInterface))
164
					continue;
165
				visited.add(superInterface);
166
				Object result = visit(superInterface);
167
				if (result == InheritDocVisitor.STOP_BRANCH) {
168
					// skip
169
				} else if (result == InheritDocVisitor.CONTINUE) {
170
					toVisitChildren.add(superInterface);
171
				} else {
172
					return result;
173
				}
174
			}
175
			for (Iterator iter = toVisitChildren.iterator(); iter.hasNext();) {
176
				IType child = (IType) iter.next();
177
				Object result = visitInheritDocInterfaces(visited, child,
178
						typeHierarchy);
179
				if (result != InheritDocVisitor.CONTINUE)
180
					return result;
181
			}
182
			return InheritDocVisitor.CONTINUE;
183
		}
184
	}
185
186
	private static class JavadocLookup {
187
		private static final JavadocLookup NONE = new JavadocLookup(null) {
188
			public CharSequence getInheritedMainDescription(IMethod method) {
189
				return null;
190
			}
191
192
			public CharSequence getInheritedParamDescription(IMethod method,
193
					int i) {
194
				return null;
195
			}
196
197
			public CharSequence getInheritedReturnDescription(IMethod method) {
198
				return null;
199
			}
200
201
			public CharSequence getInheritedExceptionDescription(
202
					IMethod method, String name) {
203
				return null;
204
			}
205
		};
206
207
		private static interface DescriptionGetter {
208
			/**
209
			 * Returns a Javadoc tag description or <code>null</code>.
210
			 * 
211
			 * @param contentAccess
212
			 *            the content access
213
			 * @return the description, or <code>null</code> if none
214
			 * @throws ModelException
215
			 *             unexpected problem
216
			 */
217
			CharSequence getDescription(
218
					PHPDocumentationContentAccess contentAccess)
219
					throws ModelException;
220
		}
221
222
		private final IType fStartingType;
223
		private final HashMap fContentAccesses;
224
225
		private ITypeHierarchy fTypeHierarchy;
226
		private MethodOverrideTester fOverrideTester;
227
228
		private JavadocLookup(IType startingType) {
229
			fStartingType = startingType;
230
			fContentAccesses = new HashMap();
231
		}
232
233
		/**
234
		 * For the given method, returns the main description from an overridden
235
		 * method.
236
		 * 
237
		 * @param method
238
		 *            a method
239
		 * @return the description that replaces the
240
		 *         <code>{&#64;inheritDoc}</code> tag, or <code>null</code> if
241
		 *         none could be found
242
		 */
243
		public CharSequence getInheritedMainDescription(IMethod method) {
244
			return getInheritedDescription(method, new DescriptionGetter() {
245
				public CharSequence getDescription(
246
						PHPDocumentationContentAccess contentAccess) {
247
					return contentAccess.getMainDescription();
248
				}
249
			});
250
		}
251
252
		/**
253
		 * For the given method, returns the @param tag description for the
254
		 * given parameter from an overridden method.
255
		 * 
256
		 * @param method
257
		 *            a method
258
		 * @param paramIndex
259
		 *            the index of the parameter
260
		 * @return the description that replaces the
261
		 *         <code>{&#64;inheritDoc}</code> tag, or <code>null</code> if
262
		 *         none could be found
263
		 */
264
		public CharSequence getInheritedParamDescription(IMethod method,
265
				final int paramIndex) {
266
			return getInheritedDescription(method, new DescriptionGetter() {
267
				public CharSequence getDescription(
268
						PHPDocumentationContentAccess contentAccess)
269
						throws ModelException {
270
					return contentAccess
271
							.getInheritedParamDescription(paramIndex);
272
				}
273
			});
274
		}
275
276
		/**
277
		 * For the given method, returns the @param tag description for the
278
		 * given parameter from an overridden method.
279
		 * 
280
		 * @param method
281
		 *            a method
282
		 * @param paramIndex
283
		 *            the index of the parameter
284
		 * @return the description that replaces the
285
		 *         <code>{&#64;inheritDoc}</code> tag, or <code>null</code> if
286
		 *         none could be found
287
		 */
288
		public CharSequence getInheritedParamType(IMethod method,
289
				final int paramIndex) {
290
			return getInheritedDescription(method, new DescriptionGetter() {
291
				public CharSequence getDescription(
292
						PHPDocumentationContentAccess contentAccess)
293
						throws ModelException {
294
					return contentAccess.getInheritedParamType(paramIndex);
295
				}
296
			});
297
		}
298
299
		/**
300
		 * For the given method, returns the @return tag description from an
301
		 * overridden method.
302
		 * 
303
		 * @param method
304
		 *            a method
305
		 * @return the description that replaces the
306
		 *         <code>{&#64;inheritDoc}</code> tag, or <code>null</code> if
307
		 *         none could be found
308
		 */
309
		public CharSequence getInheritedReturnDescription(IMethod method) {
310
			return getInheritedDescription(method, new DescriptionGetter() {
311
				public CharSequence getDescription(
312
						PHPDocumentationContentAccess contentAccess) {
313
					return contentAccess.getReturnDescription();
314
				}
315
			});
316
		}
317
318
		/**
319
		 * For the given method, returns the @throws/@exception tag description
320
		 * for the given exception from an overridden method.
321
		 * 
322
		 * @param method
323
		 *            a method
324
		 * @param simpleName
325
		 *            the simple name of an exception
326
		 * @return the description that replaces the
327
		 *         <code>{&#64;inheritDoc}</code> tag, or <code>null</code> if
328
		 *         none could be found
329
		 */
330
		public CharSequence getInheritedExceptionDescription(IMethod method,
331
				final String simpleName) {
332
			return getInheritedDescription(method, new DescriptionGetter() {
333
				public CharSequence getDescription(
334
						PHPDocumentationContentAccess contentAccess) {
335
					return contentAccess.getExceptionDescription(simpleName);
336
				}
337
			});
338
		}
339
340
		private CharSequence getInheritedDescription(final IMethod method,
341
				final DescriptionGetter descriptionGetter) {
342
			try {
343
				return (CharSequence) new InheritDocVisitor() {
344
					public Object visit(IType currType) throws ModelException {
345
						IMethod overridden = getOverrideTester()
346
								.findOverriddenMethodInType(currType, method);
347
						if (overridden == null)
348
							return InheritDocVisitor.CONTINUE;
349
350
						PHPDocumentationContentAccess contentAccess = getJavadocContentAccess(overridden);
351
						if (contentAccess == null) {
352
							// if (overridden.getOpenable().getBuffer() == null)
353
							// {
354
							// return InheritDocVisitor.CONTINUE;
355
							// } else {
356
							// return InheritDocVisitor.CONTINUE;
357
							// }
358
							return InheritDocVisitor.CONTINUE;
359
						}
360
361
						CharSequence overriddenDescription = descriptionGetter
362
								.getDescription(contentAccess);
363
						if (overriddenDescription != null)
364
							return overriddenDescription;
365
						else
366
							return InheritDocVisitor.CONTINUE;
367
					}
368
				}.visitInheritDoc(method.getDeclaringType(), getTypeHierarchy());
369
			} catch (ModelException e) {
370
				PHPUiPlugin.log(e);
371
			}
372
			return null;
373
		}
374
375
		/**
376
		 * @param method
377
		 *            the method
378
		 * @return the Javadoc content access for the given method, or
379
		 *         <code>null</code> if no Javadoc could be found in source
380
		 * @throws ModelException
381
		 *             unexpected problem
382
		 */
383
		private PHPDocumentationContentAccess getJavadocContentAccess(
384
				IMethod method) throws ModelException {
385
			Object cached = fContentAccesses.get(method);
386
			if (cached != null)
387
				return (PHPDocumentationContentAccess) cached;
388
			if (fContentAccesses.containsKey(method))
389
				return null;
390
391
			// IBuffer buf = method.getOpenable().getBuffer();
392
			// if (buf == null) { // no source attachment found
393
			// fContentAccesses.put(method, null);
394
			// return null;
395
			// }
396
397
			PHPDocBlock javadoc = PHPModelUtils.getDocBlock(method);
398
			if (javadoc == null) {
399
				fContentAccesses.put(method, null);
400
				return null;
401
			}
402
403
			PHPDocumentationContentAccess contentAccess = new PHPDocumentationContentAccess(
404
					method, javadoc, this);
405
			fContentAccesses.put(method, contentAccess);
406
			return contentAccess;
407
		}
408
409
		private ITypeHierarchy getTypeHierarchy() throws ModelException {
410
			if (fTypeHierarchy == null)
411
				fTypeHierarchy = SuperTypeHierarchyCache
412
						.getTypeHierarchy(fStartingType);
413
			return fTypeHierarchy;
414
		}
415
416
		private MethodOverrideTester getOverrideTester() throws ModelException {
417
			if (fOverrideTester == null)
418
				fOverrideTester = SuperTypeHierarchyCache
419
						.getMethodOverrideTester(fStartingType);
420
			return fOverrideTester;
421
		}
422
	}
423
424
	private final IMember fMember;
425
	/**
426
	 * The method, or <code>null</code> if {@link #fMember} is not a method
427
	 * where {@inheritDoc} could work.
428
	 */
429
	private final IMethod fMethod;
430
	private final PHPDocBlock fJavadoc;
431
	private final JavadocLookup fJavadocLookup;
432
433
	private StringBuffer fBuf;
434
	private StringBuffer fMainDescription;
435
	private StringBuffer fReturnDescription;
436
	private StringBuffer[] fParamDescriptions;
437
	private StringBuffer[] fParamTypes;
438
	private HashMap<String, StringBuffer> fExceptionDescriptions;
439
440
	private PHPDocumentationContentAccess(IMethod method, PHPDocBlock javadoc,
441
			JavadocLookup lookup) {
442
		fMember = method;
443
		fMethod = method;
444
		fJavadoc = javadoc;
445
		fJavadocLookup = lookup;
446
	}
447
448
	private PHPDocumentationContentAccess(IMember member, PHPDocBlock javadoc) {
449
		fMember = member;
450
		fMethod = null;
451
		fJavadoc = javadoc;
452
		fJavadocLookup = JavadocLookup.NONE;
453
	}
454
455
	/**
456
	 * Gets an IMember's Javadoc comment content from the source or Javadoc
457
	 * attachment and renders the tags and links in HTML. Returns
458
	 * <code>null</code> if the member does not contain a Javadoc comment or if
459
	 * no source is available.
460
	 * 
461
	 * @param member
462
	 *            the member to get the Javadoc of
463
	 * @param useAttachedJavadoc
464
	 *            if <code>true</code> Javadoc will be extracted from attached
465
	 *            Javadoc if there's no source
466
	 * @return the Javadoc comment content in HTML or <code>null</code> if the
467
	 *         member does not have a Javadoc comment or if no source is
468
	 *         available
469
	 * @throws ModelException
470
	 *             is thrown when the element's Javadoc can not be accessed
471
	 */
472
	public static String getHTMLContent(IMember member) throws ModelException {
473
		return getHTMLContentFromSource(member);
474
	}
475
476
	private static StringBuffer createSuperMethodReferences(final IMethod method)
477
			throws ModelException {
478
		IType type = method.getDeclaringType();
479
		ITypeHierarchy hierarchy = SuperTypeHierarchyCache
480
				.getTypeHierarchy(type);
481
		final MethodOverrideTester tester = SuperTypeHierarchyCache
482
				.getMethodOverrideTester(type);
483
484
		final ArrayList<IMethod> superInterfaceMethods = new ArrayList<IMethod>();
485
		final IMethod[] superClassMethod = { null };
486
		new InheritDocVisitor() {
487
			public Object visit(IType currType) throws ModelException {
488
				IMethod overridden = tester.findOverriddenMethodInType(
489
						currType, method);
490
				if (overridden == null)
491
					return InheritDocVisitor.CONTINUE;
492
493
				if (PHPFlags.isInterface(currType.getFlags()))
494
					superInterfaceMethods.add(overridden);
495
				else
496
					superClassMethod[0] = overridden;
497
498
				return STOP_BRANCH;
499
			}
500
		}.visitInheritDoc(type, hierarchy);
501
502
		boolean hasSuperInterfaceMethods = superInterfaceMethods.size() != 0;
503
		if (!hasSuperInterfaceMethods && superClassMethod[0] == null)
504
			return null;
505
506
		StringBuffer buf = new StringBuffer();
507
		buf.append("<div>"); //$NON-NLS-1$
508
		if (hasSuperInterfaceMethods) {
509
			buf.append("<b>"); //$NON-NLS-1$
510
			buf.append(PHPDocumentationMessages.JavaDoc2HTMLTextReader_specified_by_section);
511
			buf.append("</b> "); //$NON-NLS-1$
512
			for (Iterator<IMethod> iter = superInterfaceMethods.iterator(); iter
513
					.hasNext();) {
514
				IMethod overridden = (IMethod) iter.next();
515
				buf.append(createMethodInTypeLinks(overridden));
516
				if (iter.hasNext())
517
					buf.append(ScriptElementLabels.COMMA_STRING);
518
			}
519
		}
520
		if (superClassMethod[0] != null) {
521
			if (hasSuperInterfaceMethods)
522
				buf.append(ScriptElementLabels.COMMA_STRING);
523
			buf.append("<b>"); //$NON-NLS-1$
524
			buf.append(PHPDocumentationMessages.JavaDoc2HTMLTextReader_overrides_section);
525
			buf.append("</b> "); //$NON-NLS-1$
526
			buf.append(createMethodInTypeLinks(superClassMethod[0]));
527
		}
528
		buf.append("</div>"); //$NON-NLS-1$
529
		return buf;
530
	}
531
532
	private static String createMethodInTypeLinks(IMethod overridden) {
533
		CharSequence methodLink = createSimpleMemberLink(overridden);
534
		CharSequence typeLink = createSimpleMemberLink(overridden
535
				.getDeclaringType());
536
		String methodInType = MessageFormat.format(
537
				PHPDocumentationMessages.JavaDoc2HTMLTextReader_method_in_type,
538
				new Object[] { methodLink, typeLink });
539
		return methodInType;
540
	}
541
542
	private static CharSequence createSimpleMemberLink(IMember member) {
543
		StringBuffer buf = new StringBuffer();
544
		buf.append("<a href='"); //$NON-NLS-1$
545
		// try {
546
		// String uri=
547
		// JavaElementLinks.createURI(JavaElementLinks.JAVADOC_SCHEME, member);
548
		// buf.append(uri);
549
		// } catch (URISyntaxException e) {
550
		// JavaPlugin.log(e);
551
		// }
552
		buf.append("'>"); //$NON-NLS-1$
553
		ScriptElementLabels.getDefault().getElementLabel(member, 0, buf);
554
		buf.append("</a>"); //$NON-NLS-1$
555
		return buf;
556
	}
557
558
	private static String getHTMLContentFromSource(IMember member)
559
			throws ModelException {
560
		return javadoc2HTML(member);
561
	}
562
563
	private static PHPDocBlock getJavadocNode(IMember member) {
564
		if (member instanceof IType) {
565
			return PHPModelUtils.getDocBlock((IType) member);
566
		}
567
		if (member instanceof IMethod) {
568
			return PHPModelUtils.getDocBlock((IMethod) member);
569
		}
570
		if (member instanceof IField) {
571
			return PHPModelUtils.getDocBlock((IField) member);
572
		}
573
		return null;
574
	}
575
576
	private static String javadoc2HTML(IMember member) {
577
		PHPDocBlock javadoc = getJavadocNode(member);
578
579
		if (javadoc == null) {
580
			javadoc = new PHPDocBlock(0, 0, null, new PHPDocTag[0]);
581
		}
582
		if (canInheritJavadoc(member)) {
583
			IMethod method = (IMethod) member;
584
			IType declaringType = method.getDeclaringType();
585
			JavadocLookup lookup;
586
			if (declaringType == null) {
587
				lookup = JavadocLookup.NONE;
588
			} else {
589
				lookup = new JavadocLookup(method.getDeclaringType());
590
			}
591
			return new PHPDocumentationContentAccess(method, javadoc, lookup)
592
					.toHTML();
593
		}
594
		return new PHPDocumentationContentAccess(member, javadoc).toHTML();
595
	}
596
597
	private static boolean canInheritJavadoc(IMember member) {
598
		if (member instanceof IMethod && member.getScriptProject().exists()) {
599
			/*
600
			 * Exists test catches ExternalJavaProject, in which case no
601
			 * hierarchy can be built.
602
			 */
603
			try {
604
				return !((IMethod) member).isConstructor();
605
			} catch (ModelException e) {
606
				PHPUiPlugin.log(e);
607
			}
608
		}
609
		return false;
610
	}
611
612
	private String toHTML() {
613
		fBuf = new StringBuffer();
614
615
		if (appendBuiltinDoc(fMember, fBuf)) {
616
			return fBuf.toString();
617
		}
618
619
		// After first loop, non-null entries in the following two lists are
620
		// missing and need to be inherited:
621
		List<String> parameterNames = initParameterNames();
622
		List<String> exceptionNames = new ArrayList<String>();
623
624
		PHPDocTag deprecatedTag = null;
625
		PHPDocTag returnTag = null;
626
		List<PHPDocTag> parameters = new ArrayList<PHPDocTag>();
627
		List<PHPDocTag> exceptions = new ArrayList<PHPDocTag>();
628
		List<PHPDocTag> versions = new ArrayList<PHPDocTag>();
629
		List<PHPDocTag> authors = new ArrayList<PHPDocTag>();
630
		List<PHPDocTag> sees = new ArrayList<PHPDocTag>();
631
		List<PHPDocTag> since = new ArrayList<PHPDocTag>();
632
		List<PHPDocTag> rest = new ArrayList<PHPDocTag>();
633
		String shortDescription = fJavadoc.getShortDescription();
634
		PHPDocTag[] tags = fJavadoc.getTags();
635
		for (PHPDocTag tag : tags) {
636
			if (PHPDocTag.PARAM == tag.getTagKind()) {
637
				parameters.add(tag);
638
				SimpleReference[] fragments = tag.getReferences();
639
				if (fragments.length == 0) {
640
					if (parameterNames.size() > parameters.indexOf(tag))
641
						parameterNames.set(parameters.indexOf(tag), null);
642
				}
643
				for (SimpleReference reference : fragments) {
644
					String name = reference.getName();
645
					if (reference instanceof TypeReference) {
646
						// parameterTypes.add(name);
647
					} else if (reference instanceof VariableReference) {
648
						int paramIndex = parameterNames.indexOf(name);
649
						if (paramIndex != -1) {
650
							parameterNames.set(paramIndex, null);
651
						}
652
					}
653
				}
654
			} else if (PHPDocTag.RETURN == tag.getTagKind()) {
655
				if (returnTag == null)
656
					returnTag = tag; // the Javadoc tool only shows the first
657
				// return tag
658
659
			} else if (PHPDocTag.THROWS == tag.getTagKind()) {
660
				exceptions.add(tag);
661
				SimpleReference[] fragments = tag.getReferences();
662
				if (fragments.length > 0) {
663
					Object first = fragments[0];
664
					if (first instanceof TypeReference) {
665
						exceptionNames.add(((TypeReference) first).getName());
666
					}
667
				}
668
669
			} else if (PHPDocTag.SINCE == tag.getTagKind()) {
670
				since.add(tag);
671
			} else if (PHPDocTag.VERSION == tag.getTagKind()) {
672
				versions.add(tag);
673
			} else if (PHPDocTag.AUTHOR == tag.getTagKind()) {
674
				authors.add(tag);
675
			} else if (PHPDocTag.SEE == tag.getTagKind()) {
676
				sees.add(tag);
677
			} else if (PHPDocTag.DEPRECATED == tag.getTagKind()) {
678
				if (deprecatedTag == null)
679
					deprecatedTag = tag; // the Javadoc tool only shows the
680
				// first deprecated tag
681
			} else {
682
				rest.add(tag);
683
			}
684
		}
685
686
		if (deprecatedTag != null)
687
			handleDeprecatedTag(deprecatedTag);
688
		if (shortDescription != null && shortDescription.length() > 0)
689
			fBuf.append(shortDescription);
690
		else if (fMethod != null) {
691
			CharSequence inherited = fJavadocLookup
692
					.getInheritedMainDescription(fMethod);
693
			handleInherited(inherited);
694
		}
695
696
		CharSequence[] parameterDescriptions = new CharSequence[parameterNames
697
				.size()];
698
		CharSequence[] parameterTypes = new CharSequence[parameterNames.size()];
699
		boolean hasInheritedParameters = inheritParameterDescriptions(
700
				parameterNames, parameterDescriptions, parameterTypes);
701
		boolean hasParameters = parameters.size() > 0 || hasInheritedParameters;
702
703
		CharSequence returnDescription = null;
704
		if (returnTag == null)
705
			returnDescription = fJavadocLookup
706
					.getInheritedReturnDescription(fMethod);
707
		boolean hasReturnTag = returnTag != null || returnDescription != null;
708
709
		CharSequence[] exceptionDescriptions = new CharSequence[exceptionNames
710
				.size()];
711
		boolean hasInheritedExceptions = inheritExceptionDescriptions(
712
				exceptionNames, exceptionDescriptions);
713
		boolean hasExceptions = exceptions.size() > 0 || hasInheritedExceptions;
714
715
		if (hasParameters
716
				|| hasReturnTag
717
				|| hasExceptions
718
				|| versions.size() > 0
719
				|| authors.size() > 0
720
				|| since.size() > 0
721
				|| sees.size() > 0
722
				|| rest.size() > 0
723
				|| (fBuf.length() > 0 && (parameterDescriptions.length > 0 || exceptionDescriptions.length > 0))) {
724
			handleSuperMethodReferences();
725
			fBuf.append(BLOCK_TAG_START);
726
			handleParameterTags(parameters, parameterNames, parameterTypes,
727
					parameterDescriptions);
728
			handleReturnTag(returnTag, returnDescription);
729
			handleExceptionTags(exceptions, exceptionNames,
730
					exceptionDescriptions);
731
			handleBlockTags(
732
					PHPDocumentationMessages.JavaDoc2HTMLTextReader_since_section,
733
					since);
734
			handleBlockTags(
735
					PHPDocumentationMessages.JavaDoc2HTMLTextReader_version_section,
736
					versions);
737
			handleBlockTags(
738
					PHPDocumentationMessages.JavaDoc2HTMLTextReader_author_section,
739
					authors);
740
			handleBlockTags(
741
					PHPDocumentationMessages.JavaDoc2HTMLTextReader_see_section,
742
					sees);
743
			handleBlockTags(rest);
744
			fBuf.append(BLOCK_TAG_END);
745
746
		} else if (fBuf.length() > 0) {
747
			handleSuperMethodReferences();
748
		}
749
750
		String result = fBuf.toString();
751
		fBuf = null;
752
		return result;
753
	}
754
755
	private void handleDeprecatedTag(PHPDocTag tag) {
756
		fBuf.append("<p><b>"); //$NON-NLS-1$
757
		fBuf.append(PHPDocumentationMessages.JavaDoc2HTMLTextReader_deprecated_section);
758
		fBuf.append("</b> <i>"); //$NON-NLS-1$
759
		handleContentElements(tag);
760
		fBuf.append("</i><p>"); //$NON-NLS-1$
761
	}
762
763
	private void handleSuperMethodReferences() {
764
		if (fMethod != null && fMethod.getDeclaringType() != null) {
765
			try {
766
				StringBuffer superMethodReferences = createSuperMethodReferences(fMethod);
767
				if (superMethodReferences != null)
768
					fBuf.append(superMethodReferences);
769
			} catch (ModelException e) {
770
				PHPUiPlugin.log(e);
771
			}
772
		}
773
	}
774
775
	private List<String> initParameterNames() {
776
		if (fMethod != null) {
777
			try {
778
				return new ArrayList<String>(Arrays.asList(fMethod
779
						.getParameterNames()));
780
			} catch (ModelException e) {
781
				PHPUiPlugin.log(e);
782
			}
783
		}
784
		return Collections.EMPTY_LIST;
785
	}
786
787
	private boolean inheritParameterDescriptions(List<String> parameterNames,
788
			CharSequence[] parameterDescriptions, CharSequence[] parameterTypes) {
789
		boolean hasInheritedParameters = false;
790
		if (fMethod != null && fMethod.getDeclaringType() == null) {
791
			return hasInheritedParameters;
792
		}
793
		for (int i = 0; i < parameterNames.size(); i++) {
794
			String name = (String) parameterNames.get(i);
795
			if (name != null) {
796
				parameterDescriptions[i] = fJavadocLookup
797
						.getInheritedParamDescription(fMethod, i);
798
				parameterTypes[i] = fJavadocLookup.getInheritedParamType(
799
						fMethod, i);
800
				if (parameterDescriptions[i] != null)
801
					hasInheritedParameters = true;
802
			}
803
		}
804
		return hasInheritedParameters;
805
	}
806
807
	private boolean inheritExceptionDescriptions(List<String> exceptionNames,
808
			CharSequence[] exceptionDescriptions) {
809
		boolean hasInheritedExceptions = false;
810
		if (fMethod != null && fMethod.getDeclaringType() == null) {
811
			return hasInheritedExceptions;
812
		}
813
		for (int i = 0; i < exceptionNames.size(); i++) {
814
			String name = (String) exceptionNames.get(i);
815
			if (name != null) {
816
				exceptionDescriptions[i] = fJavadocLookup
817
						.getInheritedExceptionDescription(fMethod, name);
818
				if (exceptionDescriptions[i] != null)
819
					hasInheritedExceptions = true;
820
			}
821
		}
822
		return hasInheritedExceptions;
823
	}
824
825
	CharSequence getMainDescription() {
826
		if (fMainDescription == null) {
827
			fMainDescription = new StringBuffer();
828
			fBuf = fMainDescription;
829
830
			String shortDescription = fJavadoc.getShortDescription();
831
			if (shortDescription != null && shortDescription.length() > 0) {
832
				fMainDescription.append(shortDescription);
833
			}
834
			fBuf = null;
835
		}
836
		return fMainDescription.length() > 0 ? fMainDescription : null;
837
	}
838
839
	CharSequence getReturnDescription() {
840
		if (fReturnDescription == null) {
841
			fReturnDescription = new StringBuffer();
842
			fBuf = fReturnDescription;
843
844
			PHPDocTag[] tags = fJavadoc.getTags();
845
			for (PHPDocTag tag : tags) {
846
				if (PHPDocTag.RETURN == tag.getTagKind()) {
847
					handleContentElements(tag);
848
					break;
849
				}
850
			}
851
852
			fBuf = null;
853
		}
854
		return fReturnDescription.length() > 0 ? fReturnDescription : null;
855
	}
856
857
	CharSequence getInheritedParamDescription(int paramIndex)
858
			throws ModelException {
859
		if (fMethod != null) {
860
			String[] parameterNames = fMethod.getParameterNames();
861
			if (paramIndex >= parameterNames.length) {
862
				return null;
863
			}
864
			if (fParamDescriptions == null) {
865
				fParamDescriptions = new StringBuffer[parameterNames.length];
866
			} else {
867
				StringBuffer description = fParamDescriptions[paramIndex];
868
				if (description != null) {
869
					return description.length() > 0 ? description : null;
870
				}
871
			}
872
873
			StringBuffer description = new StringBuffer();
874
			fParamDescriptions[paramIndex] = description;
875
			fBuf = description;
876
877
			String paramName = parameterNames[paramIndex];
878
			String info = getParameterInfo(fJavadoc, paramName,
879
					PARAMETER_DESCRIPTION_TYPE);
880
			if (info != null)
881
				description.append(info);
882
			fBuf = null;
883
			return description.length() > 0 ? description : null;
884
		}
885
		return null;
886
	}
887
888
	CharSequence getInheritedParamType(int paramIndex) throws ModelException {
889
		if (fMethod != null) {
890
			String[] parameterNames = fMethod.getParameterNames();
891
			if (paramIndex >= parameterNames.length) {
892
				return null;
893
			}
894
			if (fParamTypes == null) {
895
				fParamTypes = new StringBuffer[parameterNames.length];
896
			} else {
897
				StringBuffer typeName = fParamTypes[paramIndex];
898
				if (typeName != null) {
899
					return typeName.length() > 0 ? typeName : null;
900
				}
901
			}
902
903
			StringBuffer typeName = new StringBuffer();
904
			fParamTypes[paramIndex] = typeName;
905
			fBuf = typeName;
906
907
			String paramName = parameterNames[paramIndex];
908
			String info = getParameterInfo(fJavadoc, paramName,
909
					PARAMETER_TYPE_TYPE);
910
			if (info != null)
911
				typeName.append(info);
912
913
			fBuf = null;
914
			return typeName.length() > 0 ? typeName : null;
915
		}
916
		return null;
917
	}
918
919
	CharSequence getExceptionDescription(String simpleName) {
920
		if (fMethod != null) {
921
			if (fExceptionDescriptions == null) {
922
				fExceptionDescriptions = new HashMap();
923
			} else {
924
				StringBuffer description = (StringBuffer) fExceptionDescriptions
925
						.get(simpleName);
926
				if (description != null) {
927
					return description.length() > 0 ? description : null;
928
				}
929
			}
930
931
			StringBuffer description = new StringBuffer();
932
			fExceptionDescriptions.put(simpleName, description);
933
			fBuf = description;
934
935
			List tags = Arrays.asList(fJavadoc.getTags());
936
			for (Iterator iter = tags.iterator(); iter.hasNext();) {
937
				PHPDocTag tag = (PHPDocTag) iter.next();
938
				if (PHPDocTag.THROWS == tag.getTagKind()) {
939
					List fragments = Arrays.asList(tag.getReferences());
940
					if (fragments.size() > 0) {
941
						Object first = fragments.get(0);
942
						if (first instanceof Identifier) {
943
							String name = ((Identifier) first).getName();
944
							if (name.equals(simpleName)) {
945
								if (fragments.size() > 1)
946
									handleContentElements(tag);
947
								break;
948
							}
949
						}
950
					}
951
				}
952
			}
953
954
			fBuf = null;
955
			return description.length() > 0 ? description : null;
956
		}
957
		return null;
958
	}
959
960
	private void handleContentElements(PHPDocTag tag) {
961
		fBuf.append(tag.getValue());
962
	}
963
964
	private boolean handleInherited(CharSequence inherited) {
965
		if (inherited == null)
966
			return false;
967
968
		fBuf.append(inherited);
969
		return true;
970
	}
971
972
	private void handleBlockTags(String title, List tags) {
973
		if (tags.isEmpty())
974
			return;
975
976
		handleBlockTagTitle(title);
977
978
		for (Iterator iter = tags.iterator(); iter.hasNext();) {
979
			PHPDocTag tag = (PHPDocTag) iter.next();
980
			fBuf.append(BlOCK_TAG_ENTRY_START);
981
			if (PHPDocTag.SEE == tag.getTagKind()) {
982
				handleSeeTag(tag);
983
			} else {
984
				handleContentElements(tag);
985
			}
986
			fBuf.append(BlOCK_TAG_ENTRY_END);
987
		}
988
	}
989
990
	private void handleReturnTag(PHPDocTag tag, CharSequence returnDescription) {
991
		if (tag == null && returnDescription == null)
992
			return;
993
994
		handleBlockTagTitle(PHPDocumentationMessages.JavaDoc2HTMLTextReader_returns_section);
995
		fBuf.append(BlOCK_TAG_ENTRY_START);
996
		if (tag != null)
997
			handleContentElements(tag);
998
		else
999
			fBuf.append(returnDescription);
1000
		fBuf.append(BlOCK_TAG_ENTRY_END);
1001
	}
1002
1003
	private void handleBlockTags(List tags) {
1004
		for (Iterator iter = tags.iterator(); iter.hasNext();) {
1005
			PHPDocTag tag = (PHPDocTag) iter.next();
1006
			if (tag.getTagKind() == PHPDocTag.VAR) {
1007
				handleBlockTagTitle("Type");
1008
			} else {
1009
				handleBlockTagTitle(PHPDocTag.getTagKind(tag.getTagKind()));
1010
			}
1011
			fBuf.append(BlOCK_TAG_ENTRY_START);
1012
			if (tag.getTagKind() == PHPDocTag.LINK) {
1013
				handleLinkTag(tag);
1014
			} else {
1015
				handleContentElements(tag);
1016
			}
1017
			fBuf.append(BlOCK_TAG_ENTRY_END);
1018
		}
1019
	}
1020
1021
	private void handleBlockTagTitle(String title) {
1022
		fBuf.append("<dt>"); //$NON-NLS-1$
1023
		fBuf.append(title);
1024
		fBuf.append("</dt>"); //$NON-NLS-1$
1025
	}
1026
1027
	private void handleSeeTag(PHPDocTag tag) {
1028
		handleLink(Arrays.asList(tag.getReferences()));
1029
	}
1030
1031
	private void handleExceptionTags(List tags, List exceptionNames,
1032
			CharSequence[] exceptionDescriptions) {
1033
		if (tags.size() == 0 && containsOnlyNull(exceptionNames))
1034
			return;
1035
1036
		handleBlockTagTitle(PHPDocumentationMessages.JavaDoc2HTMLTextReader_throws_section);
1037
1038
		for (Iterator iter = tags.iterator(); iter.hasNext();) {
1039
			PHPDocTag tag = (PHPDocTag) iter.next();
1040
			fBuf.append(BlOCK_TAG_ENTRY_START);
1041
			handleThrowsTag(tag);
1042
			fBuf.append(BlOCK_TAG_ENTRY_END);
1043
		}
1044
		for (int i = 0; i < exceptionDescriptions.length; i++) {
1045
			CharSequence description = exceptionDescriptions[i];
1046
			String name = (String) exceptionNames.get(i);
1047
			if (name != null) {
1048
				fBuf.append(BlOCK_TAG_ENTRY_START);
1049
				// handleLink(Collections.singletonList(
1050
				// .newSimpleName(name)));
1051
				if (description != null) {
1052
					fBuf.append(ScriptElementLabels.CONCAT_STRING);
1053
					fBuf.append(description);
1054
				}
1055
				fBuf.append(BlOCK_TAG_ENTRY_END);
1056
			}
1057
		}
1058
	}
1059
1060
	private void handleThrowsTag(PHPDocTag tag) {
1061
		List<SimpleReference> fragments = Arrays.asList(tag.getReferences());
1062
		int size = fragments.size();
1063
		if (size > 0) {
1064
			String exceptionName = "";
1065
			if (fragments.get(0) instanceof TypeReference) {
1066
				exceptionName = fragments.get(0).getName().trim();
1067
				fBuf.append(exceptionName);
1068
			}
1069
			String value = tag.getValue().trim();
1070
			String description = value.substring(exceptionName.length());
1071
			if (description.length() > 0) {
1072
				fBuf.append(ScriptElementLabels.CONCAT_STRING);
1073
				fBuf.append(description.trim());
1074
			}
1075
		}
1076
	}
1077
1078
	private void handleParameterTags(List tags, List parameterNames,
1079
			CharSequence[] parameterTypes, CharSequence[] parameterDescriptions) {
1080
		if (tags.size() == 0 && containsOnlyNull(parameterNames))
1081
			return;
1082
1083
		handleBlockTagTitle(PHPDocumentationMessages.JavaDoc2HTMLTextReader_parameters_section);
1084
1085
		for (Iterator iter = tags.iterator(); iter.hasNext();) {
1086
			PHPDocTag tag = (PHPDocTag) iter.next();
1087
			fBuf.append(BlOCK_TAG_ENTRY_START);
1088
			handleParamTag(tag);
1089
			fBuf.append(BlOCK_TAG_ENTRY_END);
1090
		}
1091
		for (int i = 0; i < parameterDescriptions.length; i++) {
1092
			CharSequence description = parameterDescriptions[i];
1093
			String name = (String) parameterNames.get(i);
1094
			if (name != null) {
1095
				fBuf.append(BlOCK_TAG_ENTRY_START);
1096
				if (parameterTypes[i] != null) {
1097
					fBuf.append(PARAM_NAME_START);
1098
					fBuf.append(parameterTypes[i]);
1099
					fBuf.append(PARAM_NAME_END);
1100
				}
1101
				fBuf.append(PARAM_NAME_END);
1102
				fBuf.append(PARAM_NAME_START);
1103
				fBuf.append(name);
1104
				fBuf.append(PARAM_NAME_END);
1105
				if (description != null)
1106
					fBuf.append(description);
1107
				fBuf.append(BlOCK_TAG_ENTRY_END);
1108
			}
1109
		}
1110
	}
1111
1112
	private void handleParamTag(PHPDocTag tag) {
1113
		if (tag.getReferences().length == 0) {
1114
			fBuf.append(tag.getValue());
1115
			return;
1116
		}
1117
		String parameterName = getParameterInfo(tag, PARAMETER_NAME_TYPE);
1118
		String parameterType = getParameterInfo(tag, PARAMETER_TYPE_TYPE);
1119
		String description = getParameterInfo(tag, PARAMETER_DESCRIPTION_TYPE);
1120
		fBuf.append(BlOCK_TAG_ENTRY_START);
1121
		if (parameterType != null) {
1122
			fBuf.append(PARAM_NAME_START);
1123
			fBuf.append(parameterType);
1124
			fBuf.append(PARAM_NAME_END);
1125
		}
1126
		fBuf.append(PARAM_NAME_START);
1127
		fBuf.append(parameterName);
1128
		fBuf.append(PARAM_NAME_END);
1129
		if (description != null)
1130
			fBuf.append(description);
1131
		fBuf.append(BlOCK_TAG_ENTRY_END);
1132
	}
1133
1134
	private void handleLinkTag(PHPDocTag tag) {
1135
		fBuf.append("<a href=");
1136
		fBuf.append(tag.getValue());
1137
		fBuf.append(">").append(tag.getValue()).append("</a>");
1138
	}
1139
1140
	private void handleLink(List fragments) {
1141
		// int fs = fragments.size();
1142
		// if (fs > 0) {
1143
		// Object first = fragments.get(0);
1144
		// String refTypeName = null;
1145
		// String refMemberName = null;
1146
		// String[] refMethodParamTypes = null;
1147
		// String[] refMethodParamNames = null;
1148
		// if (first instanceof Name) {
1149
		// Name name = (Name) first;
1150
		// refTypeName = name.getFullyQualifiedName();
1151
		// } else if (first instanceof MemberRef) {
1152
		// MemberRef memberRef = (MemberRef) first;
1153
		// Name qualifier = memberRef.getQualifier();
1154
		//				refTypeName = qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$
1155
		// refMemberName = memberRef.getName().getIdentifier();
1156
		// } else if (first instanceof MethodRef) {
1157
		// MethodRef methodRef = (MethodRef) first;
1158
		// Name qualifier = methodRef.getQualifier();
1159
		//				refTypeName = qualifier == null ? "" : qualifier.getFullyQualifiedName(); //$NON-NLS-1$
1160
		// refMemberName = methodRef.getName().getIdentifier();
1161
		// List params = methodRef.parameters();
1162
		// int ps = params.size();
1163
		// refMethodParamTypes = new String[ps];
1164
		// refMethodParamNames = new String[ps];
1165
		// for (int i = 0; i < ps; i++) {
1166
		// MethodRefParameter param = (MethodRefParameter) params
1167
		// .get(i);
1168
		// refMethodParamTypes[i] = ASTNodes.asString(param.getType());
1169
		// SimpleName paramName = param.getName();
1170
		// if (paramName != null)
1171
		// refMethodParamNames[i] = paramName.getIdentifier();
1172
		// }
1173
		// }
1174
		//
1175
		// if (refTypeName != null) {
1176
		//				fBuf.append("<a href='"); //$NON-NLS-1$
1177
		// try {
1178
		// String scheme = JavaElementLinks.JAVADOC_SCHEME;
1179
		// String uri = JavaElementLinks.createURI(scheme, fMember,
1180
		// refTypeName, refMemberName, refMethodParamTypes);
1181
		// fBuf.append(uri);
1182
		// } catch (URISyntaxException e) {
1183
		// PHPUiPlugin.log(e);
1184
		// }
1185
		//				fBuf.append("'>"); //$NON-NLS-1$
1186
		// if (fs > 1) {
1187
		// // if (fs == 2 && fragments.get(1) instanceof TextElement) {
1188
		// // String text= removeLeadingWhitespace(((TextElement)
1189
		// // fragments.get(1)).getText());
1190
		// // if (text.length() != 0)
1191
		// // handleText(text);
1192
		// // else
1193
		// // //throws
1194
		// // }
1195
		// handleContentElements(fragments.subList(1, fs));
1196
		// } else {
1197
		// fBuf.append(refTypeName);
1198
		// if (refMemberName != null) {
1199
		// if (refTypeName.length() > 0) {
1200
		// fBuf.append('.');
1201
		// }
1202
		// fBuf.append(refMemberName);
1203
		// if (refMethodParamTypes != null) {
1204
		// fBuf.append('(');
1205
		// for (int i = 0; i < refMethodParamTypes.length; i++) {
1206
		// String pType = refMethodParamTypes[i];
1207
		// fBuf.append(pType);
1208
		// String pName = refMethodParamNames[i];
1209
		// if (pName != null) {
1210
		// fBuf.append(' ').append(pName);
1211
		// }
1212
		// if (i < refMethodParamTypes.length - 1) {
1213
		//									fBuf.append(", "); //$NON-NLS-1$
1214
		// }
1215
		// }
1216
		// fBuf.append(')');
1217
		// }
1218
		// }
1219
		// }
1220
		//				fBuf.append("</a>"); //$NON-NLS-1$
1221
		// } else {
1222
		// handleContentElements(fragments);
1223
		// }
1224
		// }
1225
	}
1226
1227
	private boolean containsOnlyNull(List parameterNames) {
1228
		for (Iterator iter = parameterNames.iterator(); iter.hasNext();) {
1229
			if (iter.next() != null)
1230
				return false;
1231
		}
1232
		return true;
1233
	}
1234
1235
	private String getParameterInfo(PHPDocBlock phpDoc, String paramName,
1236
			int infoType) {
1237
		for (PHPDocTag tag : phpDoc.getTags(PHPDocTag.PARAM)) {
1238
			String name = getParameterInfo(tag, PARAMETER_NAME_TYPE);
1239
			if (name.equals(paramName)) {
1240
				return getParameterInfo(tag, infoType);
1241
			}
1242
			continue;
1243
		}
1244
		return null;
1245
	}
1246
1247
	private String getParameterInfo(PHPDocTag tag, int infoType) {
1248
		if (tag.getTagKind() != PHPDocTag.PARAM) {
1249
			return null;
1250
		}
1251
		SimpleReference typeRef = null;
1252
		SimpleReference variableRef = null;
1253
		String value = tag.getValue();
1254
		if (tag.getReferences().length != 2) {
1255
			return null;
1256
		}
1257
		for (SimpleReference reference : tag.getReferences()) {
1258
			if (reference instanceof TypeReference) {
1259
				typeRef = reference;
1260
			} else if (reference instanceof VariableReference) {
1261
				variableRef = reference;
1262
			}
1263
		}
1264
		if (infoType == PARAMETER_DESCRIPTION_TYPE) {
1265
			int typeRefIndex = value.indexOf(typeRef.getName());
1266
			int variableRefIndex = value.indexOf(variableRef.getName());
1267
			int lastRefIndex = typeRefIndex > variableRefIndex ? typeRefIndex
1268
					+ typeRef.getName().length() : variableRefIndex
1269
					+ variableRef.getName().length();
1270
			return value.substring(lastRefIndex).trim();
1271
		} else if (infoType == PARAMETER_TYPE_TYPE) {
1272
			return typeRef.getName();
1273
		} else if (infoType == PARAMETER_NAME_TYPE) {
1274
			return variableRef.getName();
1275
		}
1276
		return null;
1277
	}
1278
1279
	private boolean appendBuiltinDoc(IMember element, StringBuffer buf) {
1280
		String builtinDoc = BuiltinDoc.getString(element.getElementName());
1281
		if (builtinDoc.length() > 0) {
1282
			// String fileName = getFileName(element);
1283
			//
1284
			// // append the file name
1285
			// appendDefinitionRow(FIELD_LOCATION, fileName, buf);
1286
			//
1287
			// // append the class name if it exists
1288
			// IType declaringType = element.getDeclaringType();
1289
			// appendTypeInfoRow(declaringType, buf);
1290
1291
			buf.append(builtinDoc);
1292
			return true;
1293
		}
1294
		return false;
1295
	}
1296
1297
}
(-)src/org/eclipse/php/internal/ui/documentation/PHPDocumentationMessages.java (+33 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.documentation;
2
3
import org.eclipse.osgi.util.NLS;
4
5
/**
6
 * Helper class to get NLSed messages.
7
 */
8
final class PHPDocumentationMessages extends NLS {
9
10
	private static final String BUNDLE_NAME = PHPDocumentationMessages.class
11
			.getName();
12
13
	private PHPDocumentationMessages() {
14
		// Do not instantiate
15
	}
16
17
	public static String CompletionEvaluator_default_package;
18
	public static String JavaDoc2HTMLTextReader_parameters_section;
19
	public static String JavaDoc2HTMLTextReader_returns_section;
20
	public static String JavaDoc2HTMLTextReader_throws_section;
21
	public static String JavaDoc2HTMLTextReader_author_section;
22
	public static String JavaDoc2HTMLTextReader_deprecated_section;
23
	public static String JavaDoc2HTMLTextReader_method_in_type;
24
	public static String JavaDoc2HTMLTextReader_overrides_section;
25
	public static String JavaDoc2HTMLTextReader_see_section;
26
	public static String JavaDoc2HTMLTextReader_since_section;
27
	public static String JavaDoc2HTMLTextReader_specified_by_section;
28
	public static String JavaDoc2HTMLTextReader_version_section;
29
30
	static {
31
		NLS.initializeMessages(BUNDLE_NAME, PHPDocumentationMessages.class);
32
	}
33
}
(-)src/org/eclipse/php/internal/ui/documentation/PHPDocumentationMessages.properties (+24 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2000, 2008 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
12
CompletionEvaluator_default_package=(default package)
13
14
JavaDoc2HTMLTextReader_parameters_section=Parameters:
15
JavaDoc2HTMLTextReader_returns_section=Returns:
16
JavaDoc2HTMLTextReader_throws_section=Throws:
17
JavaDoc2HTMLTextReader_author_section=Author:
18
JavaDoc2HTMLTextReader_deprecated_section=Deprecated.
19
JavaDoc2HTMLTextReader_method_in_type={0} in {1}
20
JavaDoc2HTMLTextReader_overrides_section=Overrides:
21
JavaDoc2HTMLTextReader_see_section=See Also:
22
JavaDoc2HTMLTextReader_since_section=Since:
23
JavaDoc2HTMLTextReader_specified_by_section=Specified by:
24
JavaDoc2HTMLTextReader_version_section=Version:
(-)src/org/eclipse/php/internal/ui/editor/hover/AbstractPHPEditorTextHover.java (+108 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.editor.hover;
2
3
import org.eclipse.core.resources.IStorage;
4
import org.eclipse.dltk.core.ICodeAssist;
5
import org.eclipse.dltk.core.IModelElement;
6
import org.eclipse.dltk.core.ModelException;
7
import org.eclipse.dltk.internal.core.ExternalSourceModule;
8
import org.eclipse.dltk.internal.ui.editor.ExternalStorageEditorInput;
9
import org.eclipse.dltk.internal.ui.text.hover.AbstractScriptEditorTextHover;
10
import org.eclipse.dltk.ui.DLTKUIPlugin;
11
import org.eclipse.dltk.ui.IWorkingCopyManager;
12
import org.eclipse.jface.text.*;
13
import org.eclipse.swt.widgets.Shell;
14
import org.eclipse.ui.IEditorInput;
15
import org.eclipse.ui.IEditorPart;
16
import org.eclipse.ui.editors.text.EditorsUI;
17
18
public class AbstractPHPEditorTextHover extends AbstractScriptEditorTextHover
19
		implements ITextHoverExtension2 {
20
21
	public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
22
		return getHoverInfo(textViewer, hoverRegion);
23
	}
24
25
	/*
26
	 * @see ITextHoverExtension#getHoverControlCreator()
27
	 * 
28
	 * @since 3.0
29
	 */
30
	public IInformationControlCreator getHoverControlCreator() {
31
		return new IInformationControlCreator() {
32
			public IInformationControl createInformationControl(Shell parent) {
33
				return new DefaultInformationControl(parent, EditorsUI
34
						.getTooltipAffordanceString());
35
			}
36
		};
37
	}
38
39
	/*
40
	 * @seeorg.eclipse.jface.text.ITextHoverExtension2#
41
	 * getInformationPresenterControlCreator()
42
	 * 
43
	 * @since 3.4
44
	 */
45
	public IInformationControlCreator getInformationPresenterControlCreator() {
46
		return new IInformationControlCreator() {
47
			public IInformationControl createInformationControl(Shell shell) {
48
				return new DefaultInformationControl(shell, true);
49
			}
50
		};
51
	}
52
53
	protected ICodeAssist getCodeAssist() {
54
		IEditorPart editor = getEditor();
55
		if (editor != null) {
56
			IEditorInput input = editor.getEditorInput();
57
58
			if (input instanceof ExternalStorageEditorInput) {
59
				ExternalStorageEditorInput external = (ExternalStorageEditorInput) input;
60
				IStorage storage = external.getStorage();
61
				if (storage != null) {
62
					if (storage instanceof ExternalSourceModule) {
63
						ExternalSourceModule externalSourceModule = (ExternalSourceModule) storage;
64
						return externalSourceModule;
65
					}
66
				}
67
			}
68
69
			IWorkingCopyManager manager = DLTKUIPlugin.getDefault()
70
					.getWorkingCopyManager();
71
			return manager.getWorkingCopy(input, false);
72
		}
73
74
		return null;
75
	}
76
77
	/**
78
	 * Returns the Java elements at the given hover region.
79
	 * 
80
	 * @param textViewer
81
	 *            the text viewer
82
	 * @param hoverRegion
83
	 *            the hover region
84
	 * @return the array with the Java elements or <code>null</code>
85
	 * @since 3.4
86
	 */
87
	protected IModelElement[] getElementsAt(ITextViewer textViewer,
88
			IRegion hoverRegion) {
89
		/*
90
		 * The region should be a word region an not of length 0. This check is
91
		 * needed because codeSelect(...) also finds the Java element if the
92
		 * offset is behind the word.
93
		 */
94
		if (hoverRegion.getLength() == 0)
95
			return null;
96
97
		ICodeAssist resolve = getCodeAssist();
98
		if (resolve != null) {
99
			try {
100
				return resolve.codeSelect(hoverRegion.getOffset(), hoverRegion
101
						.getLength());
102
			} catch (ModelException x) {
103
				return null;
104
			}
105
		}
106
		return null;
107
	}
108
}
(-)src/org/eclipse/php/internal/ui/editor/hover/BestMatchHover.java (-2 / +37 lines)
Lines 15-21 Link Here
15
import java.util.Iterator;
15
import java.util.Iterator;
16
import java.util.List;
16
import java.util.List;
17
17
18
import org.eclipse.dltk.internal.ui.text.hover.AbstractScriptEditorTextHover;
19
import org.eclipse.jface.preference.IPreferenceStore;
18
import org.eclipse.jface.preference.IPreferenceStore;
20
import org.eclipse.jface.text.*;
19
import org.eclipse.jface.text.*;
21
import org.eclipse.jface.text.information.IInformationProviderExtension2;
20
import org.eclipse.jface.text.information.IInformationProviderExtension2;
Lines 26-32 Link Here
26
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
25
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
27
import org.eclipse.ui.IEditorPart;
26
import org.eclipse.ui.IEditorPart;
28
27
29
public class BestMatchHover extends AbstractScriptEditorTextHover implements
28
public class BestMatchHover extends AbstractPHPEditorTextHover implements
30
		IPHPTextHover, ITextHoverExtension, IInformationProviderExtension2 {
29
		IPHPTextHover, ITextHoverExtension, IInformationProviderExtension2 {
31
30
32
	private List<PHPEditorTextHoverDescriptor> fTextHoverSpecifications;
31
	private List<PHPEditorTextHoverDescriptor> fTextHoverSpecifications;
Lines 113-118 Link Here
113
	}
112
	}
114
113
115
	/*
114
	/*
115
	 * @see
116
	 * org.eclipse.jface.text.ITextHoverExtension2#getHoverInfo2(org.eclipse
117
	 * .jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
118
	 */
119
	public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
120
121
		checkTextHovers();
122
		fBestHover = null;
123
124
		if (fInstantiatedTextHovers == null)
125
			return null;
126
127
		for (Iterator iterator = fInstantiatedTextHovers.iterator(); iterator
128
				.hasNext();) {
129
			ITextHover hover = (ITextHover) iterator.next();
130
131
			if (hover instanceof ITextHoverExtension2) {
132
				Object info = ((ITextHoverExtension2) hover).getHoverInfo2(
133
						textViewer, hoverRegion);
134
				if (info != null) {
135
					fBestHover = hover;
136
					return info;
137
				}
138
			} else {
139
				String s = hover.getHoverInfo(textViewer, hoverRegion);
140
				if (s != null && s.trim().length() > 0) {
141
					fBestHover = hover;
142
					return s;
143
				}
144
			}
145
		}
146
147
		return null;
148
	}
149
150
	/*
116
	 * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator()
151
	 * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator()
117
	 * 
152
	 * 
118
	 * @since 3.0
153
	 * @since 3.0
(-)src/org/eclipse/php/internal/ui/editor/hover/PHPDocumentationBrowserInformationControlInput.java (+81 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.editor.hover;
2
3
import org.eclipse.core.runtime.Assert;
4
import org.eclipse.dltk.core.IModelElement;
5
import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
6
7
/**
8
 * Browser input for Javadoc hover.
9
 * 
10
 * @since 3.4
11
 */
12
public class PHPDocumentationBrowserInformationControlInput extends
13
		BrowserInformationControlInput {
14
15
	private final IModelElement fElement;
16
	private final String fHtml;
17
	private final int fLeadingImageWidth;
18
19
	/**
20
	 * Creates a new browser information control input.
21
	 * 
22
	 * @param previous
23
	 *            previous input, or <code>null</code> if none available
24
	 * @param element
25
	 *            the element, or <code>null</code> if none available
26
	 * @param html
27
	 *            HTML contents, must not be null
28
	 * @param leadingImageWidth
29
	 *            the indent required for the element image
30
	 */
31
	public PHPDocumentationBrowserInformationControlInput(
32
			PHPDocumentationBrowserInformationControlInput previous,
33
			IModelElement element, String html, int leadingImageWidth) {
34
		super(previous);
35
		Assert.isNotNull(html);
36
		fElement = element;
37
		fHtml = html;
38
		fLeadingImageWidth = leadingImageWidth;
39
	}
40
41
	/*
42
	 * @seeorg.eclipse.jface.internal.text.html.BrowserInformationControlInput#
43
	 * getLeadingImageWidth()
44
	 * 
45
	 * @since 3.4
46
	 */
47
	public int getLeadingImageWidth() {
48
		return fLeadingImageWidth;
49
	}
50
51
	/**
52
	 * Returns the Java element.
53
	 * 
54
	 * @return the element or <code>null</code> if none available
55
	 */
56
	public IModelElement getElement() {
57
		return fElement;
58
	}
59
60
	/*
61
	 * @see org.eclipse.jface.internal.text.html.BrowserInput#getHtml()
62
	 */
63
	public String getHtml() {
64
		return fHtml;
65
	}
66
67
	/*
68
	 * @see org.eclipse.jdt.internal.ui.infoviews.BrowserInput#getInputElement()
69
	 */
70
	public Object getInputElement() {
71
		return fElement == null ? (Object) fHtml : fElement;
72
	}
73
74
	/*
75
	 * @see org.eclipse.jdt.internal.ui.infoviews.BrowserInput#getInputName()
76
	 */
77
	public String getInputName() {
78
		return fElement == null ? "" : fElement.getElementName(); //$NON-NLS-1$
79
	}
80
81
}
(-)src/org/eclipse/php/internal/ui/editor/hover/PHPDocumentationHover.java (-107 / +772 lines)
Lines 11-160 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.php.internal.ui.editor.hover;
12
package org.eclipse.php.internal.ui.editor.hover;
13
13
14
import java.io.Reader;
14
import java.io.*;
15
import java.io.StringReader;
15
import java.net.URL;
16
16
17
import org.eclipse.core.resources.IStorage;
17
import org.eclipse.core.runtime.Platform;
18
import org.eclipse.dltk.core.ICodeAssist;
18
import org.eclipse.dltk.core.*;
19
import org.eclipse.dltk.core.IMember;
19
import org.eclipse.dltk.internal.ui.editor.EditorUtility;
20
import org.eclipse.dltk.core.IModelElement;
20
import org.eclipse.dltk.ui.DLTKPluginImages;
21
import org.eclipse.dltk.core.ModelException;
21
import org.eclipse.dltk.ui.PreferenceConstants;
22
import org.eclipse.dltk.internal.core.ExternalSourceModule;
23
import org.eclipse.dltk.internal.ui.editor.ExternalStorageEditorInput;
24
import org.eclipse.dltk.internal.ui.text.HTMLPrinter;
25
import org.eclipse.dltk.internal.ui.text.hover.DocumentationHover;
26
import org.eclipse.dltk.internal.ui.text.hover.ScriptHoverMessages;
27
import org.eclipse.dltk.ui.DLTKUIPlugin;
28
import org.eclipse.dltk.ui.IWorkingCopyManager;
29
import org.eclipse.dltk.ui.ScriptElementLabels;
22
import org.eclipse.dltk.ui.ScriptElementLabels;
30
import org.eclipse.dltk.ui.documentation.ScriptDocumentationAccess;
23
import org.eclipse.dltk.ui.viewsupport.BasicElementLabels;
31
import org.eclipse.dltk.utils.TextUtils;
24
import org.eclipse.jface.action.Action;
25
import org.eclipse.jface.action.ToolBarManager;
26
import org.eclipse.jface.internal.text.html.BrowserInformationControl;
27
import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
28
import org.eclipse.jface.internal.text.html.BrowserInput;
29
import org.eclipse.jface.internal.text.html.HTMLPrinter;
30
import org.eclipse.jface.resource.JFaceResources;
31
import org.eclipse.jface.text.*;
32
import org.eclipse.jface.text.IRegion;
33
import org.eclipse.php.core.compiler.PHPFlags;
34
import org.eclipse.php.internal.core.ast.nodes.*;
35
import org.eclipse.php.internal.core.corext.dom.NodeFinder;
36
import org.eclipse.php.internal.ui.PHPUiPlugin;
37
import org.eclipse.php.internal.ui.documentation.PHPDocumentationContentAccess;
38
import org.eclipse.php.internal.ui.util.Messages;
39
import org.eclipse.php.ui.editor.SharedASTProvider;
32
import org.eclipse.php.ui.editor.hover.IHoverMessageDecorator;
40
import org.eclipse.php.ui.editor.hover.IHoverMessageDecorator;
33
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
41
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
34
import org.eclipse.ui.IEditorInput;
42
import org.eclipse.swt.SWT;
43
import org.eclipse.swt.graphics.FontData;
44
import org.eclipse.swt.widgets.Shell;
35
import org.eclipse.ui.IEditorPart;
45
import org.eclipse.ui.IEditorPart;
46
import org.eclipse.ui.ISharedImages;
47
import org.eclipse.ui.PartInitException;
48
import org.eclipse.ui.PlatformUI;
49
import org.eclipse.ui.editors.text.EditorsUI;
50
import org.osgi.framework.Bundle;
36
51
37
public class PHPDocumentationHover extends DocumentationHover implements
52
@SuppressWarnings("restriction")
53
public class PHPDocumentationHover extends AbstractPHPEditorTextHover implements
38
		IPHPTextHover {
54
		IPHPTextHover {
39
55
40
	private final long LABEL_FLAGS = // ScriptElementLabels.ALL_FULLY_QUALIFIED
56
	public IHoverMessageDecorator getMessageDecorator() {
41
	ScriptElementLabels.M_APP_TYPE_PARAMETERS
57
		return null;
58
	}
59
60
	/**
61
	 * Action to go back to the previous input in the hover control.
62
	 * 
63
	 * @since 3.4
64
	 */
65
	private static final class BackAction extends Action {
66
		private final BrowserInformationControl fInfoControl;
67
68
		public BackAction(BrowserInformationControl infoControl) {
69
			fInfoControl = infoControl;
70
			setText(PHPHoverMessages.JavadocHover_back);
71
			ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
72
			setImageDescriptor(images
73
					.getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
74
			setDisabledImageDescriptor(images
75
					.getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED));
76
77
			update();
78
		}
79
80
		public void run() {
81
			BrowserInformationControlInput previous = (BrowserInformationControlInput) fInfoControl
82
					.getInput().getPrevious();
83
			if (previous != null) {
84
				fInfoControl.setInput(previous);
85
			}
86
		}
87
88
		public void update() {
89
			BrowserInformationControlInput current = fInfoControl.getInput();
90
91
			if (current != null && current.getPrevious() != null) {
92
				BrowserInput previous = current.getPrevious();
93
				setToolTipText(Messages.format(
94
						PHPHoverMessages.JavadocHover_back_toElement_toolTip,
95
						BasicElementLabels.getJavaElementName(previous
96
								.getInputName())));
97
				setEnabled(true);
98
			} else {
99
				setToolTipText(PHPHoverMessages.JavadocHover_back);
100
				setEnabled(false);
101
			}
102
		}
103
	}
104
105
	/**
106
	 * Action to go forward to the next input in the hover control.
107
	 * 
108
	 * @since 3.4
109
	 */
110
	private static final class ForwardAction extends Action {
111
		private final BrowserInformationControl fInfoControl;
112
113
		public ForwardAction(BrowserInformationControl infoControl) {
114
			fInfoControl = infoControl;
115
			setText(PHPHoverMessages.JavadocHover_forward);
116
			ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
117
			setImageDescriptor(images
118
					.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
119
			setDisabledImageDescriptor(images
120
					.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD_DISABLED));
121
122
			update();
123
		}
124
125
		public void run() {
126
			BrowserInformationControlInput next = (BrowserInformationControlInput) fInfoControl
127
					.getInput().getNext();
128
			if (next != null) {
129
				fInfoControl.setInput(next);
130
			}
131
		}
132
133
		public void update() {
134
			BrowserInformationControlInput current = fInfoControl.getInput();
135
136
			if (current != null && current.getNext() != null) {
137
				setToolTipText(Messages
138
						.format(
139
								PHPHoverMessages.JavadocHover_forward_toElement_toolTip,
140
								BasicElementLabels.getJavaElementName(current
141
										.getNext().getInputName())));
142
				setEnabled(true);
143
			} else {
144
				setToolTipText(PHPHoverMessages.JavadocHover_forward_toolTip);
145
				setEnabled(false);
146
			}
147
		}
148
	}
149
150
	/**
151
	 * Action that opens the current hover input element.
152
	 * 
153
	 * @since 3.4
154
	 */
155
	private static final class OpenDeclarationAction extends Action {
156
		private final BrowserInformationControl fInfoControl;
157
158
		public OpenDeclarationAction(BrowserInformationControl infoControl) {
159
			fInfoControl = infoControl;
160
			setText(PHPHoverMessages.JavadocHover_openDeclaration);
161
			DLTKPluginImages.setLocalImageDescriptors(this, "goto_input.gif"); //$NON-NLS-1$ //TODO: better images
162
		}
163
164
		/*
165
		 * @see org.eclipse.jface.action.Action#run()
166
		 */
167
		public void run() {
168
			PHPDocumentationBrowserInformationControlInput infoInput = (PHPDocumentationBrowserInformationControlInput) fInfoControl
169
					.getInput(); // TODO: check cast
170
			fInfoControl.notifyDelayedInputChange(null);
171
			fInfoControl.dispose(); // FIXME: should have protocol to hide,
172
			// rather than dispose
173
174
			try {
175
				// FIXME: add hover location to editor navigation history?
176
				IEditorPart editor = EditorUtility.openInEditor(infoInput
177
						.getElement(), true);
178
				EditorUtility.revealInEditor(editor, infoInput.getElement());
179
			} catch (PartInitException e) {
180
				PHPUiPlugin.log(e);
181
			} catch (ModelException e) {
182
				PHPUiPlugin.log(e);
183
			}
184
		}
185
	}
186
187
	/**
188
	 * Presenter control creator.
189
	 * 
190
	 * @since 3.3
191
	 */
192
	public static final class PresenterControlCreator extends
193
			AbstractReusableInformationControlCreator {
194
195
		/*
196
		 * @seeorg.eclipse.jdt.internal.ui.text.java.hover.
197
		 * AbstractReusableInformationControlCreator
198
		 * #doCreateInformationControl(org.eclipse.swt.widgets.Shell)
199
		 */
200
		public IInformationControl doCreateInformationControl(Shell parent) {
201
			if (BrowserInformationControl.isAvailable(parent)) {
202
				ToolBarManager tbm = new ToolBarManager(SWT.FLAT);
203
				String font = PreferenceConstants.APPEARANCE_DOCUMENTATION_FONT;
204
				BrowserInformationControl iControl = new BrowserInformationControl(
205
						parent, font, tbm);
206
207
				final BackAction backAction = new BackAction(iControl);
208
				backAction.setEnabled(false);
209
				tbm.add(backAction);
210
				final ForwardAction forwardAction = new ForwardAction(iControl);
211
				tbm.add(forwardAction);
212
				forwardAction.setEnabled(false);
213
214
				final OpenDeclarationAction openDeclarationAction = new OpenDeclarationAction(
215
						iControl);
216
				tbm.add(openDeclarationAction);
217
218
				// final SimpleSelectionProvider selectionProvider = new
219
				// SimpleSelectionProvider();
220
				// OpenExternalBrowserAction openExternalJavadocAction = new
221
				// OpenExternalBrowserAction(
222
				// parent.getDisplay(), selectionProvider);
223
				// selectionProvider
224
				// .addSelectionChangedListener(openExternalJavadocAction);
225
				// selectionProvider.setSelection(new StructuredSelection());
226
				// tbm.add(openExternalJavadocAction);
227
228
				IInputChangedListener inputChangeListener = new IInputChangedListener() {
229
					public void inputChanged(Object newInput) {
230
						backAction.update();
231
						forwardAction.update();
232
						if (newInput == null) {
233
						} else if (newInput instanceof BrowserInformationControlInput) {
234
							BrowserInformationControlInput input = (BrowserInformationControlInput) newInput;
235
							Object inputElement = input.getInputElement();
236
							boolean isJavaElementInput = inputElement instanceof IModelElement;
237
							openDeclarationAction
238
									.setEnabled(isJavaElementInput);
239
						}
240
					}
241
				};
242
				iControl.addInputChangeListener(inputChangeListener);
243
244
				tbm.update(true);
245
246
				return iControl;
247
248
			} else {
249
				return new DefaultInformationControl(parent, true);
250
			}
251
		}
252
	}
253
254
	/**
255
	 * Hover control creator.
256
	 * 
257
	 * @since 3.3
258
	 */
259
	public static final class HoverControlCreator extends
260
			AbstractReusableInformationControlCreator {
261
		/**
262
		 * The information presenter control creator.
263
		 * 
264
		 * @since 3.4
265
		 */
266
		private final IInformationControlCreator fInformationPresenterControlCreator;
267
		/**
268
		 * <code>true</code> to use the additional info affordance,
269
		 * <code>false</code> to use the hover affordance.
270
		 */
271
		private final boolean fAdditionalInfoAffordance;
272
273
		/**
274
		 * @param informationPresenterControlCreator
275
		 *            control creator for enriched hover
276
		 * @since 3.4
277
		 */
278
		public HoverControlCreator(
279
				IInformationControlCreator informationPresenterControlCreator) {
280
			this(informationPresenterControlCreator, false);
281
		}
282
283
		/**
284
		 * @param informationPresenterControlCreator
285
		 *            control creator for enriched hover
286
		 * @param additionalInfoAffordance
287
		 *            <code>true</code> to use the additional info affordance,
288
		 *            <code>false</code> to use the hover affordance
289
		 * @since 3.4
290
		 */
291
		public HoverControlCreator(
292
				IInformationControlCreator informationPresenterControlCreator,
293
				boolean additionalInfoAffordance) {
294
			fInformationPresenterControlCreator = informationPresenterControlCreator;
295
			fAdditionalInfoAffordance = additionalInfoAffordance;
296
		}
297
298
		/*
299
		 * @seeorg.eclipse.jdt.internal.ui.text.java.hover.
300
		 * AbstractReusableInformationControlCreator
301
		 * #doCreateInformationControl(org.eclipse.swt.widgets.Shell)
302
		 */
303
		public IInformationControl doCreateInformationControl(Shell parent) {
304
			String tooltipAffordanceString = EditorsUI
305
					.getTooltipAffordanceString();
306
			if (BrowserInformationControl.isAvailable(parent)) {
307
				String font = PreferenceConstants.APPEARANCE_DOCUMENTATION_FONT;
308
				BrowserInformationControl iControl = new BrowserInformationControl(
309
						parent, font, tooltipAffordanceString) {
310
					/*
311
					 * @see
312
					 * org.eclipse.jface.text.IInformationControlExtension5#
313
					 * getInformationPresenterControlCreator()
314
					 */
315
					public IInformationControlCreator getInformationPresenterControlCreator() {
316
						return fInformationPresenterControlCreator;
317
					}
318
				};
319
				return iControl;
320
			} else {
321
				return new DefaultInformationControl(parent,
322
						tooltipAffordanceString);
323
			}
324
		}
325
326
		/*
327
		 * @seeorg.eclipse.jdt.internal.ui.text.java.hover.
328
		 * AbstractReusableInformationControlCreator
329
		 * #canReuse(org.eclipse.jface.text.IInformationControl)
330
		 */
331
		public boolean canReuse(IInformationControl control) {
332
			if (!super.canReuse(control))
333
				return false;
334
335
			if (control instanceof IInformationControlExtension4) {
336
				String tooltipAffordanceString = EditorsUI
337
						.getTooltipAffordanceString();
338
				((IInformationControlExtension4) control)
339
						.setStatusText(tooltipAffordanceString);
340
			}
341
342
			return true;
343
		}
344
	}
345
346
	private static final long LABEL_FLAGS = ScriptElementLabels.ALL_FULLY_QUALIFIED
347
			| ScriptElementLabels.M_PRE_RETURNTYPE
348
			| ScriptElementLabels.M_PARAMETER_TYPES
42
			| ScriptElementLabels.M_PARAMETER_NAMES
349
			| ScriptElementLabels.M_PARAMETER_NAMES
43
			| ScriptElementLabels.M_EXCEPTIONS
350
			| ScriptElementLabels.M_EXCEPTIONS
44
			| ScriptElementLabels.F_PRE_TYPE_SIGNATURE
351
			| ScriptElementLabels.F_PRE_TYPE_SIGNATURE
45
			| ScriptElementLabels.M_PRE_TYPE_PARAMETERS
352
			| ScriptElementLabels.M_PRE_TYPE_PARAMETERS
46
			| ScriptElementLabels.T_TYPE_PARAMETERS
353
			| ScriptElementLabels.T_TYPE_PARAMETERS
47
			| ScriptElementLabels.USE_RESOLVED;
354
			| ScriptElementLabels.USE_RESOLVED;
48
	private final long LOCAL_VARIABLE_FLAGS = LABEL_FLAGS
355
	private static final long LOCAL_VARIABLE_FLAGS = LABEL_FLAGS
49
			& ~ScriptElementLabels.F_FULLY_QUALIFIED
356
			& ~ScriptElementLabels.F_FULLY_QUALIFIED
50
			| ScriptElementLabels.F_POST_QUALIFIED;
357
			| ScriptElementLabels.F_POST_QUALIFIED;
51
358
52
	public IHoverMessageDecorator getMessageDecorator() {
359
	/**
53
		return null;
360
	 * The style sheet (css).
361
	 * 
362
	 * @since 3.4
363
	 */
364
	private static String fgStyleSheet;
365
366
	/**
367
	 * The hover control creator.
368
	 * 
369
	 * @since 3.2
370
	 */
371
	private IInformationControlCreator fHoverControlCreator;
372
	/**
373
	 * The presentation control creator.
374
	 * 
375
	 * @since 3.2
376
	 */
377
	private IInformationControlCreator fPresenterControlCreator;
378
379
	/*
380
	 * @seeorg.eclipse.jface.text.ITextHoverExtension2#
381
	 * getInformationPresenterControlCreator()
382
	 * 
383
	 * @since 3.1
384
	 */
385
	public IInformationControlCreator getInformationPresenterControlCreator() {
386
		if (fPresenterControlCreator == null)
387
			fPresenterControlCreator = new PresenterControlCreator();
388
		return fPresenterControlCreator;
54
	}
389
	}
55
390
56
	protected ICodeAssist getCodeAssist() {
391
	/*
57
		IEditorPart editor = getEditor();
392
	 * @see ITextHoverExtension#getHoverControlCreator()
58
		if (editor != null) {
393
	 * 
59
			IEditorInput input = editor.getEditorInput();
394
	 * @since 3.2
60
395
	 */
61
			if (input instanceof ExternalStorageEditorInput) {
396
	public IInformationControlCreator getHoverControlCreator() {
62
				ExternalStorageEditorInput external = (ExternalStorageEditorInput) input;
397
		if (fHoverControlCreator == null)
63
				IStorage storage = external.getStorage();
398
			fHoverControlCreator = new HoverControlCreator(
64
				if (storage != null) {
399
					getInformationPresenterControlCreator());
65
					if (storage instanceof ExternalSourceModule) {
400
		return fHoverControlCreator;
66
						ExternalSourceModule externalSourceModule = (ExternalSourceModule) storage;
401
	}
67
						return externalSourceModule;
68
					}
69
				}
70
			}
71
402
72
			IWorkingCopyManager manager = DLTKUIPlugin.getDefault()
403
	// private static void addLinkListener(final BrowserInformationControl
73
					.getWorkingCopyManager();
404
	// control) {
74
			return manager.getWorkingCopy(input, false);
405
	// control.addLocationListener(JavaElementLinks
75
		}
406
	// .createLocationListener(new JavaElementLinks.ILinkHandler() {
407
	// /*
408
	// * (non-Javadoc)
409
	// *
410
	// * @see
411
	// * org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks
412
	// * .ILinkHandler
413
	// * #handleJavadocViewLink(org.eclipse.jdt.core.
414
	// * IModelElement)
415
	// */
416
	// public void handleJavadocViewLink(IModelElement linkTarget) {
417
	// control.notifyDelayedInputChange(null);
418
	// control.setVisible(false);
419
	// control.dispose(); // FIXME: should have protocol to
420
	// // hide, rather than dispose
421
	// try {
422
	// JavadocView view = (JavadocView) PHPUiPlugin
423
	// .getActivePage().showView(
424
	// JavaUI.ID_JAVADOC_VIEW);
425
	// view.setInput(linkTarget);
426
	// } catch (PartInitException e) {
427
	// PHPUiPlugin.log(e);
428
	// }
429
	// }
430
	//
431
	// /*
432
	// * (non-Javadoc)
433
	// *
434
	// * @see
435
	// * org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks
436
	// * .ILinkHandler
437
	// * #handleInlineJavadocLink(org.eclipse.jdt.core
438
	// * .IModelElement)
439
	// */
440
	// public void handleInlineJavadocLink(IModelElement linkTarget) {
441
	// PHPDocumentationBrowserInformationControlInput hoverInfo = getHoverInfo(
442
	// new IModelElement[] { linkTarget }, null,
443
	// (PHPDocumentationBrowserInformationControlInput) control
444
	// .getInput());
445
	// if (control.hasDelayedInputChangeListener())
446
	// control.notifyDelayedInputChange(hoverInfo);
447
	// else
448
	// control.setInput(hoverInfo);
449
	// }
450
	//
451
	// /*
452
	// * (non-Javadoc)
453
	// *
454
	// * @see
455
	// * org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks
456
	// * .ILinkHandler
457
	// * #handleDeclarationLink(org.eclipse.jdt.core.
458
	// * IModelElement)
459
	// */
460
	// public void handleDeclarationLink(IModelElement linkTarget) {
461
	// control.notifyDelayedInputChange(null);
462
	// control.dispose(); // FIXME: should have protocol to
463
	// // hide, rather than dispose
464
	// try {
465
	// // FIXME: add hover location to editor navigation
466
	// // history?
467
	// JavaUI.openInEditor(linkTarget);
468
	// } catch (PartInitException e) {
469
	// PHPUiPlugin.log(e);
470
	// } catch (ModelException e) {
471
	// PHPUiPlugin.log(e);
472
	// }
473
	// }
474
	//
475
	// /*
476
	// * (non-Javadoc)
477
	// *
478
	// * @see
479
	// * org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks
480
	// * .ILinkHandler#handleExternalLink(java.net.URL,
481
	// * org.eclipse.swt.widgets.Display)
482
	// */
483
	// public boolean handleExternalLink(URL url, Display display) {
484
	// control.notifyDelayedInputChange(null);
485
	// control.dispose(); // FIXME: should have protocol to
486
	// // hide, rather than dispose
487
	//
488
	// // open external links in real browser:
489
	//						OpenBrowserUtil.open(url, display, ""); //$NON-NLS-1$
490
	//
491
	// return true;
492
	// }
493
	//
494
	// public void handleTextSet() {
495
	// }
496
	// }));
497
	// }
498
499
	/**
500
	 * @deprecated see
501
	 *             {@link org.eclipse.jface.text.ITextHover#getHoverInfo(ITextViewer, IRegion)}
502
	 */
503
	public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
504
		PHPDocumentationBrowserInformationControlInput info = (PHPDocumentationBrowserInformationControlInput) getHoverInfo2(
505
				textViewer, hoverRegion);
506
		return info != null ? info.getHtml() : null;
507
	}
76
508
77
		return null;
509
	/*
510
	 * @see
511
	 * org.eclipse.jface.text.ITextHoverExtension2#getHoverInfo2(org.eclipse
512
	 * .jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
513
	 */
514
	public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
515
		return internalGetHoverInfo(textViewer, hoverRegion);
78
	}
516
	}
79
517
80
	@Override
518
	private PHPDocumentationBrowserInformationControlInput internalGetHoverInfo(
81
	protected String getHoverInfo(String nature, IModelElement[] result) {
519
			ITextViewer textViewer, IRegion hoverRegion) {
82
		StringBuffer buffer = new StringBuffer();
520
		IModelElement[] elements = getElementsAt(textViewer, hoverRegion);
83
		int nResults = result.length;
521
		if (elements == null || elements.length == 0)
84
		if (nResults == 0)
85
			return null;
522
			return null;
86
523
524
		String constantValue;
525
		if (elements.length == 1
526
				&& elements[0].getElementType() == IModelElement.FIELD) {
527
			constantValue = getConstantValue((IField) elements[0], hoverRegion);
528
			if (constantValue != null)
529
				constantValue = HTMLPrinter.convertToHTMLContent(constantValue);
530
		} else {
531
			constantValue = null;
532
		}
533
534
		return getHoverInfo(elements, constantValue, null);
535
	}
536
537
	/**
538
	 * Computes the hover info.
539
	 * 
540
	 * @param elements
541
	 *            the resolved elements
542
	 * @param constantValue
543
	 *            a constant value iff result contains exactly 1 constant field,
544
	 *            or <code>null</code>
545
	 * @param previousInput
546
	 *            the previous input, or <code>null</code>
547
	 * @return the HTML hover info for the given element(s) or <code>null</code>
548
	 *         if no information is available
549
	 * @since 3.4
550
	 */
551
	private static PHPDocumentationBrowserInformationControlInput getHoverInfo(
552
			IModelElement[] elements, String constantValue,
553
			PHPDocumentationBrowserInformationControlInput previousInput) {
554
		int nResults = elements.length;
555
		StringBuffer buffer = new StringBuffer();
87
		boolean hasContents = false;
556
		boolean hasContents = false;
88
		if (nResults > 1) {
557
		String base = null;
89
			HTMLPrinter.addSmallHeader(buffer, getInfoText(result[0]));
558
		IModelElement element = null;
90
			HTMLPrinter.addParagraph(buffer, "<hr>"); //$NON-NLS-1$
91
			for (int i = 0; i < result.length; i++) {
92
				// HTMLPrinter.startBulletList(buffer);
93
				IModelElement curr = result[i];
94
				if (curr instanceof IMember) {
95
					IMember member = (IMember) curr;
96
97
					Reader reader;
98
					try {
99
						reader = ScriptDocumentationAccess
100
								.getHTMLContentReader(nature, member, true,
101
										true);
102
103
						// Provide hint why there's no doc
104
						if (reader == null) {
105
							// reader= new
106
							// StringReader(DLTKHoverMessages.ScriptdocHover_noAttachedInformation);
107
							continue;
108
						}
109
559
110
					} catch (ModelException ex) {
560
		int leadingImageWidth = 0;
111
						return null;
112
					}
113
561
114
					if (reader != null) {
562
		if (nResults > 1) {
115
						// HTMLPrinter.addBullet(buffer, getInfoText(curr));
563
116
						// HTMLPrinter.addParagraph(buffer, "<br>");
564
			for (int i = 0; i < elements.length; i++) {
117
						if (hasContents) {
565
				HTMLPrinter.startBulletList(buffer);
118
							HTMLPrinter.addParagraph(buffer, "<hr>"); //$NON-NLS-1$
566
				IModelElement curr = elements[i];
119
						}
567
				if (curr instanceof IMember
120
						HTMLPrinter.addParagraph(buffer, reader);
568
						|| curr.getElementType() == IModelElement.FIELD) {
121
					}
569
					// FIXME: provide links
570
					HTMLPrinter.addBullet(buffer, getInfoText(curr,
571
							constantValue, false));
122
					hasContents = true;
572
					hasContents = true;
123
				}
573
				}
124
				// HTMLPrinter.endBulletList(buffer);
574
				HTMLPrinter.endBulletList(buffer);
125
			}
575
			}
126
576
127
		} else {
577
		} else {
128
578
129
			IModelElement curr = result[0];
579
			element = elements[0];
130
			if (curr instanceof IMember) {
580
			if (element instanceof IMember) {
131
				IMember member = (IMember) curr;
581
				IMember member = (IMember) element;
132
				HTMLPrinter.addSmallHeader(buffer, getInfoText(member));
582
				HTMLPrinter.addSmallHeader(buffer, getInfoText(member,
133
				Reader reader;
583
						constantValue, true));
584
				Reader reader = null;
134
				try {
585
				try {
135
					reader = ScriptDocumentationAccess.getHTMLContentReader(
586
					reader = getHTMLContent(member);
136
							nature, member, true, true);
587
				} catch (ModelException e) {
137
138
					// Provide hint why there's no doc
139
					if (reader == null) {
140
						reader = new StringReader(
141
								ScriptHoverMessages.ScriptdocHover_noAttachedInformation);
142
					}
143
144
				} catch (ModelException ex) {
145
					return null;
146
				}
588
				}
147
589
148
				if (reader != null) {
590
				if (reader != null) {
149
					HTMLPrinter.addParagraph(buffer, reader);
591
					HTMLPrinter.addParagraph(buffer, reader);
150
				}
592
				}
151
				hasContents = true;
593
				hasContents = true;
152
			}/*
594
153
			 * else if (curr.getElementType() == IModelElement.LOCAL_VARIABLE ||
595
			} else if (element.getElementType() == IModelElement.FIELD) {
154
			 * curr.getElementType() == IModelElement.TYPE_PARAMETER) {
596
				HTMLPrinter.addSmallHeader(buffer, getInfoText(element,
155
			 * HTMLPrinter.addSmallHeader(buffer, getInfoText(curr));
597
						constantValue, true));
156
			 * hasContents= true; }
598
				hasContents = true;
157
			 */
599
			}
600
			leadingImageWidth = 20;
158
		}
601
		}
159
602
160
		if (!hasContents)
603
		if (!hasContents)
Lines 163-180 Link Here
163
		if (buffer.length() > 0) {
606
		if (buffer.length() > 0) {
164
			HTMLPrinter.insertPageProlog(buffer, 0, getStyleSheet());
607
			HTMLPrinter.insertPageProlog(buffer, 0, getStyleSheet());
165
			HTMLPrinter.addPageEpilog(buffer);
608
			HTMLPrinter.addPageEpilog(buffer);
166
			return buffer.toString();
609
			return new PHPDocumentationBrowserInformationControlInput(
610
					previousInput, element, buffer.toString(),
611
					leadingImageWidth);
167
		}
612
		}
168
613
169
		return null;
614
		return null;
170
	}
615
	}
171
616
172
	private String getInfoText(IModelElement member) {
617
	private static String getInfoText(IModelElement element,
618
			String constantValue, boolean allowImage) {
619
		StringBuffer label = getInfoText(element);
620
		if (element.getElementType() == IModelElement.FIELD) {
621
			if (constantValue != null) {
622
				label.append(' ');
623
				label.append('=');
624
				label.append(' ');
625
				label.append(constantValue);
626
			}
627
		}
628
629
		String imageName = null;
630
		if (allowImage) {
631
			URL imageUrl = PHPUiPlugin.getDefault().getImagesOnFSRegistry()
632
					.getImageURL(element);
633
			if (imageUrl != null) {
634
				imageName = imageUrl.toExternalForm();
635
			}
636
		}
637
638
		StringBuffer buf = new StringBuffer();
639
		addImageAndLabel(buf, imageName, 16, 16, 2, 2, label.toString(), 20, 2);
640
		return buf.toString();
641
	}
642
643
	/*
644
	 * @since 3.4
645
	 */
646
	private static boolean isFinal(IField field) {
647
		try {
648
			return PHPFlags.isFinal(field.getFlags());
649
		} catch (ModelException e) {
650
			PHPUiPlugin.log(e);
651
			return false;
652
		}
653
	}
654
655
	/**
656
	 * Returns the constant value for the given field.
657
	 * 
658
	 * @param field
659
	 *            the field
660
	 * @param hoverRegion
661
	 *            the hover region
662
	 * @return the constant value for the given field or <code>null</code> if
663
	 *         none
664
	 * @since 3.4
665
	 */
666
	private String getConstantValue(IField field, IRegion hoverRegion) {
667
		if (!isFinal(field))
668
			return null;
669
670
		ISourceModule typeRoot = getEditorInputModelElement();
671
		if (typeRoot == null)
672
			return null;
673
674
		Object constantValue = null;
675
		if (field != null && field.exists()) {
676
			try {
677
				Program unit = SharedASTProvider.getAST(
678
						field.getSourceModule(), SharedASTProvider.WAIT_YES,
679
						null);
680
				ASTNode node = NodeFinder.perform(unit, field.getNameRange()
681
						.getOffset(), field.getNameRange().getLength());
682
				if (node != null && node instanceof Identifier
683
						&& node.getParent() instanceof ConstantDeclaration) {
684
					ConstantDeclaration decl = (ConstantDeclaration) node
685
							.getParent();
686
					if (decl.initializers().size() == 1
687
							&& decl.initializers().get(0) instanceof Scalar) {
688
						Scalar scalar = (Scalar) decl.initializers().get(0);
689
						constantValue = scalar.getStringValue();
690
					}
691
				}
692
			} catch (ModelException e) {
693
			} catch (IOException e) {
694
			}
695
		}
696
697
		if (constantValue == null)
698
			return null;
699
700
		if (constantValue instanceof String) {
701
			StringBuffer result = new StringBuffer();
702
			String stringConstant = (String) constantValue;
703
			if (stringConstant.length() > 80) {
704
				result.append(stringConstant.substring(0, 80));
705
				result.append(ScriptElementLabels.ELLIPSIS_STRING);
706
			} else {
707
				result.append(stringConstant);
708
			}
709
			return result.toString();
710
711
		} else if (constantValue instanceof Integer) {
712
			int intValue = ((Integer) constantValue).intValue();
713
			return formatWithHexValue(constantValue,
714
					"0x" + Integer.toHexString(intValue)); //$NON-NLS-1$
715
		} else {
716
			return constantValue.toString();
717
		}
718
	}
719
720
	/**
721
	 * Creates and returns a formatted message for the given constant with its
722
	 * hex value.
723
	 * 
724
	 * @param constantValue
725
	 *            the constant value
726
	 * @param hexValue
727
	 *            the hex value
728
	 * @return a formatted string with constant and hex values
729
	 * @since 3.4
730
	 */
731
	private static String formatWithHexValue(Object constantValue,
732
			String hexValue) {
733
		return Messages.format(
734
				PHPHoverMessages.JavadocHover_constantValue_hexValue,
735
				new String[] { constantValue.toString(), hexValue });
736
	}
737
738
	/**
739
	 * Returns the Javadoc hover style sheet with the current Javadoc font from
740
	 * the preferences.
741
	 * 
742
	 * @return the updated style sheet
743
	 * @since 3.4
744
	 */
745
	protected static String getStyleSheet() {
746
		if (fgStyleSheet == null)
747
			fgStyleSheet = loadStyleSheet();
748
		String css = fgStyleSheet;
749
		if (css != null) {
750
			FontData fontData = JFaceResources.getFontRegistry().getFontData(
751
					PreferenceConstants.APPEARANCE_DOCUMENTATION_FONT)[0];
752
			css = HTMLPrinter.convertTopLevelFont(css, fontData);
753
		}
754
755
		return css;
756
	}
757
758
	/**
759
	 * Loads and returns the Javadoc hover style sheet.
760
	 * 
761
	 * @return the style sheet, or <code>null</code> if unable to load
762
	 * @since 3.4
763
	 */
764
	private static String loadStyleSheet() {
765
		Bundle bundle = Platform.getBundle(PHPUiPlugin.getPluginId());
766
		URL styleSheetURL = bundle
767
				.getEntry("/PHPDocumentationHoverStyleSheet.css"); //$NON-NLS-1$
768
		if (styleSheetURL != null) {
769
			BufferedReader reader = null;
770
			try {
771
				reader = new BufferedReader(new InputStreamReader(styleSheetURL
772
						.openStream()));
773
				StringBuffer buffer = new StringBuffer(1500);
774
				String line = reader.readLine();
775
				while (line != null) {
776
					buffer.append(line);
777
					buffer.append('\n');
778
					line = reader.readLine();
779
				}
780
				return buffer.toString();
781
			} catch (IOException ex) {
782
				PHPUiPlugin.log(ex);
783
				return ""; //$NON-NLS-1$
784
			} finally {
785
				try {
786
					if (reader != null)
787
						reader.close();
788
				} catch (IOException e) {
789
				}
790
			}
791
		}
792
		return null;
793
	}
794
795
	public static void addImageAndLabel(StringBuffer buf, String imageName,
796
			int imageWidth, int imageHeight, int imageLeft, int imageTop,
797
			String label, int labelLeft, int labelTop) {
798
799
		if (imageName != null) {
800
			StringBuffer imageStyle = new StringBuffer("position: absolute; "); //$NON-NLS-1$
801
			imageStyle.append("width: ").append(imageWidth).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
802
			imageStyle.append("height: ").append(imageHeight).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
803
			imageStyle.append("top: ").append(imageTop).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
804
			imageStyle.append("left: ").append(imageLeft).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
805
806
			buf.append("<!--[if lte IE 6]><![if gte IE 5.5]>\n"); //$NON-NLS-1$
807
			buf.append("<span style=\"").append(imageStyle).append("filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='").append(imageName).append("')\"></span>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
808
			buf.append("<![endif]><![endif]-->\n"); //$NON-NLS-1$
809
810
			buf.append("<!--[if !IE]>-->\n"); //$NON-NLS-1$
811
			buf.append("<img style='").append(imageStyle).append("' src='").append(imageName).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
812
			buf.append("<!--<![endif]-->\n"); //$NON-NLS-1$
813
			buf.append("<!--[if gte IE 7]>\n"); //$NON-NLS-1$
814
			buf.append("<img style='").append(imageStyle).append("' src='").append(imageName).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
815
			buf.append("<![endif]-->\n"); //$NON-NLS-1$
816
		}
817
818
		buf.append("<div style='word-wrap:break-word;"); //$NON-NLS-1$
819
		if (imageName != null) {
820
			buf.append("margin-left: ").append(labelLeft).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
821
			buf.append("margin-top: ").append(labelTop).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
822
		}
823
		buf.append("'>"); //$NON-NLS-1$
824
		buf.append(label);
825
		buf.append("</div>"); //$NON-NLS-1$
826
	}
827
828
	protected static Reader getHTMLContent(IMember curr) throws ModelException {
829
		String html = PHPDocumentationContentAccess.getHTMLContent(curr);
830
		if (html != null) {
831
			return new StringReader(html);
832
		}
833
		return null;
834
		// return ScriptDocumentationAccess.getHTMLContentReader(PHPNature.ID,
835
		// curr, true, true);
836
	}
837
838
	private static StringBuffer getInfoText(IModelElement member) {
173
		long flags = member.getElementType() == IModelElement.FIELD ? LOCAL_VARIABLE_FLAGS
839
		long flags = member.getElementType() == IModelElement.FIELD ? LOCAL_VARIABLE_FLAGS
174
				: LABEL_FLAGS;
840
				: LABEL_FLAGS;
175
		String label = ScriptElementLabels.getDefault().getElementLabel(member,
841
		String label = ScriptElementLabels.getDefault().getElementLabel(member,
176
				flags);
842
				flags);
177
		return TextUtils.escapeHTML(label);
843
		return new StringBuffer(label);
178
	}
844
	}
179
180
}
845
}
(-)src/org/eclipse/php/internal/ui/editor/hover/PHPHoverMessages.java (+54 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.editor.hover;
2
3
import org.eclipse.osgi.util.NLS;
4
5
/**
6
 * Helper class to get NLSed messages.
7
 */
8
final class PHPHoverMessages extends NLS {
9
10
	private static final String BUNDLE_NAME = PHPHoverMessages.class.getName();
11
12
	private PHPHoverMessages() {
13
		// Do not instantiate
14
	}
15
16
	public static String AbstractAnnotationHover_action_configureAnnotationPreferences;
17
	public static String AbstractAnnotationHover_message_singleQuickFix;
18
	public static String AbstractAnnotationHover_message_multipleQuickFix;
19
20
	public static String JavadocHover_back;
21
	public static String JavadocHover_back_toElement_toolTip;
22
	public static String JavadocHover_back_toolTip;
23
	public static String JavadocHover_noAttachments;
24
	public static String JavadocHover_noAttachedJavadoc;
25
	public static String JavadocHover_noAttachedSource;
26
	public static String JavadocHover_noInformation;
27
	public static String JavadocHover_constantValue_hexValue;
28
	public static String JavadocHover_error_gettingJavadoc;
29
	public static String JavadocHover_forward;
30
	public static String JavadocHover_forward_toElement_toolTip;
31
	public static String JavadocHover_forward_toolTip;
32
	public static String JavadocHover_openDeclaration;
33
	public static String JavadocHover_showInJavadoc;
34
35
	public static String JavaTextHover_createTextHover;
36
37
	public static String NoBreakpointAnnotation_addBreakpoint;
38
39
	public static String NLSStringHover_NLSStringHover_missingKeyWarning;
40
	public static String NLSStringHover_NLSStringHover_PropertiesFileNotDetectedWarning;
41
	public static String NLSStringHover_open_in_properties_file;
42
	public static String ProblemHover_action_configureProblemSeverity;
43
44
	public static String ProblemHover_chooseSettingsTypeDialog_button_cancel;
45
	public static String ProblemHover_chooseSettingsTypeDialog_button_project;
46
	public static String ProblemHover_chooseSettingsTypeDialog_button_workspace;
47
	public static String ProblemHover_chooseSettingsTypeDialog_checkBox_dontShowAgain;
48
	public static String ProblemHover_chooseSettingsTypeDialog_message;
49
	public static String ProblemHover_chooseSettingsTypeDialog_title;
50
51
	static {
52
		NLS.initializeMessages(BUNDLE_NAME, PHPHoverMessages.class);
53
	}
54
}
(-)src/org/eclipse/php/internal/ui/editor/hover/PHPHoverMessages.properties (+44 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2000, 2009 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
12
AbstractAnnotationHover_action_configureAnnotationPreferences= Configure Annotation Preferences
13
AbstractAnnotationHover_message_singleQuickFix= 1 quick fix available:
14
AbstractAnnotationHover_message_multipleQuickFix= {0} quick fixes available:
15
16
JavaTextHover_createTextHover= Could not create Java text hover
17
18
NoBreakpointAnnotation_addBreakpoint= Add a breakpoint
19
20
NLSStringHover_NLSStringHover_PropertiesFileNotDetectedWarning= The properties file could not be detected
21
NLSStringHover_NLSStringHover_missingKeyWarning= <b>Warning:</b> The key is missing!
22
NLSStringHover_open_in_properties_file=Open in Properties File
23
JavadocHover_back= Back
24
JavadocHover_back_toElement_toolTip=Back to {0}
25
JavadocHover_back_toolTip=Back
26
JavadocHover_noAttachments= <em>Note: This element neither has attached source nor attached Javadoc and hence no Javadoc could be found.</em>
27
JavadocHover_noAttachedSource= <em>Note: This element has no attached source and the Javadoc could not be found in the attached Javadoc.</em>
28
JavadocHover_noAttachedJavadoc= <em>Note: This element has no attached Javadoc and the Javadoc could not be found in the attached source.</em>
29
JavadocHover_noInformation= <em>Note: The Javadoc for this element could neither be found in the attached source nor the attached Javadoc.</em>
30
# The first parameter is the constant value string and the second is its hex representation 
31
JavadocHover_constantValue_hexValue={0} [{1}]
32
JavadocHover_error_gettingJavadoc= <em>Note: An exception occurred while getting the Javadoc. See log for details.</em>
33
JavadocHover_forward= Forward
34
JavadocHover_forward_toElement_toolTip=Forward to {0}
35
JavadocHover_forward_toolTip=Forward
36
JavadocHover_openDeclaration= Open Declaration
37
JavadocHover_showInJavadoc= Show in Javadoc View
38
ProblemHover_action_configureProblemSeverity=Configure Problem Severity
39
ProblemHover_chooseSettingsTypeDialog_button_cancel=Cancel
40
ProblemHover_chooseSettingsTypeDialog_button_project=Configure &Project
41
ProblemHover_chooseSettingsTypeDialog_button_workspace=Configure &Workspace
42
ProblemHover_chooseSettingsTypeDialog_checkBox_dontShowAgain=&Always configure the workspace settings
43
ProblemHover_chooseSettingsTypeDialog_message=The project ''{0}'' does not have any project specific problem severity settings yet.\n\nDo you want to create and configure the project settings or do you want to configure the workspace settings?
44
ProblemHover_chooseSettingsTypeDialog_title=Configure Problem Severity
(-)src/org/eclipse/php/internal/ui/editor/hover/PHPTextHoverProxy.java (-6 / +14 lines)
Lines 11-29 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.php.internal.ui.editor.hover;
12
package org.eclipse.php.internal.ui.editor.hover;
13
13
14
import org.eclipse.dltk.internal.ui.text.hover.AbstractScriptEditorTextHover;
15
import org.eclipse.jface.preference.IPreferenceStore;
14
import org.eclipse.jface.preference.IPreferenceStore;
16
import org.eclipse.jface.text.IInformationControlCreator;
15
import org.eclipse.jface.text.*;
17
import org.eclipse.jface.text.IRegion;
18
import org.eclipse.jface.text.ITextHoverExtension;
19
import org.eclipse.jface.text.ITextViewer;
20
import org.eclipse.jface.text.information.IInformationProviderExtension2;
16
import org.eclipse.jface.text.information.IInformationProviderExtension2;
21
import org.eclipse.php.internal.ui.text.hover.PHPEditorTextHoverDescriptor;
17
import org.eclipse.php.internal.ui.text.hover.PHPEditorTextHoverDescriptor;
22
import org.eclipse.php.ui.editor.hover.IHoverMessageDecorator;
18
import org.eclipse.php.ui.editor.hover.IHoverMessageDecorator;
23
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
19
import org.eclipse.php.ui.editor.hover.IPHPTextHover;
24
import org.eclipse.ui.IEditorPart;
20
import org.eclipse.ui.IEditorPart;
25
21
26
public class PHPTextHoverProxy extends AbstractScriptEditorTextHover implements
22
public class PHPTextHoverProxy extends AbstractPHPEditorTextHover implements
27
		IPHPTextHover, ITextHoverExtension, IInformationProviderExtension2 {
23
		IPHPTextHover, ITextHoverExtension, IInformationProviderExtension2 {
28
24
29
	private PHPEditorTextHoverDescriptor fHoverDescriptor;
25
	private PHPEditorTextHoverDescriptor fHoverDescriptor;
Lines 75-80 Link Here
75
		return null;
71
		return null;
76
	}
72
	}
77
73
74
	public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
75
		if (ensureHoverCreated()) {
76
			if (fHover instanceof ITextHoverExtension2)
77
				return ((ITextHoverExtension2) fHover).getHoverInfo2(
78
						textViewer, hoverRegion);
79
			else
80
				return fHover.getHoverInfo(textViewer, hoverRegion);
81
		}
82
83
		return null;
84
	}
85
78
	private boolean ensureHoverCreated() {
86
	private boolean ensureHoverCreated() {
79
		if (!isEnabled() || fHoverDescriptor == null)
87
		if (!isEnabled() || fHoverDescriptor == null)
80
			return false;
88
			return false;
(-)src/org/eclipse/php/internal/ui/viewsupport/ImagesOnFileSystemRegistry.java (+125 lines)
Added Link Here
1
package org.eclipse.php.internal.ui.viewsupport;
2
3
import java.io.File;
4
import java.net.MalformedURLException;
5
import java.net.URL;
6
import java.util.HashMap;
7
8
import org.eclipse.dltk.core.IModelElement;
9
import org.eclipse.dltk.ui.ScriptElementImageProvider;
10
import org.eclipse.jface.resource.ImageDescriptor;
11
import org.eclipse.php.internal.ui.PHPUiPlugin;
12
import org.eclipse.swt.SWT;
13
import org.eclipse.swt.graphics.ImageData;
14
import org.eclipse.swt.graphics.ImageLoader;
15
16
/**
17
 * Image registry that keeps its images on the local file system.
18
 * 
19
 * @since 3.4
20
 */
21
public class ImagesOnFileSystemRegistry {
22
23
	private static final String IMAGE_DIR = "pdt-images"; //$NON-NLS-1$
24
25
	private HashMap fURLMap;
26
	private final File fTempDir;
27
	private final ScriptElementImageProvider fImageProvider;
28
	private int fImageCount;
29
30
	public ImagesOnFileSystemRegistry() {
31
		fURLMap = new HashMap();
32
		fTempDir = getTempDir();
33
		fImageProvider = new ScriptElementImageProvider();
34
		fImageCount = 0;
35
	}
36
37
	private File getTempDir() {
38
		try {
39
			File imageDir = PHPUiPlugin.getDefault().getStateLocation().append(
40
					IMAGE_DIR).toFile();
41
			if (imageDir.exists()) {
42
				// has not been deleted on previous shutdown
43
				delete(imageDir);
44
			}
45
			if (!imageDir.exists()) {
46
				imageDir.mkdir();
47
			}
48
			if (!imageDir.isDirectory()) {
49
				PHPUiPlugin
50
						.logErrorMessage("Failed to create image directory " + imageDir.toString()); //$NON-NLS-1$
51
				return null;
52
			}
53
			return imageDir;
54
		} catch (IllegalStateException e) {
55
			// no state location
56
			return null;
57
		}
58
	}
59
60
	private void delete(File file) {
61
		if (file.isDirectory()) {
62
			File[] listFiles = file.listFiles();
63
			for (int i = 0; i < listFiles.length; i++) {
64
				delete(listFiles[i]);
65
			}
66
		}
67
		file.delete();
68
	}
69
70
	public URL getImageURL(IModelElement element) {
71
		ImageDescriptor descriptor = fImageProvider.getScriptImageDescriptor(
72
				element, ScriptElementImageProvider.OVERLAY_ICONS
73
						| ScriptElementImageProvider.SMALL_ICONS);
74
		if (descriptor == null)
75
			return null;
76
		return getImageURL(descriptor);
77
	}
78
79
	public URL getImageURL(ImageDescriptor descriptor) {
80
		if (fTempDir == null)
81
			return null;
82
83
		URL url = (URL) fURLMap.get(descriptor);
84
		if (url != null)
85
			return url;
86
87
		File imageFile = getNewFile();
88
		ImageData imageData = descriptor.getImageData();
89
		if (imageData == null) {
90
			return null;
91
		}
92
93
		ImageLoader loader = new ImageLoader();
94
		loader.data = new ImageData[] { imageData };
95
		loader.save(imageFile.getAbsolutePath(), SWT.IMAGE_PNG);
96
97
		try {
98
			url = imageFile.toURI().toURL();
99
			fURLMap.put(descriptor, url);
100
			return url;
101
		} catch (MalformedURLException e) {
102
			PHPUiPlugin.log(e);
103
		}
104
		return null;
105
	}
106
107
	private File getNewFile() {
108
		File file;
109
		do {
110
			file = new File(fTempDir, String.valueOf(getImageCount()) + ".png"); //$NON-NLS-1$
111
		} while (file.exists());
112
		return file;
113
	}
114
115
	private synchronized int getImageCount() {
116
		return fImageCount++;
117
	}
118
119
	public void dispose() {
120
		if (fTempDir != null) {
121
			delete(fTempDir);
122
		}
123
		fURLMap = null;
124
	}
125
}

Return to bug 311734