Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: af578af4f1942c162d53ada27112cc1cfa432a20 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*******************************************************************************
 * Copyright (c) 2005, 2020 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Jens Lukowski/Innoopract - initial renaming/restructuring
 *     
 *******************************************************************************/
package org.eclipse.wst.sse.ui.internal.taginfo;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextHoverExtension;
import org.eclipse.jface.text.ITextHoverExtension2;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
import org.eclipse.wst.sse.ui.internal.ExtendedConfigurationBuilder;
import org.eclipse.wst.sse.ui.internal.Logger;
import org.eclipse.wst.sse.ui.internal.SSEUIPlugin;
import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames;

/**
 * Provides the best hover help documentation (by using other hover help
 * processors) Priority of hover help processors is: ProblemHoverProcessor,
 * TagInfoProcessor, AnnotationHoverProcessor
 */
public class BestMatchHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 {
	/** Current best match text hover */
	private ITextHover fBestMatchHover;
	/**
	 * Documentation / Information hovers
	 */
	private ITextHover[] fTagInfoHovers;
	/** List of text hovers to consider in best match */
	private List<ITextHover> fTextHovers;
	/**
	 * Partition type for which to create text hovers (when deferred for
	 * performance)
	 */
	private String fPartitionType;

	private ITextHover controlCreatorProvider;

	private Set<IContentType> fDetectedContentTypes;

	public BestMatchHover(ITextHover infoTagHover) {
		this(new ITextHover[]{infoTagHover});
	}

	public BestMatchHover(ITextHover[] infoTagHovers) {
		fTagInfoHovers = infoTagHovers;
	}

	public BestMatchHover(String partitionType) {
		fPartitionType = partitionType;
	}

	/**
	 * Create a list of text hovers applicable to this best match hover
	 * processor
	 * 
	 * @return List of ITextHover - in abstract class this is empty list
	 */
	private List<ITextHover> createTextHoversList(ITextViewer textViewer) {
		List<ITextHover> hoverList = new ArrayList<>();
		// if currently debugging, then add the debug hover to the list of
		// best match
		if (Logger.isTracing(DebugInfoHoverProcessor.TRACEFILTER)) {
			hoverList.add(new DebugInfoHoverProcessor());
		}

		hoverList.add(new ProblemAnnotationHoverProcessor());
		
		if (fPartitionType != null && fTagInfoHovers == null) {
			List<ITextHover> extendedTextHover = ExtendedConfigurationBuilder.getInstance().getConfigurations(ExtendedConfigurationBuilder.DOCUMENTATIONTEXTHOVER, fPartitionType);
			fTagInfoHovers = extendedTextHover.toArray(new ITextHover[extendedTextHover.size()]);
		}
		if (fTagInfoHovers != null) {
			for (int i = 0; i < fTagInfoHovers.length; i++) {
				hoverList.add(fTagInfoHovers[i]);
			}
		}
		hoverList.add(new AnnotationHoverProcessor());

		if (SSEUIPlugin.getInstance().getPreferenceStore().getBoolean(EditorPreferenceNames.PREFER_GENERIC_HOVER)) {
			Set<IContentType> detectedContentTypes = detectContentTypes(textViewer);
			if (textViewer instanceof ISourceViewer && detectedContentTypes != null) {
				List<ITextHover> genericHovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers((ISourceViewer) textViewer, null, detectedContentTypes);
				hoverList.addAll(0, genericHovers);
			}
		}
		return hoverList;
	}

	private Set<IContentType> detectContentTypes(ITextViewer viewer) {
		if (fDetectedContentTypes == null) {
			Set<IContentType> types = new HashSet<>();
			IDocument currentDocument = viewer.getDocument();
			if (currentDocument != null) {
				ITextFileBuffer textFileBuffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(currentDocument);
				if (textFileBuffer != null) {
					IContentType[] foundTypes = Platform.getContentTypeManager().findContentTypesFor(textFileBuffer.getLocation().lastSegment());
					for (int i = 0; i < foundTypes.length; i++) {
						IContentType type = foundTypes[i];
						while (type != null) {
							types.add(type);
							type = type.getBaseType();
						}
					}
				}
			}
			fDetectedContentTypes = types;
		}
		return fDetectedContentTypes;
	}

	public IInformationControlCreator getHoverControlCreator() {
		IInformationControlCreator creator = null;

		if (controlCreatorProvider instanceof ITextHoverExtension) {
			creator = ((ITextHoverExtension) controlCreatorProvider).getHoverControlCreator();
		}
		else if (fBestMatchHover instanceof ITextHoverExtension) {
			creator = ((ITextHoverExtension) fBestMatchHover).getHoverControlCreator();
		}
		return creator;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer,
	 *      org.eclipse.jface.text.IRegion)
	 */
	public String getHoverInfo(ITextViewer viewer, IRegion hoverRegion) {
		String displayText = null;
		controlCreatorProvider = null;
		// already have a best match hover picked out from getHoverRegion call
		if (fBestMatchHover != null) {
			displayText = fBestMatchHover.getHoverInfo(viewer, hoverRegion);
		}
		// either had no best match hover or best match hover returned null
		if (displayText == null) {
			// go through list of text hovers and return first display string
			Iterator<ITextHover> i = getTextHovers(viewer).iterator();
			while ((i.hasNext()) && (displayText == null)) {
				ITextHover hover = i.next();
				displayText = hover.getHoverInfo(viewer, hoverRegion);
				if (displayText != null) {
					controlCreatorProvider = hover;
				}
			}
		}
		else {
			controlCreatorProvider = fBestMatchHover;
		}
		return displayText;
	}

	public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
		Object information = null;
		controlCreatorProvider = null;
		// already have a best match hover picked out from getHoverRegion call
		if (fBestMatchHover instanceof ITextHoverExtension2) {
			information = ((ITextHoverExtension2 ) fBestMatchHover).getHoverInfo2(textViewer, hoverRegion);
		}
		else if (fBestMatchHover != null) {
			information = fBestMatchHover.getHoverInfo(textViewer, hoverRegion);
		}
		// either had no best match hover or best match hover returned null
		if (information == null) {
			// go through list of text hovers and return first display string
			Iterator<ITextHover> i = getTextHovers(textViewer).iterator();
			while ((i.hasNext()) && (information == null)) {
				ITextHover hover = i.next();
				if (hover == fBestMatchHover)
					continue;
				if (hover instanceof ITextHoverExtension2) {
					information = ((ITextHoverExtension2) hover).getHoverInfo2(textViewer, hoverRegion);
				}
				else {
					information = hover.getHoverInfo(textViewer, hoverRegion);
				}
				if (information != null) {
					controlCreatorProvider = hover;
				}
			}
		}
		else {
			controlCreatorProvider = fBestMatchHover;
		}
		return information;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer,
	 *      int)
	 */
	public IRegion getHoverRegion(ITextViewer viewer, int offset) {
		IRegion hoverRegion = null;

		// go through list of text hovers and return first hover region
		ITextHover hover = null;
		Iterator<ITextHover> i = getTextHovers(viewer).iterator();
		while ((i.hasNext()) && (hoverRegion == null)) {
			hover = i.next();
			hoverRegion = hover.getHoverRegion(viewer, offset);
		}

		// store the text hover processor that found region
		if (hoverRegion != null)
			fBestMatchHover = hover;
		else
			fBestMatchHover = null;

		return hoverRegion;
	}

	private List<ITextHover> getTextHovers(ITextViewer viewer) {
		if (fTextHovers == null) {
			fTextHovers = createTextHoversList(viewer);
		}
		return fTextHovers;
	}
}

Back to the top