blob: 22819abb0447e0a9a738afdc5f0f655b4194fbe0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* 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
*******************************************************************************/
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.core.runtime.CoreException;
import org.eclipse.core.resources.IStorage;
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.IEditorInput;
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;
import org.eclipse.jdt.core.IJarEntryResource;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
/**
* Properties key hyperlink detector.
*
* @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)
*/
@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
ITextEditor textEditor= 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 | BadPartitioningException | IOException ex) {
return null;
} catch (IllegalArgumentException ex) {
showErrorInStatusLine(ex.getLocalizedMessage(), textEditor);
return null;
}
}
private String getUnicodeString(String key) {
StringCharacterIterator iter= new StringCharacterIterator(key);
StringBuilder result= new StringBuilder();
while (iter.getIndex() < iter.getEndIndex()) {
char c= iter.current();
if (c == '\\') {
iter.next();
c= iter.current();
if (c == 'u') {
StringBuilder unicode= new StringBuilder();
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();
}
static boolean checkEnabled(ITextEditor textEditor, int offset) {
if (offset < 0)
return false;
IEditorInput editorInput= textEditor.getEditorInput();
return editorInput instanceof IFileEditorInput || (editorInput instanceof IStorageEditorInput && isEclipseNLSAvailable((IStorageEditorInput) editorInput));
}
private static boolean isEclipseNLSAvailable(IStorageEditorInput editorInput) {
IStorage storage;
try {
storage= editorInput.getStorage();
} catch (CoreException ex) {
return false;
}
if (!(storage instanceof IJarEntryResource))
return false;
IJavaProject javaProject= ((IJarEntryResource) storage).getPackageFragmentRoot().getJavaProject();
if (javaProject == null || !javaProject.exists())
return false;
try {
return javaProject.findType("org.eclipse.osgi.util.NLS") != null; //$NON-NLS-1$
} catch (JavaModelException e) {
return false;
}
}
private void showErrorInStatusLine(final String message, ITextEditor textEditor) {
Display display= textEditor.getEditorSite().getShell().getDisplay();
display.beep();
final IEditorStatusLine statusLine= textEditor.getAdapter(IEditorStatusLine.class);
if (statusLine != null) {
display.asyncExec(() -> statusLine.setMessage(true, message, null));
}
}
}