1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Fix for 87119: Shortcut to Toggle Header/Source

This commit is contained in:
Anton Leherbauer 2007-04-12 13:54:12 +00:00
parent 568b682abf
commit 86a79e05e8
8 changed files with 377 additions and 18 deletions

View file

@ -123,6 +123,9 @@ ActionDefinition.format.description=Format Source Code
ActionDefinition.gotoMatchingBracket.name= Go to Matching Bracket
ActionDefinition.gotoMatchingBracket.description= Moves the cursor to the matching bracket
ActionDefinition.toggleSourceHeader.name= Toggle Source/Header
ActionDefinition.toggleSourceHeader.description= Toggles between corresponding source and header files
CEditor.name=C/C++ Editor
CPluginPreferencePage.name=C/C++

View file

@ -1244,6 +1244,11 @@
contextId="org.eclipse.cdt.ui.cEditorScope"
commandId="org.eclipse.cdt.ui.edit.text.c.goto.matching.bracket"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
<key
sequence="M1+E"
contextId="org.eclipse.cdt.ui.cEditorScope"
commandId="org.eclipse.cdt.ui.edit.text.c.toggle.source.header"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
<extension
point="org.eclipse.ui.commands">
@ -1369,6 +1374,12 @@
categoryId="org.eclipse.cdt.ui.category.source"
id="org.eclipse.cdt.ui.edit.text.c.goto.matching.bracket">
</command>
<command
name="%ActionDefinition.toggleSourceHeader.name"
description="%ActionDefinition.toggleSourceHeader.description"
categoryId="org.eclipse.cdt.ui.category.source"
id="org.eclipse.cdt.ui.edit.text.c.toggle.source.header">
</command>
</extension>
<extension
id="pdomSearchPage"

View file

@ -41,10 +41,6 @@ import org.eclipse.cdt.internal.core.model.ASTCache;
*/
public final class ASTProvider {
public static interface ASTRunnable {
IStatus runOnAST(IASTTranslationUnit tu);
}
/**
* Wait flag.
*/

View file

@ -1882,6 +1882,10 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IR
action.setActionDefinitionId(ICEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER);
setAction(GoToNextPreviousMemberAction.NEXT_MEMBER, action);
action= new ToggleSourceAndHeaderAction(CEditorMessages.getResourceBundle(), "ToggleSourceHeader.", this); //$NON-NLS-1$
action.setActionDefinitionId(ICEditorActionDefinitionIds.TOGGLE_SOURCE_HEADER);
setAction("ToggleSourceHeader", action); //$NON-NLS-1$
//Assorted action groupings
fSelectionSearchGroup = new SelectionSearchGroup(this);
fTextSearchGroup= new TextSearchGroup(this);
@ -1921,6 +1925,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IR
addAction(menu, IContextMenuConstants.GROUP_OPEN, "OpenOutline"); //$NON-NLS-1$
addAction(menu, IContextMenuConstants.GROUP_OPEN, "OpenHierarchy"); //$NON-NLS-1$
addAction(menu, IContextMenuConstants.GROUP_OPEN, "ToggleSourceHeader"); //$NON-NLS-1$
}
ActionContext context= new ActionContext(getSelectionProvider().getSelection());

View file

@ -38,7 +38,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
private RetargetTextEditorAction fContextInformation;
private RetargetTextEditorAction fFormatter;
private RetargetTextEditorAction fAddInclude;
// private RetargetTextEditorAction fOpenOnSelection;
private RetargetTextEditorAction fOpenDeclaration;
private RetargetTextEditorAction fShiftLeft;
private RetargetTextEditorAction fShiftRight;
private TogglePresentationAction fTogglePresentation;
@ -49,6 +49,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
private RetargetTextEditorAction fGotoPreviousMemberAction;
private RetargetTextEditorAction fToggleInsertModeAction;
private RetargetTextEditorAction fShowOutline;
private RetargetTextEditorAction fToggleSourceHeader;
public CEditorActionContributor() {
super();
@ -75,14 +76,13 @@ public class CEditorActionContributor extends TextEditorActionContributor {
fAddInclude = new RetargetTextEditorAction(bundle, "AddIncludeOnSelection."); //$NON-NLS-1$
fAddInclude.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_INCLUDE);
// fOpenOnSelection = new RetargetTextEditorAction(bundle, "OpenOnSelection."); //$NON-NLS-1$
fOpenDeclaration = new RetargetTextEditorAction(bundle, "OpenDeclarations."); //$NON-NLS-1$
fOpenDeclaration.setActionDefinitionId(ICEditorActionDefinitionIds.OPEN_DECL);
// actions that are "contributed" to editors, they are considered belonging to the active editor
fTogglePresentation= new TogglePresentationAction();
fTogglePresentation.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_SHOW_SELECTED_ELEMENT_ONLY);
//fToggleTextHover= new ToggleTextHoverAction();
fPreviousAnnotation= new GotoAnnotationAction("PreviousAnnotation.", false); //$NON-NLS-1$
fNextAnnotation= new GotoAnnotationAction("NextAnnotation.", true); //$NON-NLS-1$
@ -100,6 +100,8 @@ public class CEditorActionContributor extends TextEditorActionContributor {
fShowOutline= new RetargetTextEditorAction(bundle, "OpenOutline."); //$NON-NLS-1$
fShowOutline.setActionDefinitionId(ICEditorActionDefinitionIds.OPEN_OUTLINE);
fToggleSourceHeader= new RetargetTextEditorAction(bundle, "ToggleSourceHeader."); //$NON-NLS-1$
fToggleSourceHeader.setActionDefinitionId(ICEditorActionDefinitionIds.TOGGLE_SOURCE_HEADER);
}
/*
@ -126,9 +128,10 @@ public class CEditorActionContributor extends TextEditorActionContributor {
IMenuManager navigateMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
if (navigateMenu != null) {
navigateMenu.appendToGroup(IWorkbenchActionConstants.OPEN_EXT, fOpenDeclaration);
navigateMenu.appendToGroup(IWorkbenchActionConstants.OPEN_EXT, fToggleSourceHeader);
navigateMenu.appendToGroup(IWorkbenchActionConstants.SHOW_EXT, fShowOutline);
// navigateMenu.appendToGroup(IWorkbenchActionConstants.SHOW_EXT, fOpenHierarchy);
// navigateMenu.appendToGroup(IWorkbenchActionConstants.SHOW_EXT, fOpenOnSelection);
IMenuManager gotoMenu= navigateMenu.findMenuUsingPath(IWorkbenchActionConstants.GO_TO);
if (gotoMenu != null) {
@ -176,7 +179,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
fContentAssist.setAction(getAction(textEditor, "ContentAssistProposal")); //$NON-NLS-1$
fContextInformation.setAction(getAction(textEditor, "ContentAssistContextInformation")); //$NON-NLS-1$
fAddInclude.setAction(getAction(textEditor, "AddIncludeOnSelection")); //$NON-NLS-1$
// fOpenOnSelection.setAction(getAction(textEditor, "OpenOnSelection")); //$NON-NLS-1$
fOpenDeclaration.setAction(getAction(textEditor, "OpenDeclarations")); //$NON-NLS-1$
fFormatter.setAction(getAction(textEditor, "Format")); //$NON-NLS-1$
fGotoMatchingBracket.setAction(getAction(textEditor, GotoMatchingBracketAction.GOTO_MATCHING_BRACKET));
@ -184,7 +187,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
fGotoPreviousMemberAction.setAction(getAction(textEditor, GoToNextPreviousMemberAction.PREVIOUS_MEMBER));
fShowOutline.setAction(getAction(textEditor, "OpenOutline")); //$NON-NLS-1$
fToggleSourceHeader.setAction(getAction(textEditor, "ToggleSourceHeader")); //$NON-NLS-1$
fToggleInsertModeAction.setAction(getAction(textEditor, ITextEditorActionConstants.TOGGLE_INSERT_MODE));
if (part instanceof CEditor) {

View file

@ -171,3 +171,8 @@ ToggleInsertMode.label=Sma&rt Insert Mode
ToggleInsertMode.tooltip=Toggle Smart Insert Mode
ToggleInsertMode.image=
ToggleInsertMode.description= Toggles smart insert mode
ToggleSourceHeader.label= To&ggle Source/Header
ToggleSourceHeader.tooltip= Toggle Source and Header File
ToggleInsertMode.image=
ToggleSourceHeader.description= Toggles between corresponding source and header file

View file

@ -173,11 +173,10 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition
public static final String GOTO_MATCHING_BRACKET= "org.eclipse.cdt.ui.edit.text.c.goto.matching.bracket"; //$NON-NLS-1$
/**
* Action definition ID of the edit -> show tooltip action
* (value <code>"org.eclipse.cdt.ui.edit.text.c.show.tooltip"</code>).
*
* @since 3.1.1
* @deprecated Use {@link ITextEditorActionDefinitionIds#SHOW_INFORMATION} instead.
* Action definition ID for toggle source/header action.
* (value <code>"org.eclipse.cdt.ui.edit.text.c.toggle.source.header"</code>)
*
* @since 4.0
*/
public static final String SHOW_TOOLTIP = ITextEditorActionDefinitionIds.SHOW_INFORMATION;
public static final String TOGGLE_SOURCE_HEADER = "org.eclipse.cdt.ui.edit.text.c.toggle.source.header"; //$NON-NLS-1$
}

View file

@ -0,0 +1,337 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems, Inc. 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:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.TextEditorAction;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IWorkingCopy;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.IWorkingCopyManager;
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
import org.eclipse.cdt.internal.ui.util.EditorUtility;
/**
* Editor action to toggle between source and header files.
*
* @since 4.0
*/
public class ToggleSourceAndHeaderAction extends TextEditorAction {
private static class Counter {
public int fCount;
}
/**
* Compute the partner file for a translation unit.
* The partner file is the corresponding source or header file
* based on heuristics.
*
* @since 4.0
*/
private static class PartnerFileComputer extends CPPASTVisitor implements ASTRunnable {
/**
* When this many times the same partner file is hit,
* we are confident enough to take it.
*/
private static final int CONFIDENCE_LIMIT = 15;
/**
* When this many times no match was found in the index,
* we suspect that we won't get a good partner.
*/
private static final int SUSPECT_LIMIT = 15;
private IIndex fIndex;
private IPath fFilePath;
private Map fMap;
/** The confidence level == number of hits */
private int fConfidence;
/** Suspect level == number of no index matches */
private int fSuspect;
/** The current favorite partner file */
private IPath fFavoriteLocation;
{
shouldVisitDeclarators= true;
}
public IStatus runOnAST(IASTTranslationUnit ast) {
fIndex= ast.getIndex();
fFilePath= Path.fromOSString(ast.getFilePath());
fMap= new HashMap();
if (fIndex != null) {
ast.accept(this);
}
return Status.OK_STATUS;
}
public IPath getPartnerFileLocation() {
return fFavoriteLocation;
}
/*
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTDeclarator)
*/
public int visit(IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator) {
IASTName name= declarator.getName();
if (name != null && declarator.getNestedDeclarator() == null) {
IBinding binding= name.resolveBinding();
if (binding != null && !(binding instanceof IProblemBinding)) {
boolean isDefinition= name.isDefinition();
final IIndexName[] partnerNames;
try {
if (isDefinition) {
partnerNames= fIndex.findNames(binding, IIndex.FIND_DECLARATIONS);
} else {
partnerNames= fIndex.findNames(binding, IIndex.FIND_DEFINITIONS);
}
if (partnerNames.length == 0) {
++fSuspect;
if (fSuspect == SUSPECT_LIMIT) {
fFavoriteLocation= null;
return PROCESS_ABORT;
}
}
for (int i= 0; i < partnerNames.length; i++) {
IIndexName partnerName= partnerNames[i];
IASTFileLocation partnerLocation= partnerName.getFileLocation();
if (partnerLocation != null) {
IPath partnerFileLocation= Path.fromOSString(partnerLocation.getFileName());
if (!fFilePath.equals(partnerFileLocation)) {
addPotentialPartnerFileLocation(partnerFileLocation);
if (fConfidence == CONFIDENCE_LIMIT) {
return PROCESS_ABORT;
}
}
}
}
} catch (CoreException exc) {
CUIPlugin.getDefault().log(exc.getStatus());
}
}
}
}
return PROCESS_SKIP;
}
private void addPotentialPartnerFileLocation(IPath partnerFileLocation) {
Counter counter= (Counter)fMap.get(partnerFileLocation);
if (counter == null) {
counter= new Counter();
fMap.put(partnerFileLocation, counter);
}
++counter.fCount;
if (counter.fCount > fConfidence) {
fConfidence= counter.fCount;
fFavoriteLocation= partnerFileLocation;
}
}
}
private static ITranslationUnit fgLastPartnerUnit;
private static ITranslationUnit fgLastSourceUnit;
/**
* Create a toggle source/header action for the given editor.
*
* @param bundle the resource bundle to take the label, tooltip and description from.
* @param prefix the prefix to be prepended to the resource bundle keys
* @param editor the text editor this action is associated with
* @see TextEditorAction#TextEditorAction(ResourceBundle, String, ITextEditor)
*/
public ToggleSourceAndHeaderAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
super(bundle, prefix, editor);
}
/*
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
IEditorPart editor = getTextEditor();
if (editor == null) {
return;
}
IEditorInput input= editor.getEditorInput();
IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager();
IWorkingCopy currentUnit= manager.getWorkingCopy(input);
ITranslationUnit partnerUnit= computePartnerFile(currentUnit);
if (partnerUnit != null) {
fgLastSourceUnit= currentUnit.getOriginalElement();
fgLastPartnerUnit= partnerUnit;
try {
EditorUtility.openInEditor(partnerUnit);
} catch (PartInitException exc) {
CUIPlugin.getDefault().log(exc.getStatus());
} catch (CModelException exc) {
CUIPlugin.getDefault().log(exc.getStatus());
}
}
}
/**
* Compute the corresponding translation unit for the given unit.
*
* @param tUnit the current source/header translation unit
* @return the partner translation unit
*/
private ITranslationUnit computePartnerFile(ITranslationUnit tUnit) {
// try shortcut for fast toggling
if (fgLastPartnerUnit != null) {
final ITranslationUnit originalUnit;
if (tUnit instanceof IWorkingCopy) {
originalUnit= ((IWorkingCopy)tUnit).getOriginalElement();
} else {
originalUnit= tUnit;
}
if (originalUnit.getTranslationUnit().equals(fgLastPartnerUnit)) {
if (fgLastSourceUnit.exists()) {
// toggle back
return fgLastSourceUnit;
}
}
}
IProgressMonitor monitor= new NullProgressMonitor();
PartnerFileComputer computer= new PartnerFileComputer();
ASTProvider.getASTProvider().runOnAST(tUnit, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer);
IPath partnerFileLoation= computer.getPartnerFileLocation();
if (partnerFileLoation != null) {
ITranslationUnit partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFileLoation);
if (partnerUnit == null) {
partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(tUnit.getCProject(), partnerFileLoation);
}
return partnerUnit;
}
// search partnerfile based on filename/extension
IPath sourceFileLocation= tUnit.getLocation();
IPath partnerBasePath= sourceFileLocation.removeFileExtension();
IContentType contentType= getPartnerContentType(tUnit.getContentTypeId());
if (contentType != null) {
String[] partnerExtensions;
partnerExtensions= contentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
for (int i= 0; i < partnerExtensions.length; i++) {
String ext= partnerExtensions[i];
String partnerFileBasename= partnerBasePath.addFileExtension(ext).lastSegment();
IFile partnerFile= null;
if (tUnit.getResource() != null) {
partnerFile= findInContainer(tUnit.getResource().getParent(), partnerFileBasename);
}
if (partnerFile == null) {
partnerFile= findInContainer(tUnit.getCProject().getProject(), partnerFileBasename);
}
if (partnerFile != null) {
ITranslationUnit partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFile);
if (partnerUnit != null) {
return partnerUnit;
}
}
// external tanslation unit - try in same directory
if (tUnit.getResource() == null) {
partnerFileLoation= partnerBasePath.removeLastSegments(1).append(partnerFileBasename);
ITranslationUnit partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(tUnit.getCProject(), partnerFileLoation);
if (partnerUnit != null) {
return partnerUnit;
}
}
}
}
return null;
}
/**
* Find a file in the given resource container for the given basename.
*
* @param container
* @param basename
* @return a matching {@link IFile} or <code>null</code>, if no matching file was found
*/
private IFile findInContainer(IContainer container, final String basename) {
final IFile[] result= { null };
IResourceProxyVisitor visitor= new IResourceProxyVisitor() {
public boolean visit(IResourceProxy proxy) throws CoreException {
if (result[0] != null) {
return false;
}
if (!proxy.isAccessible()) {
return false;
}
if (proxy.getType() == IResource.FILE && proxy.getName().equals(basename)) {
result[0]= (IFile)proxy.requestResource();
return false;
}
return true;
}};
try {
container.accept(visitor, 0);
} catch (CoreException exc) {
// ignore
}
return result[0];
}
private IContentType getPartnerContentType(String contentTypeId) {
IContentTypeManager mgr= Platform.getContentTypeManager();
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CHEADER)) {
return mgr.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE);
}
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CSOURCE)) {
return mgr.getContentType(CCorePlugin.CONTENT_TYPE_CHEADER);
}
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXHEADER)) {
return mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE);
}
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXSOURCE)) {
return mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER);
}
return null;
}
}