1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 
12 package net.sourceforge.phpdt.internal.ui.text.java.hover;
13 
14 import java.text.Collator;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.StringTokenizer;
20 
21 import net.sourceforge.phpdt.ui.PreferenceConstants;
22 import net.sourceforge.phpdt.ui.text.java.hover.IJavaEditorTextHover;
23 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
24 import net.sourceforge.phpeclipse.phpeditor.EditorUtility;
25 
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IConfigurationElement;
28 import org.eclipse.core.runtime.IExtensionRegistry;
29 import org.eclipse.core.runtime.IStatus;
30 import org.eclipse.core.runtime.Platform;
31 import org.eclipse.core.runtime.Status;
32 import org.eclipse.jface.text.Assert;
33 import org.eclipse.swt.SWT;
34 import org.osgi.framework.Bundle;
35 
36 /**
37  * Describes a Java editor text hover.
38  *
39  * @since 2.1
40  */
41 public class JavaEditorTextHoverDescriptor implements Comparable {
42 
43 	private static final String JAVA_EDITOR_TEXT_HOVER_EXTENSION_POINT = "net.sourceforge.phpeclipse.phpEditorTextHovers"; //$NON-NLS-1$
44 
45 	private static final String HOVER_TAG = "hover"; //$NON-NLS-1$
46 
47 	private static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$
48 
49 	private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
50 
51 	private static final String LABEL_ATTRIBUTE = "label"; //$NON-NLS-1$
52 
53 	private static final String ACTIVATE_PLUG_IN_ATTRIBUTE = "activate"; //$NON-NLS-1$
54 
55 	private static final String DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$
56 
57 	public static final String NO_MODIFIER = "0"; //$NON-NLS-1$
58 
59 	public static final String DISABLED_TAG = "!"; //$NON-NLS-1$
60 
61 	public static final String VALUE_SEPARATOR = ";"; //$NON-NLS-1$
62 
63 	private int fStateMask;
64 
65 	private String fModifierString;
66 
67 	private boolean fIsEnabled;
68 
69 	private IConfigurationElement fElement;
70 
71 	/**
72 	 * Returns all Java editor text hovers contributed to the workbench.
73 	 */
getContributedHovers()74 	public static JavaEditorTextHoverDescriptor[] getContributedHovers() {
75 		IExtensionRegistry registry = Platform.getExtensionRegistry();
76 		IConfigurationElement[] elements = registry
77 				.getConfigurationElementsFor(JAVA_EDITOR_TEXT_HOVER_EXTENSION_POINT);
78 		JavaEditorTextHoverDescriptor[] hoverDescs = createDescriptors(elements);
79 		initializeFromPreferences(hoverDescs);
80 		return hoverDescs;
81 	}
82 
83 	/**
84 	 * Computes the state mask for the given modifier string.
85 	 *
86 	 * @param modifiers
87 	 *            the string with the modifiers, separated by '+', '-', ';', ','
88 	 *            or '.'
89 	 * @return the state mask or -1 if the input is invalid
90 	 */
computeStateMask(String modifiers)91 	public static int computeStateMask(String modifiers) {
92 		if (modifiers == null)
93 			return -1;
94 
95 		if (modifiers.length() == 0)
96 			return SWT.NONE;
97 
98 		int stateMask = 0;
99 		StringTokenizer modifierTokenizer = new StringTokenizer(modifiers,
100 				",;.:+-* "); //$NON-NLS-1$
101 		while (modifierTokenizer.hasMoreTokens()) {
102 			int modifier = EditorUtility
103 					.findLocalizedModifier(modifierTokenizer.nextToken());
104 			if (modifier == 0 || (stateMask & modifier) == modifier)
105 				return -1;
106 			stateMask = stateMask | modifier;
107 		}
108 		return stateMask;
109 	}
110 
111 	/**
112 	 * Creates a new Java Editor text hover descriptor from the given
113 	 * configuration element.
114 	 */
JavaEditorTextHoverDescriptor(IConfigurationElement element)115 	private JavaEditorTextHoverDescriptor(IConfigurationElement element) {
116 		Assert.isNotNull(element);
117 		fElement = element;
118 	}
119 
120 	/**
121 	 * Creates the Java editor text hover.
122 	 */
createTextHover()123 	public IJavaEditorTextHover createTextHover() {
124 		String pluginId = fElement.getDeclaringExtension().getNamespace();
125 		boolean isHoversPlugInActivated = Platform.getBundle(pluginId)
126 				.getState() == Bundle.ACTIVE;
127 		if (isHoversPlugInActivated || canActivatePlugIn()) {
128 			try {
129 				return (IJavaEditorTextHover) fElement
130 						.createExecutableExtension(CLASS_ATTRIBUTE);
131 			} catch (CoreException x) {
132 				PHPeclipsePlugin.log(new Status(IStatus.ERROR, PHPeclipsePlugin
133 						.getPluginId(), 0, JavaHoverMessages
134 						.getString("JavaTextHover.createTextHover"), null)); //$NON-NLS-1$
135 			}
136 		}
137 
138 		return null;
139 	}
140 
141 	// ---- XML Attribute accessors
142 	// ---------------------------------------------
143 
144 	/**
145 	 * Returns the hover's id.
146 	 */
getId()147 	public String getId() {
148 		return fElement.getAttribute(ID_ATTRIBUTE);
149 	}
150 
151 	/**
152 	 * Returns the hover's class name.
153 	 */
getHoverClassName()154 	public String getHoverClassName() {
155 		return fElement.getAttribute(CLASS_ATTRIBUTE);
156 	}
157 
158 	/**
159 	 * Returns the hover's label.
160 	 */
getLabel()161 	public String getLabel() {
162 		String label = fElement.getAttribute(LABEL_ATTRIBUTE);
163 		if (label != null)
164 			return label;
165 
166 		// Return simple class name
167 		label = getHoverClassName();
168 		int lastDot = label.lastIndexOf('.');
169 		if (lastDot >= 0 && lastDot < label.length() - 1)
170 			return label.substring(lastDot + 1);
171 		else
172 			return label;
173 	}
174 
175 	/**
176 	 * Returns the hover's description.
177 	 *
178 	 * @return the hover's description or <code>null</code> if not provided
179 	 */
getDescription()180 	public String getDescription() {
181 		return fElement.getAttribute(DESCRIPTION_ATTRIBUTE);
182 	}
183 
canActivatePlugIn()184 	public boolean canActivatePlugIn() {
185 		return Boolean.valueOf(
186 				fElement.getAttribute(ACTIVATE_PLUG_IN_ATTRIBUTE))
187 				.booleanValue();
188 	}
189 
equals(Object obj)190 	public boolean equals(Object obj) {
191 		if (obj == null || !obj.getClass().equals(this.getClass())
192 				|| getId() == null)
193 			return false;
194 		return getId().equals(((JavaEditorTextHoverDescriptor) obj).getId());
195 	}
196 
hashCode()197 	public int hashCode() {
198 		return getId().hashCode();
199 	}
200 
201 	/*
202 	 * Implements a method from IComparable
203 	 */
compareTo(Object o)204 	public int compareTo(Object o) {
205 		return Collator.getInstance().compare(getLabel(),
206 				((JavaEditorTextHoverDescriptor) o).getLabel());
207 	}
208 
209 	// /**
210 	// * @param descriptor a JavaEditorTextHoverDescriptor
211 	// * @return <code>true</code> if this contributed hover depends on the
212 	// other one
213 	// */
214 	// public boolean dependsOn(JavaEditorTextHoverDescriptor descriptor) {
215 	// if (descriptor == null)
216 	// return false;
217 	//
218 	// IPluginDescriptor thisPluginDescriptor=
219 	// fElement.getDeclaringExtension().getDeclaringPluginDescriptor();
220 	// IPluginDescriptor otherPluginDescriptor=
221 	// descriptor.fElement.getDeclaringExtension().getDeclaringPluginDescriptor();
222 	// return dependsOn(thisPluginDescriptor, otherPluginDescriptor);
223 	// }
224 
225 	// private boolean dependsOn(IPluginDescriptor descriptor0,
226 	// IPluginDescriptor descriptor1) {
227 	//
228 	// IPluginRegistry registry= Platform.getPluginRegistry();
229 	// IPluginPrerequisite[] prerequisites=
230 	// descriptor0.getPluginPrerequisites();
231 	//
232 	// for (int i= 0; i < prerequisites.length; i++) {
233 	// IPluginPrerequisite prerequisite= prerequisites[i];
234 	// String id= prerequisite.getUniqueIdentifier();
235 	// IPluginDescriptor descriptor= registry.getPluginDescriptor(id);
236 	//
237 	// if (descriptor != null && (descriptor.equals(descriptor1) ||
238 	// dependsOn(descriptor, descriptor1)))
239 	// return true;
240 	// }
241 	//
242 	// return false;
243 	// }
244 
createDescriptors( IConfigurationElement[] elements)245 	private static JavaEditorTextHoverDescriptor[] createDescriptors(
246 			IConfigurationElement[] elements) {
247 		List result = new ArrayList(elements.length);
248 		for (int i = 0; i < elements.length; i++) {
249 			IConfigurationElement element = elements[i];
250 			if (HOVER_TAG.equals(element.getName())) {
251 				JavaEditorTextHoverDescriptor desc = new JavaEditorTextHoverDescriptor(
252 						element);
253 				result.add(desc);
254 			}
255 		}
256 		Collections.sort(result);
257 		return (JavaEditorTextHoverDescriptor[]) result
258 				.toArray(new JavaEditorTextHoverDescriptor[result.size()]);
259 	}
260 
initializeFromPreferences( JavaEditorTextHoverDescriptor[] hovers)261 	private static void initializeFromPreferences(
262 			JavaEditorTextHoverDescriptor[] hovers) {
263 		String compiledTextHoverModifiers = PHPeclipsePlugin.getDefault()
264 				.getPreferenceStore().getString(
265 						PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS);
266 
267 		StringTokenizer tokenizer = new StringTokenizer(
268 				compiledTextHoverModifiers, VALUE_SEPARATOR);
269 		HashMap idToModifier = new HashMap(tokenizer.countTokens() / 2);
270 
271 		while (tokenizer.hasMoreTokens()) {
272 			String id = tokenizer.nextToken();
273 			if (tokenizer.hasMoreTokens())
274 				idToModifier.put(id, tokenizer.nextToken());
275 		}
276 
277 		String compiledTextHoverModifierMasks = PHPeclipsePlugin.getDefault()
278 				.getPreferenceStore().getString(
279 						PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS);
280 
281 		tokenizer = new StringTokenizer(compiledTextHoverModifierMasks,
282 				VALUE_SEPARATOR);
283 		HashMap idToModifierMask = new HashMap(tokenizer.countTokens() / 2);
284 
285 		while (tokenizer.hasMoreTokens()) {
286 			String id = tokenizer.nextToken();
287 			if (tokenizer.hasMoreTokens())
288 				idToModifierMask.put(id, tokenizer.nextToken());
289 		}
290 
291 		for (int i = 0; i < hovers.length; i++) {
292 			String modifierString = (String) idToModifier
293 					.get(hovers[i].getId());
294 			boolean enabled = true;
295 			if (modifierString == null)
296 				modifierString = DISABLED_TAG;
297 
298 			if (modifierString.startsWith(DISABLED_TAG)) {
299 				enabled = false;
300 				modifierString = modifierString.substring(1);
301 			}
302 
303 			if (modifierString.equals(NO_MODIFIER))
304 				modifierString = ""; //$NON-NLS-1$
305 
306 			hovers[i].fModifierString = modifierString;
307 			hovers[i].fIsEnabled = enabled;
308 			hovers[i].fStateMask = computeStateMask(modifierString);
309 			if (hovers[i].fStateMask == -1) {
310 				// Fallback: use stored modifier masks
311 				try {
312 					hovers[i].fStateMask = Integer
313 							.parseInt((String) idToModifierMask.get(hovers[i]
314 									.getId()));
315 				} catch (NumberFormatException ex) {
316 					hovers[i].fStateMask = -1;
317 				}
318 				// Fix modifier string
319 				int stateMask = hovers[i].fStateMask;
320 				if (stateMask == -1)
321 					hovers[i].fModifierString = ""; //$NON-NLS-1$
322 				else
323 					hovers[i].fModifierString = EditorUtility
324 							.getModifierString(stateMask);
325 			}
326 		}
327 	}
328 
329 	/**
330 	 * Returns the configured modifier getStateMask for this hover.
331 	 *
332 	 * @return the hover modifier stateMask or -1 if no hover is configured
333 	 */
getStateMask()334 	public int getStateMask() {
335 		return fStateMask;
336 	}
337 
338 	/**
339 	 * Returns the modifier String as set in the preference store.
340 	 *
341 	 * @return the modifier string
342 	 */
getModifierString()343 	public String getModifierString() {
344 		return fModifierString;
345 	}
346 
347 	/**
348 	 * Returns whether this hover is enabled or not.
349 	 *
350 	 * @return <code>true</code> if enabled
351 	 */
isEnabled()352 	public boolean isEnabled() {
353 		return fIsEnabled;
354 	}
355 
356 	/**
357 	 * Returns this hover descriptors configuration element.
358 	 *
359 	 * @return the configuration element
360 	 * @since 3.0
361 	 */
getConfigurationElement()362 	public IConfigurationElement getConfigurationElement() {
363 		return fElement;
364 	}
365 }
366