blob: 44b27555febee1f41b37295f5a1b9e955a7d3c13 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.text.correction;
import java.util.Iterator;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.ui.text.IColorManager;
import org.eclipse.jdt.ui.text.JavaTextTools;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.propertiesfileeditor.IPropertiesFilePartitions;
import org.eclipse.jdt.internal.ui.text.HTMLTextPresenter;
/**
* PropertiesFileCorrectionAssistant.
*
* @since 3.1
*/
public class PropertiesFileCorrectionAssistant extends ContentAssistant {
private ITextViewer fViewer;
private ITextEditor fEditor;
private Position fPosition;
/**
* Constructor for PropertiesFileCorrectionAssistant.
*/
public PropertiesFileCorrectionAssistant(ITextEditor editor) {
Assert.isNotNull(editor);
fEditor= editor;
PropertiesFileCorrectionProcessor processor= new PropertiesFileCorrectionProcessor(this);
setContentAssistProcessor(processor, IPropertiesFilePartitions.PROPERTY_VALUE);
setContentAssistProcessor(processor, IPropertiesFilePartitions.COMMENT);
enableAutoActivation(false);
enableAutoInsert(false);
setContextInformationPopupOrientation(CONTEXT_INFO_ABOVE);
setInformationControlCreator(getInformationControlCreator());
JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools();
IColorManager manager= textTools.getColorManager();
IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
Color c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_FOREGROUND, manager);
setProposalSelectorForeground(c);
c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_BACKGROUND, manager);
setProposalSelectorBackground(c);
}
public IEditorPart getEditor() {
return fEditor;
}
private IInformationControlCreator getInformationControlCreator() {
return new IInformationControlCreator() {
public IInformationControl createInformationControl(Shell parent) {
return new DefaultInformationControl(parent, new HTMLTextPresenter());
}
};
}
private static Color getColor(IPreferenceStore store, String key, IColorManager manager) {
RGB rgb= PreferenceConverter.getColor(store, key);
return manager.getColor(rgb);
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistant#install(org.eclipse.jface.text.ITextViewer)
*/
public void install(ITextViewer textViewer) {
super.install(textViewer);
fViewer= textViewer;
}
/*
* @see org.eclipse.jface.text.contentassist.ContentAssistant#uninstall()
*/
public void uninstall() {
fViewer= null;
}
/**
* Show completions at caret position. If current
* position does not contain quick fixes look for
* next quick fix on same line by moving from left
* to right and restarting at end of line if the
* beginning of the line is reached.
*
* @see org.eclipse.jface.text.contentassist.IContentAssistant#showPossibleCompletions()
*/
public String showPossibleCompletions() {
if (fViewer == null || fViewer.getDocument() == null)
// Let superclass deal with this
return super.showPossibleCompletions();
Point selectedRange= fViewer.getSelectedRange();
fPosition= null;
if (selectedRange.y == 0) {
int invocationOffset= computeOffsetWithCorrection(selectedRange.x);
if (invocationOffset != -1) {
storePosition();
fViewer.setSelectedRange(invocationOffset, 0);
fViewer.revealRange(invocationOffset, 0);
}
}
return super.showPossibleCompletions();
}
/**
* Find offset which contains corrections.
* Search on same line by moving from left
* to right and restarting at end of line if the
* beginning of the line is reached.
*
* @return an offset where corrections are available or -1 if none
*/
private int computeOffsetWithCorrection(int initalOffset) {
IRegion lineInfo= null;
try {
lineInfo= fViewer.getDocument().getLineInformationOfOffset(initalOffset);
} catch (BadLocationException ex) {
return -1;
}
int startOffset= lineInfo.getOffset();
int endOffset= startOffset + lineInfo.getLength();
int result= computeOffsetWithCorrection(startOffset, endOffset, initalOffset);
if (result > 0 && result != initalOffset)
return result;
else
return -1;
}
/**
* @return the best matching offset with corrections or -1 if nothing is found
*/
private int computeOffsetWithCorrection(int startOffset, int endOffset, int initialOffset) {
IAnnotationModel model= null;
IEditorInput input= fEditor.getEditorInput();
if (!(input instanceof IStorageEditorInput))
return -1;
ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
IPath path= null;
try {
path= ((IStorageEditorInput)input).getStorage().getFullPath();
if (path == null)
return -1;
manager.connect(path, null);
} catch (CoreException e) {
JavaPlugin.log(e.getStatus());
return -1;
}
try {
model= manager.getTextFileBuffer(path).getAnnotationModel();
int invocationOffset= -1;
int offsetOfFirstProblem= Integer.MAX_VALUE;
Iterator iter= model.getAnnotationIterator();
while (iter.hasNext()) {
Annotation annot= (Annotation) iter.next();
if (JavaCorrectionProcessor.isQuickFixableType(annot)) {
Position pos= model.getPosition(annot);
if (isIncluded(pos, startOffset, endOffset)) {
if (PropertiesFileCorrectionProcessor.hasCorrections(annot)) {
offsetOfFirstProblem= Math.min(offsetOfFirstProblem, pos.getOffset());
invocationOffset= computeBestOffset(invocationOffset, pos, initialOffset);
if (initialOffset == invocationOffset)
return initialOffset;
}
}
}
}
if (initialOffset < offsetOfFirstProblem && offsetOfFirstProblem != Integer.MAX_VALUE)
return offsetOfFirstProblem;
else
return invocationOffset;
} finally {
try {
manager.disconnect(path, null);
} catch (CoreException e) {
JavaPlugin.log(e.getStatus());
}
}
}
private boolean isIncluded(Position pos, int lineStart, int lineEnd) {
return (pos != null) && (pos.getOffset() >= lineStart && (pos.getOffset() + pos.getLength() <= lineEnd));
}
/**
* Computes and returns the invocation offset given a new
* position, the initial offset and the best invocation offset
* found so far.
* <p>
* The closest offset to the left of the initial offset is the
* best. If there is no offset on the left, the closest on the
* right is the best.</p>
*/
private int computeBestOffset(int invocationOffset, Position pos, int initalOffset) {
int newOffset= pos.offset;
if (newOffset <= initalOffset && initalOffset <= newOffset + pos.length)
return initalOffset;
if (invocationOffset < 0)
return newOffset;
if (newOffset <= initalOffset && invocationOffset >= initalOffset)
return newOffset;
if (newOffset <= initalOffset && invocationOffset < initalOffset)
return Math.max(invocationOffset, newOffset);
if (invocationOffset <= initalOffset)
return invocationOffset;
return Math.max(invocationOffset, newOffset);
}
/*
* @see org.eclipse.jface.text.contentassist.ContentAssistant#possibleCompletionsClosed()
*/
protected void possibleCompletionsClosed() {
super.possibleCompletionsClosed();
restorePosition();
}
private void storePosition() {
int initalOffset= fViewer.getSelectedRange().x;
int length= fViewer.getSelectedRange().y;
fPosition= new Position(initalOffset, length);
}
private void restorePosition() {
if (fPosition != null && !fPosition.isDeleted() && fViewer.getDocument() != null) {
fViewer.setSelectedRange(fPosition.offset, fPosition.length);
fViewer.revealRange(fPosition.offset, fPosition.length);
}
fPosition= null;
}
/**
* Returns true if the last invoked completion was called with an updated offset.
*/
public boolean isUpdatedOffset() {
return fPosition != null;
}
}