From d046e0a25f62e7737651246adc56a3052a21b42e Mon Sep 17 00:00:00 2001 From: Andrew Eidsness Date: Tue, 10 Dec 2013 21:08:26 -0500 Subject: [PATCH] Bug 423679: CEditor navigation actions disabled outside of CEditor The Open Declaration (F3), etc. actions use code in the ASTProvider. If the provider is not able to get an AST then the actions are disabled. The implementation of the ASTProvider has an "instanceof CEditor" check the result being that ASTProvider can only be used when the editor is a CEditor. This breaks our use case where we have a CEditor embedded as a tab in a multi-pane editor (see org.eclipse.papyrus.infra.core.sasheditor .editor.AbstractMultiPageSashEditor). This patch modifies the ASTProvider to use #getAdapter instead of only the instanceof check. I've kept the common case (where the editor is a CEditor) unchanged and added the new code as extra handling. I've also introduced a public interface, ITranslationUnitProvider, to avoid forcing clients to adapt to the internal CEditor class. The only part of CEditor that ASTProvider cares about is the ITranslationUnit. The existing implementation has an unchecked cast. The new interface provides the required type directly. Change-Id: Ie7e68e8909928374fa11fe2b8a857f09d042fb5c Signed-off-by: Andrew Eidsness Reviewed-on: https://git.eclipse.org/r/20026 Tested-by: Hudson CI Reviewed-by: Doug Schaefer IP-Clean: Doug Schaefer --- .../core/model/ITranslationUnitHolder.java | 23 +++++++ .../cdt/internal/ui/editor/ASTProvider.java | 41 ++++++++---- .../cdt/internal/ui/editor/CEditor.java | 11 +++- .../search/actions/SelectionParseAction.java | 8 +-- .../cdt/internal/ui/util/EditorUtility.java | 66 +++++++++++-------- 5 files changed, 102 insertions(+), 47 deletions(-) create mode 100644 core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ITranslationUnitHolder.java diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ITranslationUnitHolder.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ITranslationUnitHolder.java new file mode 100644 index 00000000000..29f978627fe --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ITranslationUnitHolder.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Zeligsoft (2009) Limited. + * 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 + */ +package org.eclipse.cdt.core.model; + +/** + * Represents a workbench object that is able to provide instances of ITranslationUnit. For + * example, the CEditor (in the CDT UI plugin) implements this interface in order to provide + * the IWorkingCopy of the editor's active translation unit. + * + * @since 5.6 + */ +public interface ITranslationUnitHolder { + /** + * Returns the translation unit that is provided by the receiver or null if there is no + * such translation unit. + */ + public ITranslationUnit getTranslationUnit(); +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java index 209e91e9fc4..caa5742d74e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ASTProvider.java @@ -20,6 +20,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbenchPart; @@ -33,6 +34,7 @@ import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.model.ITranslationUnitHolder; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.core.model.ASTCache; @@ -41,7 +43,7 @@ import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; /** * Provides a shared AST for clients. The shared AST is * the AST of the active CEditor's input element. - * + * * @since 4.0 */ public final class ASTProvider { @@ -69,7 +71,7 @@ public final class ASTProvider { * wants to wait until an AST is ready. If the translation unit is not open no AST will * be provided. *

- * If not yet cached and if the translation unit is open, an AST will be created by + * If not yet cached and if the translation unit is open, an AST will be created by * this AST provider. *

*/ @@ -77,7 +79,7 @@ public final class ASTProvider { /** * Wait flag indicating that a client requesting an AST - * only wants to wait for the shared AST of the active editor. + * only wants to wait for the shared AST of the active editor. * If the translation unit is not open no AST will be provided. *

* No AST will be created by the AST provider. @@ -222,7 +224,17 @@ public final class ASTProvider { return false; String id= ref.getId(); - return CUIPlugin.EDITOR_ID.equals(id) || ref.getPart(false) instanceof CEditor; + if (CUIPlugin.EDITOR_ID.equals(id)) + return true; + + IWorkbenchPart part = ref.getPart(false); + if (part instanceof CEditor) + return true; + + // Other editors can behave as CEditors if they can provide a copy of their ITranslationUnit. + if (part instanceof IEditorPart) + return part.getAdapter(ITranslationUnitHolder.class) != null; + return false; } } @@ -233,7 +245,7 @@ public final class ASTProvider { /** * Returns the C plug-in's AST provider. - * + * * @return the AST provider */ public static ASTProvider getASTProvider() { @@ -264,14 +276,17 @@ public final class ASTProvider { } private void activeEditorChanged(IWorkbenchPart editor) { - ICElement cElement= null; - if (editor instanceof CEditor) { - cElement= ((CEditor) editor).getInputCElement(); + ITranslationUnit tu = null; + if (editor != null) { + ITranslationUnitHolder provider = (ITranslationUnitHolder) editor.getAdapter(ITranslationUnitHolder.class); + if (provider != null) + tu = provider.getTranslationUnit(); } + synchronized (this) { fActiveEditor= editor; fTimeStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; - fCache.setActiveElement((ITranslationUnit) cElement); + fCache.setActiveElement(tu); } } @@ -343,7 +358,7 @@ public final class ASTProvider { * Executes {@link ASTRunnable#runOnAST(ILanguage, IASTTranslationUnit)} * with the shared AST for the given translation unit. Handles acquiring * and releasing the index read-lock for the client. - * + * * @param cElement the translation unit * @param waitFlag condition for waiting for the AST to be built. * @param monitor a progress monitor, may be null @@ -368,7 +383,7 @@ public final class ASTProvider { *

* An index lock must be held by the caller when calling this method. The index lock may * not be released until the AST is released. - * + * * @param tu The translation unit to get the AST for. * @param index index with read lock held. * @param waitFlag condition for waiting for the AST to be built. @@ -396,7 +411,7 @@ public final class ASTProvider { /** * Prepares the AST cache to be used for the given translation unit. - * + * * @param tu the translation unit. * @param waitFlag condition for waiting for the AST to be built. * @return true if the AST cache can be used for the given translation unit, @@ -407,7 +422,7 @@ public final class ASTProvider { return false; // http://bugs.eclipse.org/bugs/show_bug.cgi?id=342506 explains - // benign nature of the race conditions in the code below. + // benign nature of the race conditions in the code below. final boolean isActive= fCache.isActiveElement(tu); if (waitFlag == WAIT_ACTIVE_ONLY && !isActive) { return false; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java index d3e294133a6..f8ade41240f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java @@ -184,6 +184,7 @@ import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ISourceRange; import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.model.ITranslationUnitHolder; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.ICEditor; @@ -241,7 +242,7 @@ import org.eclipse.cdt.internal.ui.viewsupport.SelectionListenerWithASTManager; /** * C/C++ source editor. */ -public class CEditor extends TextEditor implements ICEditor, ISelectionChangedListener, ICReconcilingListener { +public class CEditor extends TextEditor implements ICEditor, ISelectionChangedListener, ICReconcilingListener, ITranslationUnitHolder { /** Marker used for synchronization from Problems View to the editor on double-click. */ private IMarker fSyncProblemsViewMarker; @@ -1514,6 +1515,11 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(getEditorInput()); } + @Override + public ITranslationUnit getTranslationUnit() { + return getInputCElement(); + } + /** * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed() */ @@ -1575,7 +1581,8 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi fTemplatesPage = new CTemplatesPage(this); } return fTemplatesPage; - } + } else if (adapterClass.isAssignableFrom(ITranslationUnitHolder.class)) + return this; return super.getAdapter(adapterClass); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/SelectionParseAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/SelectionParseAction.java index 7adfed80841..14993394eec 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/SelectionParseAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/SelectionParseAction.java @@ -89,8 +89,8 @@ public class SelectionParseAction extends Action { clearStatusLine(); IEditorPart editor = EditorUtility.openInEditor(path, fEditor.getInputCElement()); - if (editor instanceof ITextEditor) { - ITextEditor textEditor = (ITextEditor) editor; + ITextEditor textEditor = EditorUtility.getTextEditor(editor); + if (textEditor != null) { textEditor.selectAndReveal(currentOffset, currentLength); } else { reportSourceFileOpenFailure(path); @@ -101,8 +101,8 @@ public class SelectionParseAction extends Action { clearStatusLine(); IEditorPart editor = EditorUtility.openInEditor(tu, true); - if (editor instanceof ITextEditor) { - ITextEditor textEditor = (ITextEditor) editor; + ITextEditor textEditor = EditorUtility.getTextEditor(editor); + if (textEditor != null) { textEditor.selectAndReveal(currentOffset, currentLength); } else { reportSourceFileOpenFailure(tu.getPath()); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java index d55ab6e0bc2..01213d138a2 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java @@ -338,7 +338,7 @@ public class EditorUtility { IEditorInput input= getEditorInputForLocation(location, element); return EditorUtility.openInEditor(input, getEditorID(input, element), activate); } - + public static IEditorPart openInEditor(URI locationURI, ICElement element) throws PartInitException { IEditorInput input= getEditorInputForLocation(locationURI, element); return EditorUtility.openInEditor(input, getEditorID(input, element), true); @@ -376,7 +376,7 @@ public class EditorUtility { IPath path = URIUtil.toPath(locationURI); if(path == null) path = new Path(locationURI.getPath()); - + if (includeReferences[j].isOnIncludeEntry(path)) { context = projects[i]; break outerFor; @@ -405,7 +405,7 @@ public class EditorUtility { e.printStackTrace(); return null; } - + if(fileStore != null) return new ExternalEditorInput(unit); } @@ -486,18 +486,18 @@ public class EditorUtility { IFile file= ResourceLookup.selectFileForLocation(location, project); if (file != null && file.isAccessible()) return file; - + IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); // workaround http://bugs.eclipse.org/233939 file= root.getFileForLocation(location); - if (file != null && file.isAccessible()) + if (file != null && file.isAccessible()) return file; // try workspace relative path if (location.segmentCount() >= 2) { // @see IContainer#getFile for the required number of segments file= root.getFile(location); - if (file != null && file.isAccessible()) + if (file != null && file.isAccessible()) return file; } return null; @@ -520,14 +520,14 @@ public class EditorUtility { project= cProject.getProject(); } } - + IFile file= ResourceLookup.selectFileForLocationURI(locationURI, project); if (file != null && file.isAccessible()) return file; - + return null; } - + /** * If the current active editor edits a c element return it, else * return null @@ -722,7 +722,7 @@ public class EditorUtility { String newModifierString= Action.findModifierString(modifier); if (modifierString.length() == 0) return newModifierString; - return NLS.bind(CEditorMessages.EditorUtility_concatModifierStrings, new String[] {modifierString, newModifierString}); + return NLS.bind(CEditorMessages.EditorUtility_concatModifierStrings, new String[] {modifierString, newModifierString}); } public static IStorage getStorage(IBinary bin) { @@ -869,10 +869,10 @@ public class EditorUtility { } } - if (!(ep instanceof ITextEditor)) + ITextEditor textEditor = getTextEditor(ep); + if (textEditor == null) return saveUnknownEditors; - ITextEditor textEditor= (ITextEditor) ep; IDocumentProvider documentProvider= textEditor.getDocumentProvider(); if (!(documentProvider instanceof TextFileDocumentProvider)) return saveUnknownEditors; @@ -885,7 +885,7 @@ public class EditorUtility { * last save occurred. Each region in the result spans over the size of at least one line. * If successive lines have changed a region spans over the size of all successive lines. * The regions include line delimiters. - * + * * @param buffer the buffer to compare contents from * @param monitor to report progress to * @return the regions of the changed lines @@ -896,7 +896,7 @@ public class EditorUtility { final IProgressMonitor monitor) throws CoreException { final IRegion[][] result= new IRegion[1][]; final IStatus[] errorStatus= new IStatus[] { Status.OK_STATUS }; - + try { SafeRunner.run(new ISafeRunnable() { /* @@ -912,7 +912,7 @@ public class EditorUtility { ICStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, msg, exception); result[0]= null; } - + /* * @see org.eclipse.core.runtime.ISafeRunnable#run() */ @@ -920,14 +920,14 @@ public class EditorUtility { public void run() throws Exception { monitor.beginTask(Messages.EditorUtility_calculatingChangedRegions_message, 20); IFileStore fileStore= buffer.getFileStore(); - + ITextFileBufferManager fileBufferManager= FileBuffers.createTextFileBufferManager(); fileBufferManager.connectFileStore(fileStore, getSubProgressMonitor(monitor, 15)); try { IDocument currentDocument= buffer.getDocument(); - IDocument oldDocument= + IDocument oldDocument= ((ITextFileBuffer) fileBufferManager.getFileStoreFileBuffer(fileStore)).getDocument(); - + result[0]= getChangedLineRegions(oldDocument, currentDocument); } finally { fileBufferManager.disconnectFileStore(fileStore, getSubProgressMonitor(monitor, 5)); @@ -938,7 +938,7 @@ public class EditorUtility { /** * Return regions of all lines which differ comparing oldDocuments content * with currentDocuments content. Successive lines are merged into one region. - * + * * @param oldDocument a document containing the old content * @param currentDocument a document containing the current content * @return the changed regions @@ -973,7 +973,7 @@ public class EditorUtility { startLineRegion = currentDocument.getLineInformation(startLine); if (startLine >= endLine) { // startLine > endLine indicates a deletion of one or more lines. - // Deletions are ignored except at the end of the document. + // Deletions are ignored except at the end of the document. if (startLine == endLine || startLineRegion.getOffset() + startLineRegion.getLength() == currentDocument.getLength()) { regions.add(startLineRegion); @@ -997,7 +997,7 @@ public class EditorUtility { if (!errorStatus[0].isOK()) throw new CoreException(errorStatus[0]); } - + return result[0]; } @@ -1015,13 +1015,13 @@ public class EditorUtility { return new NullProgressMonitor(); } - - + + /** * Returns the project contains the resource, which is currently open in the active editor. - * If the active part is no ITextEditor or if the editorInput is no FileEditorInput, + * If the active part is no ITextEditor or if the editorInput is no FileEditorInput, * null is returned. - * + * * @return the project which the selected editor input belongs to or null */ public static IProject getProjectForActiveEditor() { @@ -1030,9 +1030,9 @@ public class EditorUtility { if(window != null) { IWorkbenchPage activePage = window.getActivePage(); if(activePage != null) { - IEditorPart activeEditor = activePage.getActiveEditor(); - if(activeEditor instanceof ITextEditor) { - IEditorInput editorInput = ((ITextEditor)activeEditor).getEditorInput(); + ITextEditor activeEditor = getTextEditor(activePage.getActiveEditor()); + if (activeEditor != null) { + IEditorInput editorInput = activeEditor.getEditorInput(); IFile file = ResourceUtil.getFile(editorInput); if(file != null) { project = file.getProject(); @@ -1042,4 +1042,14 @@ public class EditorUtility { } return project; } + + /** + * Tries to convert the given editor to an implementation of ITextEditor. Returns that implementation + * if possible and null otherwise. + * + * @param editor The editor to be converted or null if there is nothing to convert. + */ + public static ITextEditor getTextEditor(IEditorPart editor) { + return editor == null ? null : (ITextEditor) editor.getAdapter(ITextEditor.class); + } }