blob: 52a90b3bc984f73907b0fc47490b22fd494e3338 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 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.actions;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.text.correction.PreviewFeaturesSubProcessor;
import org.eclipse.jdt.internal.ui.text.java.JavaMultiLineStringAutoIndentStrategy;
public class AddTextBlockAction extends SelectionDispatchAction {
private CompilationUnitEditor fEditor;
/**
* Creates a new <code>AddTextBlockAction</code>. The action requires that the selection
* provided by the site's selection provider is of type <code>
* org.eclipse.jface.viewers.IStructuredSelection</code>.
*
* @param site the site providing context information for this action
*/
private AddTextBlockAction(IWorkbenchSite site) {
super(site);
setText(ActionMessages.AddTextBlockAction_label);
setDescription(ActionMessages.AddTextBlockAction_description);
setToolTipText(ActionMessages.AddTextBlockAction_tooltip);
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.ADD_TEXTBLOCK_ACTION);
}
/**
* Note: This constructor is for internal use only. Clients should not call this constructor.
*
* @param editor the compilation unit editor
*
* @noreference This constructor is not intended to be referenced by clients.
*/
public AddTextBlockAction(CompilationUnitEditor editor) {
this(editor.getEditorSite());
fEditor= editor;
setEnabled(checkEnabledEditor());
}
private boolean checkEnabledEditor() {
return fEditor != null && SelectionConverter.canOperateOn(fEditor);
}
//---- Structured Viewer -----------------------------------------------------------
@Override
public void selectionChanged(IStructuredSelection selection) {
//do nothing
}
@Override
public void run(IStructuredSelection selection) {
//do nothing
}
//---- Java Editor --------------------------------------------------------------
@Override
public void selectionChanged(ITextSelection selection) {
//do nothing
}
@Override
public void run(ITextSelection selection) {
IEditorInput input= fEditor.getEditorInput();
IDocumentProvider docProvider= fEditor.getDocumentProvider();
if (docProvider == null || input == null)
return;
IDocument document= docProvider.getDocument(input);
if (document == null)
return;
IDocumentExtension3 docExtension= null;
if (document instanceof IDocumentExtension3)
docExtension= (IDocumentExtension3) document;
else
return;
String indentStr= IndentAction.EMPTY_STR;
IJavaProject javaProject= getProject();
if (javaProject == null) {
return;
}
try {
indentStr= IndentAction.getIndentationAsPerTextBlockSettings(document, selection.getOffset(), javaProject);
} catch (BadLocationException e) {
return;
}
try {
int selectionOffset= selection.getOffset();
boolean setCaratPosition= selection.getLength() > 0 ? false : true;
ITypedRegion partition= docExtension.getPartition(IJavaPartitions.JAVA_PARTITIONING, selectionOffset, false);
if (!canAddTextBlock(partition, javaProject, selection)) {
return;
}
DocumentCommand command= getDocumentCommand(document, javaProject, selection, indentStr);
addTextBlock(document, command, setCaratPosition);
} catch (BadLocationException | BadPartitioningException e) {
//do nothing
}
}
private DocumentCommand getDocumentCommand(IDocument document, IJavaProject javaProject, ITextSelection selection, String indentStr) {
DocumentCommand cmd= new DocumentCommand() { //empty
};
if (selection.getLength() > 0) {
try {
indentStr= getLineIndentation(document, selection.getOffset());
} catch (BadLocationException e) {
//do nothing
}
}
cmd.offset= selection.getOffset();
cmd.length= selection.getLength();
cmd.text= IndentAction.TEXT_BLOCK_STR + System.lineSeparator() + indentStr;
cmd.doit= true;
cmd.shiftsCaret= true;
cmd.caretOffset= selection.getOffset() + selection.getLength() + cmd.text.length();
cmd.text+= selection.getText();
if (JavaMultiLineStringAutoIndentStrategy.isCloseStringsPreferenceSet(javaProject)) {
cmd.text+= System.lineSeparator() + indentStr + IndentAction.TEXT_BLOCK_STR;
}
return cmd;
}
protected final void replace(IDocument document, int offset, int length, String string) throws BadLocationException {
document.replace(offset, length, string);
}
private boolean canAddTextBlock(ITypedRegion partition, IJavaProject javaProject, ITextSelection selection) {
if (fEditor == null) {
return false;
}
if (!PreviewFeaturesSubProcessor.isPreviewFeatureEnabled(javaProject)) {
return false;
}
boolean addTextBlock= true;
String partitionType= partition.getType();
if (selection.getLength() == 0) {
if (IJavaPartitions.JAVA_MULTI_LINE_STRING.equals(partitionType)
|| IJavaPartitions.JAVA_STRING.equals(partitionType)
|| IJavaPartitions.JAVA_DOC.equals(partitionType)
|| IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(partitionType)
|| IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(partitionType)
|| IJavaPartitions.JAVA_CHARACTER.equals(partitionType)) {
addTextBlock= false;
}
} else {
if (IJavaPartitions.JAVA_MULTI_LINE_STRING.equals(partitionType)) {
addTextBlock= false;
} else if (IJavaPartitions.JAVA_STRING.equals(partitionType)
|| IJavaPartitions.JAVA_DOC.equals(partitionType)
|| IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(partitionType)
|| IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(partitionType)
|| IJavaPartitions.JAVA_CHARACTER.equals(partitionType)) {
addTextBlock= false;
if (partition.getOffset() == selection.getOffset() && partition.getLength() <= selection.getLength()) {
addTextBlock= true;
}
}
}
return addTextBlock;
}
private void addTextBlock(IDocument document, DocumentCommand cmd, boolean setCaratPosition) {
try {
replace(document, cmd.offset, cmd.length, cmd.text);
if (setCaratPosition) {
selectAndReveal(cmd.caretOffset, 0);
}
} catch (BadLocationException e) {
//do nothing
}
}
protected String getLineIndentation(IDocument document, int offset) throws BadLocationException {
// find start of line
int adjustedOffset= (offset == document.getLength() ? offset - 1 : offset);
IRegion line= document.getLineInformationOfOffset(adjustedOffset);
int start= line.getOffset();
// find white spaces
int end= findEndOfWhiteSpace(document, start, offset);
return document.get(start, end - start);
}
protected int findEndOfWhiteSpace(IDocument document, int offset, int end) throws BadLocationException {
while (offset < end) {
char c= document.getChar(offset);
if (c != ' ' && c != '\t') {
return offset;
}
offset++;
}
return end;
}
private IJavaProject getProject() {
IJavaProject javaProject= null;
if (fEditor != null) {
ITypeRoot inputJavaElement= EditorUtility.getEditorInputJavaElement(fEditor, false);
javaProject= inputJavaElement.getJavaProject();
}
return javaProject;
}
private void selectAndReveal(int newOffset, int newLength) {
Assert.isTrue(newOffset >= 0);
Assert.isTrue(newLength >= 0);
ISourceViewer viewer= fEditor.getViewer();
if (viewer != null) {
viewer.setSelectedRange(newOffset, newLength);
}
}
}