| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.internal.ui.javaeditor; |
| |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Preferences; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.VerifyKeyListener; |
| import org.eclipse.swt.events.VerifyEvent; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.util.ListenerList; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.window.Window; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.BadPositionCategoryException; |
| import org.eclipse.jface.text.DocumentCommand; |
| import org.eclipse.jface.text.IAutoEditStrategy; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentExtension; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.ILineTracker; |
| import org.eclipse.jface.text.IPositionUpdater; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.ITextOperationTarget; |
| import org.eclipse.jface.text.ITextViewerExtension; |
| import org.eclipse.jface.text.ITypedRegion; |
| import org.eclipse.jface.text.IWidgetTokenKeeper; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.TextUtilities; |
| import org.eclipse.jface.text.contentassist.ContentAssistant; |
| import org.eclipse.jface.text.contentassist.IContentAssistant; |
| import org.eclipse.jface.text.contentassist.IContentAssistantExtension; |
| import org.eclipse.jface.text.formatter.FormattingContextProperties; |
| import org.eclipse.jface.text.formatter.IFormattingContext; |
| import org.eclipse.jface.text.link.ExclusivePositionUpdater; |
| import org.eclipse.jface.text.link.ILinkedListener; |
| import org.eclipse.jface.text.link.LinkedEnvironment; |
| import org.eclipse.jface.text.link.LinkedPositionGroup; |
| import org.eclipse.jface.text.link.LinkedUIControl; |
| import org.eclipse.jface.text.link.LinkedUIControl.ExitFlags; |
| import org.eclipse.jface.text.link.LinkedUIControl.IExitPolicy; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.jface.text.source.IOverviewRuler; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.IVerticalRuler; |
| import org.eclipse.jface.text.source.SourceViewerConfiguration; |
| |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IFileEditorInput; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.actions.ActionContext; |
| import org.eclipse.ui.actions.ActionGroup; |
| import org.eclipse.ui.dialogs.SaveAsDialog; |
| import org.eclipse.ui.help.WorkbenchHelp; |
| import org.eclipse.ui.part.FileEditorInput; |
| import org.eclipse.ui.texteditor.ContentAssistAction; |
| import org.eclipse.ui.texteditor.ExtendedTextEditorPreferenceConstants; |
| import org.eclipse.ui.texteditor.IDocumentProvider; |
| import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
| import org.eclipse.ui.texteditor.TextOperationAction; |
| import org.eclipse.ui.texteditor.link.EditorHistoryUpdater; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMember; |
| import org.eclipse.jdt.core.ISourceRange; |
| import org.eclipse.jdt.core.ISourceReference; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| |
| import org.eclipse.jdt.ui.IWorkingCopyManager; |
| import org.eclipse.jdt.ui.PreferenceConstants; |
| import org.eclipse.jdt.ui.actions.GenerateActionGroup; |
| import org.eclipse.jdt.ui.actions.IJavaEditorActionDefinitionIds; |
| import org.eclipse.jdt.ui.actions.RefactorActionGroup; |
| |
| import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.actions.AddBlockCommentAction; |
| import org.eclipse.jdt.internal.ui.actions.CompositeActionGroup; |
| import org.eclipse.jdt.internal.ui.actions.IndentAction; |
| import org.eclipse.jdt.internal.ui.actions.RemoveBlockCommentAction; |
| import org.eclipse.jdt.internal.ui.compare.LocalHistoryActionGroup; |
| import org.eclipse.jdt.internal.ui.text.ContentAssistPreference; |
| import org.eclipse.jdt.internal.ui.text.IJavaPartitions; |
| import org.eclipse.jdt.internal.ui.text.comment.CommentFormattingContext; |
| import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionAssistant; |
| import org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener; |
| import org.eclipse.jdt.internal.ui.text.java.SmartSemicolonAutoEditStrategy; |
| |
| |
| |
| /** |
| * Java specific text editor. |
| */ |
| public class CompilationUnitEditor extends JavaEditor implements IJavaReconcilingListener { |
| |
| /** |
| * Text operation code for requesting correction assist to show correction |
| * proposals for the current position. |
| */ |
| public static final int CORRECTIONASSIST_PROPOSALS= 50; |
| |
| /** |
| * Text operation code for requesting common prefix completion. |
| */ |
| public static final int CONTENTASSIST_COMPLETE_PREFIX= 60; |
| |
| |
| interface ITextConverter { |
| void customizeDocumentCommand(IDocument document, DocumentCommand command); |
| } |
| |
| class AdaptedSourceViewer extends JavaSourceViewer { |
| |
| private List fTextConverters; |
| private boolean fIgnoreTextConverters= false; |
| private JavaCorrectionAssistant fCorrectionAssistant; |
| |
| public AdaptedSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean showAnnotationsOverview, int styles) { |
| super(parent, verticalRuler, overviewRuler, showAnnotationsOverview, styles); |
| } |
| |
| public IContentAssistant getContentAssistant() { |
| return fContentAssistant; |
| } |
| |
| /* |
| * @see ITextOperationTarget#doOperation(int) |
| */ |
| public void doOperation(int operation) { |
| |
| if (getTextWidget() == null) |
| return; |
| |
| switch (operation) { |
| case CONTENTASSIST_PROPOSALS: |
| String msg= fContentAssistant.showPossibleCompletions(); |
| setStatusLineErrorMessage(msg); |
| return; |
| case CORRECTIONASSIST_PROPOSALS: |
| msg= fCorrectionAssistant.showPossibleCompletions(); |
| setStatusLineErrorMessage(msg); |
| return; |
| case UNDO: |
| fIgnoreTextConverters= true; |
| super.doOperation(operation); |
| fIgnoreTextConverters= false; |
| return; |
| case REDO: |
| fIgnoreTextConverters= true; |
| super.doOperation(operation); |
| fIgnoreTextConverters= false; |
| return; |
| case CONTENTASSIST_COMPLETE_PREFIX: |
| if (fContentAssistant instanceof IContentAssistantExtension) { |
| msg= ((IContentAssistantExtension) fContentAssistant).completePrefix(); |
| setStatusLineErrorMessage(msg); |
| return; |
| } else |
| break; |
| } |
| |
| super.doOperation(operation); |
| } |
| |
| /* |
| * @see ITextOperationTarget#canDoOperation(int) |
| */ |
| public boolean canDoOperation(int operation) { |
| if (operation == CORRECTIONASSIST_PROPOSALS) |
| return isEditable(); |
| else if (operation == CONTENTASSIST_COMPLETE_PREFIX) |
| return isEditable(); |
| |
| return super.canDoOperation(operation); |
| } |
| |
| /** |
| * @inheritDoc |
| * @since 3.0 |
| */ |
| public void unconfigure() { |
| if (fCorrectionAssistant != null) { |
| fCorrectionAssistant.uninstall(); |
| fCorrectionAssistant= null; |
| } |
| super.unconfigure(); |
| } |
| |
| public void insertTextConverter(ITextConverter textConverter, int index) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public void addTextConverter(ITextConverter textConverter) { |
| if (fTextConverters == null) { |
| fTextConverters= new ArrayList(1); |
| fTextConverters.add(textConverter); |
| } else if (!fTextConverters.contains(textConverter)) |
| fTextConverters.add(textConverter); |
| } |
| |
| public void removeTextConverter(ITextConverter textConverter) { |
| if (fTextConverters != null) { |
| fTextConverters.remove(textConverter); |
| if (fTextConverters.size() == 0) |
| fTextConverters= null; |
| } |
| } |
| |
| /* |
| * @see TextViewer#customizeDocumentCommand(DocumentCommand) |
| */ |
| protected void customizeDocumentCommand(DocumentCommand command) { |
| super.customizeDocumentCommand(command); |
| if (!fIgnoreTextConverters && fTextConverters != null) { |
| for (Iterator e = fTextConverters.iterator(); e.hasNext();) |
| ((ITextConverter) e.next()).customizeDocumentCommand(getDocument(), command); |
| } |
| } |
| |
| // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270 |
| public void updateIndentationPrefixes() { |
| SourceViewerConfiguration configuration= getSourceViewerConfiguration(); |
| String[] types= configuration.getConfiguredContentTypes(this); |
| for (int i= 0; i < types.length; i++) { |
| String[] prefixes= configuration.getIndentPrefixes(this, types[i]); |
| if (prefixes != null && prefixes.length > 0) |
| setIndentPrefixes(prefixes, types[i]); |
| } |
| } |
| |
| /* |
| * @see IWidgetTokenOwner#requestWidgetToken(IWidgetTokenKeeper) |
| */ |
| public boolean requestWidgetToken(IWidgetTokenKeeper requester) { |
| if (WorkbenchHelp.isContextHelpDisplayed()) |
| return false; |
| return super.requestWidgetToken(requester); |
| } |
| |
| /* |
| * @see IWidgetTokenOwnerExtension#requestWidgetToken(IWidgetTokenKeeper, int) |
| * @since 3.0 |
| */ |
| public boolean requestWidgetToken(IWidgetTokenKeeper requester, int priority) { |
| if (WorkbenchHelp.isContextHelpDisplayed()) |
| return false; |
| return super.requestWidgetToken(requester, priority); |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.source.ISourceViewer#configure(org.eclipse.jface.text.source.SourceViewerConfiguration) |
| */ |
| public void configure(SourceViewerConfiguration configuration) { |
| super.configure(configuration); |
| fCorrectionAssistant= new JavaCorrectionAssistant(CompilationUnitEditor.this); |
| fCorrectionAssistant.install(this); |
| IAutoEditStrategy smartSemi= new SmartSemicolonAutoEditStrategy(IJavaPartitions.JAVA_PARTITIONING); |
| prependAutoEditStrategy(smartSemi, IDocument.DEFAULT_CONTENT_TYPE); |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.source.SourceViewer#createFormattingContext() |
| * @since 3.0 |
| */ |
| public IFormattingContext createFormattingContext() { |
| IFormattingContext context= new CommentFormattingContext(); |
| |
| Map preferences; |
| IJavaElement inputJavaElement= getInputJavaElement(); |
| IJavaProject javaProject= inputJavaElement != null ? inputJavaElement.getJavaProject() : null; |
| if (javaProject == null) |
| preferences= new HashMap(JavaCore.getOptions()); |
| else |
| preferences= new HashMap(javaProject.getOptions(true)); |
| |
| context.storeToMap(PreferenceConstants.getPreferenceStore(), preferences, false); |
| context.setProperty(FormattingContextProperties.CONTEXT_PREFERENCES, preferences); |
| |
| return context; |
| } |
| } |
| |
| static class TabConverter implements ITextConverter { |
| |
| private int fTabRatio; |
| private ILineTracker fLineTracker; |
| |
| public TabConverter() { |
| } |
| |
| public void setNumberOfSpacesPerTab(int ratio) { |
| fTabRatio= ratio; |
| } |
| |
| public void setLineTracker(ILineTracker lineTracker) { |
| fLineTracker= lineTracker; |
| } |
| |
| private int insertTabString(StringBuffer buffer, int offsetInLine) { |
| |
| if (fTabRatio == 0) |
| return 0; |
| |
| int remainder= offsetInLine % fTabRatio; |
| remainder= fTabRatio - remainder; |
| for (int i= 0; i < remainder; i++) |
| buffer.append(' '); |
| return remainder; |
| } |
| |
| public void customizeDocumentCommand(IDocument document, DocumentCommand command) { |
| String text= command.text; |
| if (text == null) |
| return; |
| |
| int index= text.indexOf('\t'); |
| if (index > -1) { |
| |
| StringBuffer buffer= new StringBuffer(); |
| |
| fLineTracker.set(command.text); |
| int lines= fLineTracker.getNumberOfLines(); |
| |
| try { |
| |
| for (int i= 0; i < lines; i++) { |
| |
| int offset= fLineTracker.getLineOffset(i); |
| int endOffset= offset + fLineTracker.getLineLength(i); |
| String line= text.substring(offset, endOffset); |
| |
| int position= 0; |
| if (i == 0) { |
| IRegion firstLine= document.getLineInformationOfOffset(command.offset); |
| position= command.offset - firstLine.getOffset(); |
| } |
| |
| int length= line.length(); |
| for (int j= 0; j < length; j++) { |
| char c= line.charAt(j); |
| if (c == '\t') { |
| position += insertTabString(buffer, position); |
| } else { |
| buffer.append(c); |
| ++ position; |
| } |
| } |
| |
| } |
| |
| command.text= buffer.toString(); |
| |
| } catch (BadLocationException x) { |
| } |
| } |
| } |
| } |
| |
| private class ExitPolicy implements IExitPolicy { |
| |
| final char fExitCharacter; |
| final char fEscapeCharacter; |
| final Stack fStack; |
| final int fSize; |
| |
| public ExitPolicy(char exitCharacter, char escapeCharacter, Stack stack) { |
| fExitCharacter= exitCharacter; |
| fEscapeCharacter= escapeCharacter; |
| fStack= stack; |
| fSize= fStack.size(); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int) |
| */ |
| public ExitFlags doExit(LinkedEnvironment environment, VerifyEvent event, int offset, int length) { |
| |
| if (event.character == fExitCharacter) { |
| |
| if (fSize == fStack.size() && !isMasked(offset)) { |
| BracketLevel level= (BracketLevel) fStack.peek(); |
| if (level.fFirstPosition.offset > offset || level.fSecondPosition.offset < offset) |
| return null; |
| if (level.fSecondPosition.offset == offset && length == 0) |
| // don't enter the character if if its the closing peer |
| return new ExitFlags(ILinkedListener.UPDATE_CARET, false); |
| else |
| return new ExitFlags(ILinkedListener.UPDATE_CARET, true); |
| } |
| } |
| return null; |
| } |
| |
| private boolean isMasked(int offset) { |
| IDocument document= getSourceViewer().getDocument(); |
| try { |
| return fEscapeCharacter == document.getChar(offset - 1); |
| } catch (BadLocationException e) { |
| } |
| return false; |
| } |
| } |
| |
| private static class BracketLevel { |
| int fOffset; |
| int fLength; |
| LinkedUIControl fEditor; |
| Position fFirstPosition; |
| Position fSecondPosition; |
| } |
| |
| private class BracketInserter implements VerifyKeyListener, ILinkedListener { |
| |
| private boolean fCloseBrackets= true; |
| private boolean fCloseStrings= true; |
| private final String CATEGORY= toString(); |
| private IPositionUpdater fUpdater= new ExclusivePositionUpdater(CATEGORY); |
| private Stack fBracketLevelStack= new Stack(); |
| |
| public void setCloseBracketsEnabled(boolean enabled) { |
| fCloseBrackets= enabled; |
| } |
| |
| public void setCloseStringsEnabled(boolean enabled) { |
| fCloseStrings= enabled; |
| } |
| |
| private boolean hasIdentifierToTheRight(IDocument document, int offset) { |
| try { |
| int end= offset; |
| IRegion endLine= document.getLineInformationOfOffset(end); |
| int maxEnd= endLine.getOffset() + endLine.getLength(); |
| while (end != maxEnd && Character.isWhitespace(document.getChar(end))) |
| ++end; |
| |
| return end != maxEnd && Character.isJavaIdentifierPart(document.getChar(end)); |
| |
| } catch (BadLocationException e) { |
| // be conservative |
| return true; |
| } |
| } |
| |
| private boolean hasIdentifierToTheLeft(IDocument document, int offset) { |
| try { |
| int start= offset; |
| IRegion startLine= document.getLineInformationOfOffset(start); |
| int minStart= startLine.getOffset(); |
| while (start != minStart && Character.isWhitespace(document.getChar(start - 1))) |
| --start; |
| |
| return start != minStart && Character.isJavaIdentifierPart(document.getChar(start - 1)); |
| |
| } catch (BadLocationException e) { |
| return true; |
| } |
| } |
| |
| private boolean hasCharacterToTheRight(IDocument document, int offset, char character) { |
| try { |
| int end= offset; |
| IRegion endLine= document.getLineInformationOfOffset(end); |
| int maxEnd= endLine.getOffset() + endLine.getLength(); |
| while (end != maxEnd && Character.isWhitespace(document.getChar(end))) |
| ++end; |
| |
| return end != maxEnd && document.getChar(end) == character; |
| |
| |
| } catch (BadLocationException e) { |
| // be conservative |
| return true; |
| } |
| } |
| |
| /* |
| * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent) |
| */ |
| public void verifyKey(VerifyEvent event) { |
| |
| if (!event.doit || getInsertMode() != SMART_INSERT) |
| return; |
| |
| final ISourceViewer sourceViewer= getSourceViewer(); |
| IDocument document= sourceViewer.getDocument(); |
| |
| final Point selection= sourceViewer.getSelectedRange(); |
| final int offset= selection.x; |
| final int length= selection.y; |
| |
| switch (event.character) { |
| case '(': |
| if (hasCharacterToTheRight(document, offset + length, '(')) |
| return; |
| |
| // fall through |
| |
| case '[': |
| if (!fCloseBrackets) |
| return; |
| if (hasIdentifierToTheRight(document, offset + length)) |
| return; |
| |
| // fall through |
| |
| case '\'': |
| if (event.character == '\'') { |
| if (!fCloseStrings) |
| return; |
| if (hasIdentifierToTheLeft(document, offset) || hasIdentifierToTheRight(document, offset + length)) |
| return; |
| } |
| |
| // fall through |
| |
| case '"': |
| if (event.character == '"') { |
| if (!fCloseStrings) |
| return; |
| if (hasIdentifierToTheLeft(document, offset) || hasIdentifierToTheRight(document, offset + length)) |
| return; |
| } |
| |
| try { |
| ITypedRegion partition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset); |
| if (! IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()) && partition.getOffset() != offset) |
| return; |
| |
| if (!validateEditorInputState()) |
| return; |
| |
| final char character= event.character; |
| final char closingCharacter= getPeerCharacter(character); |
| final StringBuffer buffer= new StringBuffer(); |
| buffer.append(character); |
| buffer.append(closingCharacter); |
| |
| document.replace(offset, length, buffer.toString()); |
| |
| |
| BracketLevel level= new BracketLevel(); |
| fBracketLevelStack.push(level); |
| |
| LinkedPositionGroup group= new LinkedPositionGroup(); |
| group.createPosition(document, offset + 1, 0); |
| |
| LinkedEnvironment env= new LinkedEnvironment(); |
| env.addLinkedListener(this); |
| env.addGroup(group); |
| env.forceInstall(); |
| |
| level.fOffset= offset; |
| level.fLength= 2; |
| |
| // set up position tracking for our magic peers |
| if (fBracketLevelStack.size() == 1) { |
| document.addPositionCategory(CATEGORY); |
| document.addPositionUpdater(fUpdater); |
| } |
| level.fFirstPosition= new Position(offset, 1); |
| level.fSecondPosition= new Position(offset + 1, 1); |
| document.addPosition(CATEGORY, level.fFirstPosition); |
| document.addPosition(CATEGORY, level.fSecondPosition); |
| |
| level.fEditor= new LinkedUIControl(env, sourceViewer); |
| level.fEditor.setSimpleMode(true); |
| level.fEditor.setPositionListener(new EditorHistoryUpdater()); |
| level.fEditor.setExitPolicy(new ExitPolicy(closingCharacter, getEscapeCharacter(closingCharacter), fBracketLevelStack)); |
| level.fEditor.setExitPosition(sourceViewer, offset + 2, 0, Integer.MAX_VALUE); |
| level.fEditor.setCyclingMode(LinkedUIControl.CYCLE_NEVER); |
| level.fEditor.enter(); |
| |
| |
| IRegion newSelection= level.fEditor.getSelectedRegion(); |
| sourceViewer.setSelectedRange(newSelection.getOffset(), newSelection.getLength()); |
| |
| event.doit= false; |
| |
| } catch (BadLocationException e) { |
| JavaPlugin.log(e); |
| } catch (BadPositionCategoryException e) { |
| JavaPlugin.log(e); |
| } |
| break; |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment.ILinkedListener#left(org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment, int) |
| */ |
| public void left(LinkedEnvironment environment, int flags) { |
| |
| final BracketLevel level= (BracketLevel) fBracketLevelStack.pop(); |
| |
| if (flags != ILinkedListener.EXTERNAL_MODIFICATION) |
| return; |
| |
| // remove brackets |
| final ISourceViewer sourceViewer= getSourceViewer(); |
| final IDocument document= sourceViewer.getDocument(); |
| if (document instanceof IDocumentExtension) { |
| IDocumentExtension extension= (IDocumentExtension) document; |
| extension.registerPostNotificationReplace(null, new IDocumentExtension.IReplace() { |
| |
| public void perform(IDocument d, IDocumentListener owner) { |
| if ((level.fFirstPosition.isDeleted || level.fFirstPosition.length == 0) && !level.fSecondPosition.isDeleted && level.fSecondPosition.offset == level.fFirstPosition.offset) { |
| try { |
| document.replace(level.fSecondPosition.offset, level.fSecondPosition.length, null); |
| } catch (BadLocationException e) { |
| } |
| } |
| |
| if (fBracketLevelStack.size() == 0) { |
| document.removePositionUpdater(fUpdater); |
| try { |
| document.removePositionCategory(CATEGORY); |
| } catch (BadPositionCategoryException e) { |
| } |
| } |
| } |
| |
| }); |
| } |
| |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment.ILinkedListener#suspend(org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment) |
| */ |
| public void suspend(LinkedEnvironment environment) { |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment.ILinkedListener#resume(org.eclipse.jdt.internal.ui.text.link2.LinkedEnvironment, int) |
| */ |
| public void resume(LinkedEnvironment environment, int flags) { |
| } |
| } |
| |
| /** |
| * Remembers data related to the current selection to be able to |
| * restore it later. |
| * |
| * @since 3.0 |
| */ |
| private class RememberedSelection { |
| /** The remembered selection start. */ |
| private RememberedOffset fStartOffset= new RememberedOffset(); |
| /** The remembered selection end. */ |
| private RememberedOffset fEndOffset= new RememberedOffset(); |
| |
| /** |
| * Remember current selection. |
| */ |
| public void remember() { |
| /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=52257 |
| * This method may be called inside an async call posted |
| * to the UI thread, so protect against intermediate disposal |
| * of the editor. |
| */ |
| ISourceViewer viewer= getSourceViewer(); |
| if (viewer != null) { |
| IRegion selection= getSignedSelection(viewer); |
| int startOffset= selection.getOffset(); |
| int endOffset= startOffset + selection.getLength(); |
| |
| fStartOffset.setOffset(startOffset); |
| fEndOffset.setOffset(endOffset); |
| } |
| } |
| |
| /** |
| * Restore remembered selection. |
| */ |
| public void restore() { |
| /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=52257 |
| * This method may be called inside an async call posted |
| * to the UI thread, so protect against intermediate disposal |
| * of the editor. |
| */ |
| if (getSourceViewer() == null) |
| return; |
| |
| try { |
| |
| int startOffset, endOffset; |
| int revealStartOffset, revealEndOffset; |
| if (showsHighlightRangeOnly()) { |
| IJavaElement newStartElement= fStartOffset.getElement(); |
| startOffset= fStartOffset.getRememberedOffset(newStartElement); |
| revealStartOffset= fStartOffset.getRevealOffset(newStartElement, startOffset); |
| if (revealStartOffset == -1) |
| startOffset= -1; |
| |
| IJavaElement newEndElement= fEndOffset.getElement(); |
| endOffset= fEndOffset.getRememberedOffset(newEndElement); |
| revealEndOffset= fEndOffset.getRevealOffset(newEndElement, endOffset); |
| if (revealEndOffset == -1) |
| endOffset= -1; |
| } else { |
| startOffset= fStartOffset.getOffset(); |
| revealStartOffset= startOffset; |
| endOffset= fEndOffset.getOffset(); |
| revealEndOffset= endOffset; |
| } |
| |
| if (startOffset == -1) { |
| startOffset= endOffset; // fallback to caret offset |
| revealStartOffset= revealEndOffset; |
| } |
| |
| if (endOffset == -1) { |
| endOffset= startOffset; // fallback to other offset |
| revealEndOffset= revealStartOffset; |
| } |
| |
| IJavaElement element; |
| if (endOffset == -1) { |
| // fallback to element selection |
| element= fEndOffset.getElement(); |
| if (element == null) |
| element= fStartOffset.getElement(); |
| if (element != null) |
| setSelection(element); |
| return; |
| } |
| |
| if (isValidSelection(revealStartOffset, revealEndOffset - revealStartOffset) && isValidSelection(startOffset, endOffset - startOffset)) |
| selectAndReveal(startOffset, endOffset - startOffset, revealStartOffset, revealEndOffset - revealStartOffset); |
| } finally { |
| fStartOffset.clear(); |
| fEndOffset.clear(); |
| } |
| } |
| |
| private boolean isValidSelection(int offset, int length) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider != null) { |
| IDocument document= provider.getDocument(getEditorInput()); |
| if (document != null) { |
| int end= offset + length; |
| int documentLength= document.getLength(); |
| return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength; |
| } |
| } |
| return false; |
| } |
| |
| } |
| |
| /** |
| * Remembers additional data for a given |
| * offset to be able restore it later. |
| * |
| * @since 3.0 |
| */ |
| private class RememberedOffset { |
| /** Remembered line for the given offset */ |
| private int fLine; |
| /** Remembered column for the given offset*/ |
| private int fColumn; |
| /** Remembered Java element for the given offset*/ |
| private IJavaElement fElement; |
| /** Remembered Java element line for the given offset*/ |
| private int fElementLine; |
| |
| /** |
| * Store visual properties of the given offset. |
| * |
| * @param offset Offset in the document |
| */ |
| public void setOffset(int offset) { |
| try { |
| IDocument document= getSourceViewer().getDocument(); |
| fLine= document.getLineOfOffset(offset); |
| fColumn= offset - document.getLineOffset(fLine); |
| fElement= getElementAt(offset, true); |
| |
| fElementLine= -1; |
| if (fElement instanceof IMember) { |
| ISourceRange range= ((IMember) fElement).getNameRange(); |
| if (range != null) |
| fElementLine= document.getLineOfOffset(range.getOffset()); |
| } |
| if (fElementLine == -1) |
| fElementLine= document.getLineOfOffset(getOffset(fElement)); |
| } catch (BadLocationException e) { |
| // should not happen |
| JavaPlugin.log(e); |
| clear(); |
| } catch (JavaModelException e) { |
| // should not happen |
| JavaPlugin.log(e.getStatus()); |
| clear(); |
| } |
| } |
| |
| /** |
| * Return offset recomputed from stored visual properties. |
| * |
| * @return Offset in the document |
| */ |
| public int getOffset() { |
| IJavaElement newElement= getElement(); |
| |
| int offset= getRememberedOffset(newElement); |
| |
| if (offset != -1 && !containsOffset(newElement, offset) && (offset == 0 || !containsOffset(newElement, offset - 1))) |
| return -1; |
| |
| return offset; |
| } |
| |
| /** |
| * Return offset recomputed from stored visual properties. |
| * |
| * @param newElement Enclosing element |
| * @return Offset in the document |
| * @throws JavaModelException |
| * @throws BadLocationException |
| */ |
| public int getRememberedOffset(IJavaElement newElement) { |
| try { |
| if (newElement == null) |
| return -1; |
| |
| IDocument document= getSourceViewer().getDocument(); |
| int newElementLine= -1; |
| if (newElement instanceof IMember) { |
| ISourceRange range= ((IMember) newElement).getNameRange(); |
| if (range != null) |
| newElementLine= document.getLineOfOffset(range.getOffset()); |
| } |
| if (newElementLine == -1) |
| newElementLine= document.getLineOfOffset(getOffset(newElement)); |
| if (newElementLine == -1) |
| return -1; |
| |
| int newLine= fLine + newElementLine - fElementLine; |
| if (newLine < 0 || newLine >= document.getNumberOfLines()) |
| return -1; |
| int maxColumn= document.getLineLength(newLine); |
| String lineDelimiter= document.getLineDelimiter(newLine); |
| if (lineDelimiter != null) |
| maxColumn= maxColumn - lineDelimiter.length(); |
| int offset; |
| if (fColumn > maxColumn) |
| offset= document.getLineOffset(newLine) + maxColumn; |
| else |
| offset= document.getLineOffset(newLine) + fColumn; |
| |
| return offset; |
| } catch (BadLocationException e) { |
| // should not happen |
| JavaPlugin.log(e); |
| return -1; |
| } catch (JavaModelException e) { |
| // should not happen |
| JavaPlugin.log(e.getStatus()); |
| return -1; |
| } |
| } |
| |
| /** |
| * Returns the offset used to reveal the given element based on the given selection offset. |
| * @param element the element |
| * @param offset the selection offset |
| * @return the offset to reveal the given element based on the given selection offset |
| */ |
| public int getRevealOffset(IJavaElement element, int offset) { |
| if (element == null || offset == -1) |
| return -1; |
| |
| if (containsOffset(element, offset)) { |
| if (offset > 0) { |
| IJavaElement alternateElement= getElementAt(offset, false); |
| if (element.getHandleIdentifier().equals(alternateElement.getParent().getHandleIdentifier())) |
| return offset - 1; // Solves test case 2 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=47727#c3 |
| } |
| return offset; |
| } else if (offset > 0 && containsOffset(element, offset - 1)) |
| return offset - 1; // Solves test case 1 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=47727#c3 |
| |
| return -1; |
| } |
| |
| /** |
| * Return Java element recomputed from stored visual properties. |
| * |
| * @return Java element |
| */ |
| public IJavaElement getElement() { |
| if (fElement == null) |
| return null; |
| |
| return findElement(fElement); |
| } |
| |
| /** |
| * Clears the stored position |
| */ |
| public void clear() { |
| fLine= -1; |
| fColumn= -1; |
| fElement= null; |
| fElementLine= -1; |
| } |
| |
| /** |
| * Does the given Java element contain the given offset? |
| * @param element Java element |
| * @param offset Offset |
| * @return <code>true</code> iff the Java element contains the offset |
| */ |
| private boolean containsOffset(IJavaElement element, int offset) { |
| int elementOffset= getOffset(element); |
| int elementLength= getLength(element); |
| return (elementOffset > -1 && elementLength > -1) ? (offset >= elementOffset && offset < elementOffset + elementLength) : false; |
| } |
| /** |
| * Returns the offset of the given Java element. |
| * |
| * @param element Java element |
| * @return Offset of the given Java element |
| */ |
| private int getOffset(IJavaElement element) { |
| if (element instanceof ISourceReference) { |
| ISourceReference sr= (ISourceReference) element; |
| try { |
| ISourceRange srcRange= sr.getSourceRange(); |
| if (srcRange != null) |
| return srcRange.getOffset(); |
| } catch (JavaModelException e) { |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Returns the length of the given Java element. |
| * |
| * @param element Java element |
| * @return Length of the given Java element |
| */ |
| private int getLength(IJavaElement element) { |
| if (element instanceof ISourceReference) { |
| ISourceReference sr= (ISourceReference) element; |
| try { |
| ISourceRange srcRange= sr.getSourceRange(); |
| if (srcRange != null) |
| return srcRange.getLength(); |
| } catch (JavaModelException e) { |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Returns the updated java element for the old java element. |
| * |
| * @param element Old Java element |
| * @return Updated Java element |
| */ |
| private IJavaElement findElement(IJavaElement element) { |
| |
| if (element == null) |
| return null; |
| |
| IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager(); |
| ICompilationUnit unit= manager.getWorkingCopy(getEditorInput()); |
| |
| if (unit != null) { |
| try { |
| |
| synchronized (unit) { |
| unit.reconcile(false, false, null, null); |
| } |
| IJavaElement[] findings= unit.findElements(element); |
| if (findings != null && findings.length > 0) |
| return findings[0]; |
| |
| } catch (JavaModelException x) { |
| JavaPlugin.log(x.getStatus()); |
| // nothing found, be tolerant and go on |
| } |
| } |
| |
| return null; |
| } |
| |
| } |
| |
| /** Preference key for code formatter tab size */ |
| private final static String CODE_FORMATTER_TAB_SIZE= JavaCore.FORMATTER_TAB_SIZE; |
| /** Preference key for inserting spaces rather than tabs */ |
| private final static String SPACES_FOR_TABS= PreferenceConstants.EDITOR_SPACES_FOR_TABS; |
| /** Preference key for automatically closing strings */ |
| private final static String CLOSE_STRINGS= PreferenceConstants.EDITOR_CLOSE_STRINGS; |
| /** Preference key for automatically closing brackets and parenthesis */ |
| private final static String CLOSE_BRACKETS= PreferenceConstants.EDITOR_CLOSE_BRACKETS; |
| |
| |
| /** The editor's save policy */ |
| protected ISavePolicy fSavePolicy; |
| /** Listener to annotation model changes that updates the error tick in the tab image */ |
| private JavaEditorErrorTickUpdater fJavaEditorErrorTickUpdater; |
| /** The editor's tab converter */ |
| private TabConverter fTabConverter; |
| /** |
| * The remembered selection. |
| * @since 3.0 |
| */ |
| private RememberedSelection fRememberedSelection= new RememberedSelection(); |
| /** The bracket inserter. */ |
| private BracketInserter fBracketInserter= new BracketInserter(); |
| |
| /** The standard action groups added to the menu */ |
| private GenerateActionGroup fGenerateActionGroup; |
| private CompositeActionGroup fContextMenuGroup; |
| |
| /** |
| * Reconciling listeners. |
| * @since 3.0 |
| */ |
| private ListenerList fReconcilingListeners= new ListenerList(); |
| |
| |
| |
| /** |
| * Creates a new compilation unit editor. |
| */ |
| public CompilationUnitEditor() { |
| super(); |
| setDocumentProvider(JavaPlugin.getDefault().getCompilationUnitDocumentProvider()); |
| setEditorContextMenuId("#CompilationUnitEditorContext"); //$NON-NLS-1$ |
| setRulerContextMenuId("#CompilationUnitRulerContext"); //$NON-NLS-1$ |
| setOutlinerContextMenuId("#CompilationUnitOutlinerContext"); //$NON-NLS-1$ |
| // don't set help contextId, we install our own help context |
| fSavePolicy= null; |
| |
| fJavaEditorErrorTickUpdater= new JavaEditorErrorTickUpdater(this); |
| } |
| |
| /* |
| * @see AbstractTextEditor#createActions() |
| */ |
| protected void createActions() { |
| |
| super.createActions(); |
| |
| Action action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "CorrectionAssistProposal.", this, CORRECTIONASSIST_PROPOSALS); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.CORRECTION_ASSIST_PROPOSALS); |
| setAction("CorrectionAssistProposal", action); //$NON-NLS-1$ |
| markAsStateDependentAction("CorrectionAssistProposal", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.QUICK_FIX_ACTION); |
| |
| action= new ContentAssistAction(JavaEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); |
| setAction("ContentAssistProposal", action); //$NON-NLS-1$ |
| markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.CONTENT_ASSIST_ACTION); |
| |
| action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "ContentAssistContextInformation.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION); |
| setAction("ContentAssistContextInformation", action); //$NON-NLS-1$ |
| markAsStateDependentAction("ContentAssistContextInformation", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.PARAMETER_HINTS_ACTION); |
| |
| action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "ContentAssistCompletePrefix.", this, CONTENTASSIST_COMPLETE_PREFIX); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.CONTENT_ASSIST_COMPLETE_PREFIX); |
| setAction("ContentAssistCompletePrefix", action); //$NON-NLS-1$ |
| markAsStateDependentAction("ContentAssistCompletePrefix", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.PARAMETER_HINTS_ACTION); |
| |
| action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.COMMENT); |
| setAction("Comment", action); //$NON-NLS-1$ |
| markAsStateDependentAction("Comment", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.COMMENT_ACTION); |
| |
| action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.UNCOMMENT); |
| setAction("Uncomment", action); //$NON-NLS-1$ |
| markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.UNCOMMENT_ACTION); |
| |
| action= new ToggleCommentAction(JavaEditorMessages.getResourceBundle(), "ToggleComment.", this); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.TOGGLE_COMMENT); |
| setAction("ToggleComment", action); //$NON-NLS-1$ |
| markAsStateDependentAction("ToggleComment", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.TOGGLE_COMMENT_ACTION); |
| configureToggleCommentAction(); |
| |
| action= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.FORMAT); |
| setAction("Format", action); //$NON-NLS-1$ |
| markAsStateDependentAction("Format", true); //$NON-NLS-1$ |
| markAsSelectionDependentAction("Format", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.FORMAT_ACTION); |
| |
| action= new AddBlockCommentAction(JavaEditorMessages.getResourceBundle(), "AddBlockComment.", this); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.ADD_BLOCK_COMMENT); |
| setAction("AddBlockComment", action); //$NON-NLS-1$ |
| markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$ |
| markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION); |
| |
| action= new RemoveBlockCommentAction(JavaEditorMessages.getResourceBundle(), "RemoveBlockComment.", this); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT); |
| setAction("RemoveBlockComment", action); //$NON-NLS-1$ |
| markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$ |
| markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.REMOVE_BLOCK_COMMENT_ACTION); |
| |
| action= new IndentAction(JavaEditorMessages.getResourceBundle(), "Indent.", this, false); //$NON-NLS-1$ |
| action.setActionDefinitionId(IJavaEditorActionDefinitionIds.INDENT); |
| setAction("Indent", action); //$NON-NLS-1$ |
| markAsStateDependentAction("Indent", true); //$NON-NLS-1$ |
| markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$ |
| WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION); |
| |
| action= new IndentAction(JavaEditorMessages.getResourceBundle(), "Indent.", this, true); //$NON-NLS-1$ |
| setAction("IndentOnTab", action); //$NON-NLS-1$ |
| markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$ |
| markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$ |
| |
| if (getNewPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) { |
| // don't replace Shift Right - have to make sure their enablement is mutually exclusive |
| // removeActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT); |
| setActionActivationCode("IndentOnTab", '\t', -1, SWT.NONE); //$NON-NLS-1$ |
| } |
| |
| fGenerateActionGroup= new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); |
| ActionGroup rg= new RefactorActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); |
| |
| fActionGroups.addGroup(rg); |
| fActionGroups.addGroup(fGenerateActionGroup); |
| |
| // We have to keep the context menu group separate to have better control over positioning |
| fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] { |
| fGenerateActionGroup, |
| rg, |
| new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)}); |
| } |
| |
| /* |
| * @see JavaEditor#getElementAt(int) |
| */ |
| protected IJavaElement getElementAt(int offset) { |
| return getElementAt(offset, true); |
| } |
| |
| /** |
| * Returns the most narrow element including the given offset. If <code>reconcile</code> |
| * is <code>true</code> the editor's input element is reconciled in advance. If it is |
| * <code>false</code> this method only returns a result if the editor's input element |
| * does not need to be reconciled. |
| * |
| * @param offset the offset included by the retrieved element |
| * @param reconcile <code>true</code> if working copy should be reconciled |
| * @return the most narrow element which includes the given offset |
| */ |
| protected IJavaElement getElementAt(int offset, boolean reconcile) { |
| IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager(); |
| ICompilationUnit unit= manager.getWorkingCopy(getEditorInput()); |
| |
| if (unit != null) { |
| try { |
| if (reconcile) { |
| synchronized (unit) { |
| unit.reconcile(false, false, null, null); |
| } |
| return unit.getElementAt(offset); |
| } else if (unit.isConsistent()) |
| return unit.getElementAt(offset); |
| |
| } catch (JavaModelException x) { |
| if (!x.isDoesNotExist()) |
| JavaPlugin.log(x.getStatus()); |
| // nothing found, be tolerant and go on |
| } |
| } |
| |
| return null; |
| } |
| |
| /* |
| * @see JavaEditor#getCorrespondingElement(IJavaElement) |
| */ |
| protected IJavaElement getCorrespondingElement(IJavaElement element) { |
| // TODO: With new working copy story: original == working copy. |
| // Note that the previous code could result in a reconcile as side effect. Should check if that |
| // is still required. |
| return element; |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#getInputElement() |
| */ |
| protected IJavaElement getInputJavaElement() { |
| return JavaPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(getEditorInput()); |
| } |
| |
| /* |
| * @see AbstractTextEditor#editorContextMenuAboutToShow(IMenuManager) |
| */ |
| public void editorContextMenuAboutToShow(IMenuManager menu) { |
| super.editorContextMenuAboutToShow(menu); |
| |
| ActionContext context= new ActionContext(getSelectionProvider().getSelection()); |
| fContextMenuGroup.setContext(context); |
| fContextMenuGroup.fillContextMenu(menu); |
| fContextMenuGroup.setContext(null); |
| } |
| |
| /* |
| * @see JavaEditor#setOutlinePageInput(JavaOutlinePage, IEditorInput) |
| */ |
| protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input) { |
| if (page != null) { |
| IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager(); |
| page.setInput(manager.getWorkingCopy(input)); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.ui.texteditor.AbstractTextEditor#performSave(boolean, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) { |
| IDocumentProvider p= getDocumentProvider(); |
| if (p instanceof ICompilationUnitDocumentProvider) { |
| ICompilationUnitDocumentProvider cp= (ICompilationUnitDocumentProvider) p; |
| cp.setSavePolicy(fSavePolicy); |
| } |
| try { |
| super.performSave(overwrite, progressMonitor); |
| } finally { |
| if (p instanceof ICompilationUnitDocumentProvider) { |
| ICompilationUnitDocumentProvider cp= (ICompilationUnitDocumentProvider) p; |
| cp.setSavePolicy(null); |
| } |
| } |
| } |
| |
| /* |
| * @see AbstractTextEditor#doSave(IProgressMonitor) |
| */ |
| public void doSave(IProgressMonitor progressMonitor) { |
| |
| IDocumentProvider p= getDocumentProvider(); |
| if (p == null) { |
| // editor has been closed |
| return; |
| } |
| |
| if (p.isDeleted(getEditorInput())) { |
| |
| if (isSaveAsAllowed()) { |
| |
| /* |
| * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. |
| * Changed Behavior to make sure that if called inside a regular save (because |
| * of deletion of input element) there is a way to report back to the caller. |
| */ |
| performSaveAs(progressMonitor); |
| |
| } else { |
| |
| /* |
| * 1GF5YOX: ITPJUI:ALL - Save of delete file claims it's still there |
| * Missing resources. |
| */ |
| Shell shell= getSite().getShell(); |
| MessageDialog.openError(shell, JavaEditorMessages.getString("CompilationUnitEditor.error.saving.title1"), JavaEditorMessages.getString("CompilationUnitEditor.error.saving.message1")); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| } else { |
| |
| setStatusLineErrorMessage(null); |
| |
| IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager(); |
| ICompilationUnit unit= manager.getWorkingCopy(getEditorInput()); |
| |
| if (unit != null) { |
| synchronized (unit) { |
| performSave(false, progressMonitor); |
| } |
| } else |
| performSave(false, progressMonitor); |
| } |
| } |
| |
| public boolean isSaveAsAllowed() { |
| return true; |
| } |
| |
| /** |
| * The compilation unit editor implementation of this <code>AbstractTextEditor</code> |
| * method asks the user for the workspace path of a file resource and saves the document |
| * there. See http://dev.eclipse.org/bugs/show_bug.cgi?id=6295 |
| * |
| * @param progressMonitor the progress monitor |
| */ |
| protected void performSaveAs(IProgressMonitor progressMonitor) { |
| |
| Shell shell= getSite().getShell(); |
| IEditorInput input = getEditorInput(); |
| |
| SaveAsDialog dialog= new SaveAsDialog(shell); |
| |
| IFile original= (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null; |
| if (original != null) |
| dialog.setOriginalFile(original); |
| |
| dialog.create(); |
| |
| |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider == null) { |
| // editor has been programmatically closed while the dialog was open |
| return; |
| } |
| |
| if (provider.isDeleted(input) && original != null) { |
| String message= JavaEditorMessages.getFormattedString("CompilationUnitEditor.warning.save.delete", new Object[] { original.getName() }); //$NON-NLS-1$ |
| dialog.setErrorMessage(null); |
| dialog.setMessage(message, IMessageProvider.WARNING); |
| } |
| |
| if (dialog.open() == Window.CANCEL) { |
| if (progressMonitor != null) |
| progressMonitor.setCanceled(true); |
| return; |
| } |
| |
| IPath filePath= dialog.getResult(); |
| if (filePath == null) { |
| if (progressMonitor != null) |
| progressMonitor.setCanceled(true); |
| return; |
| } |
| |
| IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot(); |
| IFile file= workspaceRoot.getFile(filePath); |
| final IEditorInput newInput= new FileEditorInput(file); |
| |
| boolean success= false; |
| try { |
| |
| provider.aboutToChange(newInput); |
| getDocumentProvider().saveDocument(progressMonitor, newInput, getDocumentProvider().getDocument(getEditorInput()), true); |
| success= true; |
| |
| } catch (CoreException x) { |
| ErrorDialog.openError(shell, JavaEditorMessages.getString("CompilationUnitEditor.error.saving.title2"), JavaEditorMessages.getString("CompilationUnitEditor.error.saving.message2"), x.getStatus()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } finally { |
| provider.changed(newInput); |
| if (success) |
| setInput(newInput); |
| } |
| |
| if (progressMonitor != null) |
| progressMonitor.setCanceled(!success); |
| } |
| |
| /* |
| * @see AbstractTextEditor#doSetInput(IEditorInput) |
| */ |
| protected void doSetInput(IEditorInput input) throws CoreException { |
| super.doSetInput(input); |
| configureTabConverter(); |
| |
| configureToggleCommentAction(); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#installOverrideIndicator(boolean) |
| * @since 3.0 |
| */ |
| protected void installOverrideIndicator(boolean waitForReconcilation) { |
| IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); |
| if (!waitForReconcilation) |
| super.installOverrideIndicator(false); |
| else { |
| uninstallOverrideIndicator(); |
| IJavaElement inputElement= getInputJavaElement(); |
| if (model == null || inputElement == null) |
| return; |
| |
| fOverrideIndicatorManager= new OverrideIndicatorManager(model, inputElement, null); |
| addReconcileListener(fOverrideIndicatorManager); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#uninstallOverrideIndicator() |
| * @since 3.0 |
| */ |
| protected void uninstallOverrideIndicator() { |
| if (fOverrideIndicatorManager != null) |
| removeReconcileListener(fOverrideIndicatorManager); |
| super.uninstallOverrideIndicator(); |
| } |
| |
| /** |
| * Configures the toggle comment action |
| * |
| * @since 3.0 |
| */ |
| private void configureToggleCommentAction() { |
| IAction action= getAction("ToggleComment"); //$NON-NLS-1$ |
| if (action instanceof ToggleCommentAction) { |
| ISourceViewer sourceViewer= getSourceViewer(); |
| SourceViewerConfiguration configuration= getSourceViewerConfiguration(); |
| ((ToggleCommentAction)action).configure(sourceViewer, configuration); |
| } |
| } |
| |
| private void configureTabConverter() { |
| if (fTabConverter != null) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof ICompilationUnitDocumentProvider) { |
| ICompilationUnitDocumentProvider cup= (ICompilationUnitDocumentProvider) provider; |
| fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput())); |
| } |
| } |
| } |
| |
| private int getTabSize() { |
| Preferences preferences= JavaCore.getPlugin().getPluginPreferences(); |
| return preferences.getInt(CODE_FORMATTER_TAB_SIZE); |
| } |
| |
| private void startTabConversion() { |
| if (fTabConverter == null) { |
| fTabConverter= new TabConverter(); |
| configureTabConverter(); |
| fTabConverter.setNumberOfSpacesPerTab(getTabSize()); |
| AdaptedSourceViewer asv= (AdaptedSourceViewer) getSourceViewer(); |
| asv.addTextConverter(fTabConverter); |
| // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270 |
| asv.updateIndentationPrefixes(); |
| } |
| } |
| |
| private void stopTabConversion() { |
| if (fTabConverter != null) { |
| AdaptedSourceViewer asv= (AdaptedSourceViewer) getSourceViewer(); |
| asv.removeTextConverter(fTabConverter); |
| // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270 |
| asv.updateIndentationPrefixes(); |
| fTabConverter= null; |
| } |
| } |
| |
| private boolean isTabConversionEnabled() { |
| IPreferenceStore store= getNewPreferenceStore(); |
| return store.getBoolean(SPACES_FOR_TABS); |
| } |
| |
| public void dispose() { |
| |
| ISourceViewer sourceViewer= getSourceViewer(); |
| if (sourceViewer instanceof ITextViewerExtension) |
| ((ITextViewerExtension) sourceViewer).removeVerifyKeyListener(fBracketInserter); |
| |
| if (fJavaEditorErrorTickUpdater != null) { |
| fJavaEditorErrorTickUpdater.dispose(); |
| fJavaEditorErrorTickUpdater= null; |
| } |
| |
| if (fActionGroups != null) { |
| fActionGroups.dispose(); |
| fActionGroups= null; |
| } |
| |
| super.dispose(); |
| } |
| |
| /* |
| * @see AbstractTextEditor#createPartControl(Composite) |
| */ |
| public void createPartControl(Composite parent) { |
| |
| super.createPartControl(parent); |
| |
| if (isTabConversionEnabled()) |
| startTabConversion(); |
| |
| IPreferenceStore preferenceStore= getNewPreferenceStore(); |
| boolean closeBrackets= preferenceStore.getBoolean(CLOSE_BRACKETS); |
| boolean closeStrings= preferenceStore.getBoolean(CLOSE_STRINGS); |
| |
| fBracketInserter.setCloseBracketsEnabled(closeBrackets); |
| fBracketInserter.setCloseStringsEnabled(closeStrings); |
| |
| ISourceViewer sourceViewer= getSourceViewer(); |
| if (sourceViewer instanceof ITextViewerExtension) |
| ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter); |
| |
| } |
| |
| private static char getEscapeCharacter(char character) { |
| switch (character) { |
| case '"': |
| case '\'': |
| return '\\'; |
| default: |
| return 0; |
| } |
| } |
| |
| private static char getPeerCharacter(char character) { |
| switch (character) { |
| case '(': |
| return ')'; |
| |
| case ')': |
| return '('; |
| |
| case '[': |
| return ']'; |
| |
| case ']': |
| return '['; |
| |
| case '"': |
| return character; |
| |
| case '\'': |
| return character; |
| |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /* |
| * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) |
| */ |
| protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { |
| |
| try { |
| |
| AdaptedSourceViewer asv= (AdaptedSourceViewer) getSourceViewer(); |
| if (asv != null) { |
| |
| String p= event.getProperty(); |
| |
| if (CLOSE_BRACKETS.equals(p)) { |
| fBracketInserter.setCloseBracketsEnabled(getNewPreferenceStore().getBoolean(p)); |
| return; |
| } |
| |
| if (CLOSE_STRINGS.equals(p)) { |
| fBracketInserter.setCloseStringsEnabled(getNewPreferenceStore().getBoolean(p)); |
| return; |
| } |
| |
| if (SPACES_FOR_TABS.equals(p)) { |
| if (isTabConversionEnabled()) |
| startTabConversion(); |
| else |
| stopTabConversion(); |
| return; |
| } |
| |
| if (PreferenceConstants.EDITOR_SMART_TAB.equals(p)) { |
| if (getNewPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) { |
| setActionActivationCode("IndentOnTab", '\t', -1, SWT.NONE); //$NON-NLS-1$ |
| } else { |
| removeActionActivationCode("IndentOnTab"); //$NON-NLS-1$ |
| } |
| } |
| |
| IContentAssistant c= asv.getContentAssistant(); |
| if (c instanceof ContentAssistant) |
| ContentAssistPreference.changeConfiguration((ContentAssistant) c, getNewPreferenceStore(), event); |
| |
| if (CODE_FORMATTER_TAB_SIZE.equals(p)) { |
| asv.updateIndentationPrefixes(); |
| if (fTabConverter != null) |
| fTabConverter.setNumberOfSpacesPerTab(getTabSize()); |
| } |
| } |
| |
| } finally { |
| super.handlePreferenceStoreChanged(event); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#createJavaSourceViewer(org.eclipse.swt.widgets.Composite, org.eclipse.jface.text.source.IVerticalRuler, org.eclipse.jface.text.source.IOverviewRuler, boolean, int) |
| */ |
| protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean isOverviewRulerVisible, int styles) { |
| return new AdaptedSourceViewer(parent, verticalRuler, overviewRuler, isOverviewRulerVisible, styles); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled() |
| * @since 3.0 |
| */ |
| public void aboutToBeReconciled() { |
| |
| // Notify AST provider |
| JavaPlugin.getDefault().getASTProvider().aboutToBeReconciled(getInputJavaElement()); |
| |
| // Notify listeners |
| synchronized (fReconcilingListeners) { |
| Object[] listeners = fReconcilingListeners.getListeners(); |
| for (int i = 0, length= listeners.length; i < length; ++i) |
| ((IJavaReconcilingListener)listeners[i]).aboutToBeReconciled(); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(org.eclipse.jdt.core.dom.CompilationUnit, boolean, boolean) |
| * @since 3.0 |
| */ |
| public void reconciled(CompilationUnit ast, boolean cancelled, boolean forced) { |
| |
| // Always notify AST provider |
| JavaPlugin.getDefault().getASTProvider().reconciled(ast, getInputJavaElement()); |
| |
| // Notify listeners |
| synchronized (fReconcilingListeners) { |
| Object[] listeners = fReconcilingListeners.getListeners(); |
| for (int i = 0, length= listeners.length; i < length; ++i) |
| ((IJavaReconcilingListener)listeners[i]).reconciled(ast, cancelled, forced); |
| } |
| |
| // Update Java Outline page selection |
| if (!forced && !cancelled) { |
| Shell shell= getSite().getShell(); |
| if (shell != null && !shell.isDisposed()) { |
| shell.getDisplay().asyncExec(new Runnable() { |
| public void run() { |
| selectionChanged(); |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * Tells whether this is the active editor in the active page. |
| * |
| * @return <code>true</code> if this is the active editor in the active page |
| * @see IWorkbenchPage#getActiveEditor(); |
| */ |
| protected final boolean isActiveEditor() { |
| IWorkbenchWindow window= getSite().getWorkbenchWindow(); |
| IWorkbenchPage page= window.getActivePage(); |
| if (page == null) |
| return false; |
| IEditorPart activeEditor= page.getActiveEditor(); |
| return activeEditor != null && activeEditor.equals(this); |
| } |
| |
| /** |
| * Adds the given listener. |
| * Has no effect if an identical listener was not already registered. |
| * |
| * @param listener The reconcile listener to be added |
| * @since 3.0 |
| */ |
| final void addReconcileListener(IJavaReconcilingListener listener) { |
| synchronized (fReconcilingListeners) { |
| fReconcilingListeners.add(listener); |
| } |
| } |
| |
| /** |
| * Removes the given listener. |
| * Has no effect if an identical listener was not already registered. |
| * |
| * @param listener the reconcile listener to be removed |
| * @since 3.0 |
| */ |
| final void removeReconcileListener(IJavaReconcilingListener listener) { |
| synchronized (fReconcilingListeners) { |
| fReconcilingListeners.remove(listener); |
| } |
| } |
| |
| protected void updateStateDependentActions() { |
| super.updateStateDependentActions(); |
| fGenerateActionGroup.editorStateChanged(); |
| } |
| |
| /* |
| * @see AbstractTextEditor#rememberSelection() |
| */ |
| protected void rememberSelection() { |
| fRememberedSelection.remember(); |
| } |
| |
| /* |
| * @see AbstractTextEditor#restoreSelection() |
| */ |
| protected void restoreSelection() { |
| fRememberedSelection.restore(); |
| } |
| |
| /* |
| * @see AbstractTextEditor#canHandleMove(IEditorInput, IEditorInput) |
| */ |
| protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) { |
| |
| String oldExtension= ""; //$NON-NLS-1$ |
| if (originalElement instanceof IFileEditorInput) { |
| IFile file= ((IFileEditorInput) originalElement).getFile(); |
| if (file != null) { |
| String ext= file.getFileExtension(); |
| if (ext != null) |
| oldExtension= ext; |
| } |
| } |
| |
| String newExtension= ""; //$NON-NLS-1$ |
| if (movedElement instanceof IFileEditorInput) { |
| IFile file= ((IFileEditorInput) movedElement).getFile(); |
| if (file != null) |
| newExtension= file.getFileExtension(); |
| } |
| |
| return oldExtension.equals(newExtension); |
| } |
| |
| /* |
| * @see org.eclipse.ui.texteditor.ExtendedTextEditor#isPrefQuickDiffAlwaysOn() |
| */ |
| protected boolean isPrefQuickDiffAlwaysOn() { |
| // reestablishes the behaviour from ExtendedTextEditor which was hacked by JavaEditor |
| // to disable the change bar for the class file (attached source) java editor. |
| IPreferenceStore store= getNewPreferenceStore(); |
| return store.getBoolean(ExtendedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON); |
| } |
| |
| } |