--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.ui.propertiesfileeditor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.text.StringCharacterIterator;
+import java.util.Properties;
+
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPartitioningException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension3;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IStorageEditorInput;
+
+import org.eclipse.ui.texteditor.IEditorStatusLine;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+
+/**
+ * Properties key hyperlink detector.
+ * <p>
+ * XXX: This does not work for properties files coming from a JAR due to missing J Core
+ * functionality. For details see http://bugs.eclipse.org/22376
+ * </p>
+ *
+ * @since 3.1
+ */
+public class PropertyKeyHyperlinkDetector extends AbstractHyperlinkDetector {
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean)
+ */
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
+ ITextEditor textEditor= (ITextEditor)getAdapter(ITextEditor.class);
+ if (region == null || textEditor == null)
+ return null;
+
+ IEditorSite site= textEditor.getEditorSite();
+ if (site == null)
+ return null;
+
+ int offset= region.getOffset();
+ if (!checkEnabled(textEditor, offset))
+ return null;
+
+ ITypedRegion partition= null;
+ try {
+ IStorageEditorInput storageEditorInput= (IStorageEditorInput)textEditor.getEditorInput();
+ IDocument document= textEditor.getDocumentProvider().getDocument(storageEditorInput);
+ if (document instanceof IDocumentExtension3)
+ partition= ((IDocumentExtension3)document).getPartition(IPropertiesFilePartitions.PROPERTIES_FILE_PARTITIONING, offset, false);
+
+ // Check whether it is the correct partition
+ if (partition == null || !IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())) {
+ return null;
+ }
+
+ // Check whether the partition covers the selection
+ if (offset + region.getLength() > partition.getOffset() + partition.getLength()) {
+ return null;
+ }
+
+ // Extract the key from the partition (which contains key and assignment
+ String key= document.get(partition.getOffset(), partition.getLength());
+
+ String realKey= key.trim();
+ int delta= key.indexOf(realKey);
+
+ String unicodeKey= getUnicodeString(realKey);
+ // Check whether the key is valid
+ Properties properties= new Properties();
+ properties.load(new ByteArrayInputStream(document.get().getBytes()));
+ if (properties.getProperty(unicodeKey) == null) {
+ return null;
+ }
+
+ return new PropertyKeyHyperlink[] { new PropertyKeyHyperlink(new Region(partition.getOffset() + delta, realKey.length()), realKey, textEditor) };
+
+ } catch (BadLocationException ex) {
+ return null;
+ } catch (BadPartitioningException ex) {
+ return null;
+ } catch (IOException ex) {
+ return null;
+ } catch (IllegalArgumentException ex) {
+ showErrorInStatusLine(ex.getLocalizedMessage(), textEditor);
+ return null;
+ }
+ }
+
+ private String getUnicodeString(String key) {
+ StringCharacterIterator iter= new StringCharacterIterator(key);
+ StringBuffer result= new StringBuffer();
+ while (iter.getIndex() < iter.getEndIndex()) {
+ char c= iter.current();
+ if (c == '\\') {
+ iter.next();
+ c= iter.current();
+ if (c == 'u') {
+ StringBuffer unicode= new StringBuffer();
+ unicode.append(iter.next());
+ unicode.append(iter.next());
+ unicode.append(iter.next());
+ unicode.append(iter.next());
+ c= (char)Integer.parseInt(unicode.toString(), 16);
+ }
+ }
+ result.append(c);
+ iter.next();
+ }
+ return result.toString();
+ }
+
+ private boolean checkEnabled(ITextEditor textEditor, int offset) {
+ if (offset < 0)
+ return false;
+
+ // XXX: Must be changed to IStorageEditorInput once support for JARs is available (see class Javadoc for details)
+ return textEditor.getEditorInput() instanceof IFileEditorInput;
+ }
+
+ private void showErrorInStatusLine(final String message, ITextEditor textEditor) {
+ Display display= textEditor.getEditorSite().getShell().getDisplay();
+ display.beep();
+ final IEditorStatusLine statusLine= (IEditorStatusLine)textEditor.getAdapter(IEditorStatusLine.class);
+ if (statusLine != null) {
+ display.asyncExec(new Runnable() {
+ /*
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ statusLine.setMessage(true, message, null);
+ }
+ });
+ }
+ }
+}