blob: fd4a440f4edbdee600ad4c1b56c78524d61dce9b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* QNX Software System
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.photran.internal.cdtinterface.ui.editor;
import java.util.ResourceBundle;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.IWorkingCopy;
import org.eclipse.cdt.internal.ui.actions.SelectionConverter;
import org.eclipse.cdt.internal.ui.editor.CContentOutlinePage;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.ConstructedCEditorMessages;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.IWorkingCopyManager;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.search.ui.actions.TextSearchGroup;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPartService;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.TextOperationAction;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
/**
* A {@link TextEditor} that reuses the Outline view from CDT, as well as its document provider
* and possibly its ruler context menu. Also uses CDT's resource bundle to support content
* assist actions.
*
* @author Jeff Overbey, mostly copied from {@link CEditor}
*/
/*
* The parts of this code that don't follow Photran's source formatting conventions were copied
* from CDT.
*/
@SuppressWarnings("restriction")
public abstract class CDTBasedTextEditor extends TextEditor implements ISelectionChangedListener
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Utility Methods to Be Called in Subclass Constructors
///////////////////////////////////////////////////////////////////////////////////////////////
private TextSearchGroup textSearchGroup;
protected void useCDTDocumentProvider()
{
// We must use the CUIPlugin's document provider in order for the
// working copy manager in setOutlinePageInput (below) to function correctly.
setDocumentProvider(CUIPlugin.getDefault().getDocumentProvider());
}
protected void useCDTRulerContextMenuID()
{
// JO: This gives you a "Toggle Breakpoint" action (and others)
// when you right-click the Fortran editor's ruler
setRulerContextMenuId("#CEditorRulerContext"); //$NON-NLS-1$
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Actions (use CDT resource bundle)
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void createActions()
{
super.createActions();
// See CEditor#createActions
final ResourceBundle bundle = ConstructedCEditorMessages.getResourceBundle();
// Add content assist actions
IAction action = new ContentAssistAction(bundle, "ContentAssistProposal.", this); //$NON-NLS-1$
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", action); //$NON-NLS-1$
markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
action= new TextOperationAction(bundle, "ContentAssistContextInformation.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
setAction("ContentAssistContextInformation", action); //$NON-NLS-1$
markAsStateDependentAction("ContentAssistContextInformation", true); //$NON-NLS-1$
// Add Search > Text actions to the menu bar (added to context menu in #editorContextMenuAboutToShow(IMenuManager) below)
textSearchGroup = new TextSearchGroup(this);
}
/**
* @see org.eclipse.ui.texteditor.AbstractTextEditor#editorContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager)
*/
@Override
public void editorContextMenuAboutToShow(IMenuManager menu)
{
super.editorContextMenuAboutToShow(menu);
if (textSearchGroup != null) {
textSearchGroup.fillContextMenu(menu);
}
}
@Override
public void dispose()
{
if (textSearchGroup != null) {
textSearchGroup.dispose();
}
super.dispose();
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Outline View Support
///////////////////////////////////////////////////////////////////////////////////////////////
private CContentOutlinePage fOutlinePage;
/**
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
@Override
public Object getAdapter(Class required) {
if (IContentOutlinePage.class.equals(required)) {
return getOutlinePage();
}
if (required == IShowInTargetList.class) {
return new IShowInTargetList() {
@SuppressWarnings("deprecation")
public String[] getShowInTargetIds() {
return new String[] { CUIPlugin.CVIEW_ID, IPageLayout.ID_OUTLINE, IPageLayout.ID_RES_NAV };
}
};
}
if (required == IShowInSource.class) {
ICElement ce= null;
try {
ce= SelectionConverter.getElementAtOffset(this);
} catch (CModelException ex) {
ce= null;
}
if (ce != null) {
final ISelection selection= new StructuredSelection(ce);
return new IShowInSource() {
public ShowInContext getShowInContext() {
return new ShowInContext(getEditorInput(), selection);
}
};
}
}
return super.getAdapter(required);
}
/**
* Gets the outline page of the c-editor.
* @return Outline page.
*/
public CContentOutlinePage getOutlinePage() {
if (fOutlinePage == null) {
fOutlinePage = new CContentOutlinePage(new CEditor());
fOutlinePage.addSelectionChangedListener(this);
}
setOutlinePageInput(fOutlinePage, getEditorInput());
return fOutlinePage;
}
/**
* Sets an input for the outline page.
* @param page Page to set the input.
* @param input Input to set.
*/
public static void setOutlinePageInput(CContentOutlinePage page, IEditorInput input) {
if (page != null) {
IWorkingCopyManager manager = CUIPlugin.getDefault().getWorkingCopyManager();
IWorkingCopy workingCopy = manager.getWorkingCopy(input);
if (workingCopy != null)
page.setInput(workingCopy);
}
}
// ISelectionChangedListener Implementation ///////////////////////////////////////////////////
// (for updating editor when Outline clicked)
/**
* React to changed selection in the outline view.
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
public void selectionChanged(SelectionChangedEvent event) {
ISelection sel = event.getSelection();
if (sel instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection) sel;
Object obj = selection.getFirstElement();
if (obj instanceof ISourceReference) {
try {
ISourceRange range = ((ISourceReference) obj).getSourceRange();
if (range != null) {
setSelection(range, !isActivePart());
}
} catch (CModelException e) {
// Selection change not applied.
}
}
}
}
/**
* Sets the current editor selection to the source range. Optionally
* sets the current editor position.
*
* @param element the source range to be shown in the editor, can be null.
* @param moveCursor if true the editor is scrolled to show the range.
*/
public void setSelection(ISourceRange element, boolean moveCursor) {
if (element == null) {
return;
}
try {
IRegion alternateRegion = null;
int start = element.getStartPos();
int length = element.getLength();
// Sanity check sometimes the parser may throw wrong numbers.
if (start < 0 || length < 0) {
start = 0;
length = 0;
}
// 0 length and start and non-zero start line says we know
// the line for some reason, but not the offset.
if (length == 0 && start == 0 && element.getStartLine() > 0) {
// We have the information in term of lines, we can work it out.
// Binary elements return the first executable statement so we have to substract -1
start = getDocumentProvider().getDocument(getEditorInput()).getLineOffset(element.getStartLine() - 1);
if (element.getEndLine() > 0) {
length = getDocumentProvider().getDocument(getEditorInput()).getLineOffset(element.getEndLine()) - start;
} else {
length = start;
}
// create an alternate region for the keyword highlight.
alternateRegion = getDocumentProvider().getDocument(getEditorInput()).getLineInformation(element.getStartLine() - 1);
if (start == length || length < 0) {
if (alternateRegion != null) {
start = alternateRegion.getOffset();
length = alternateRegion.getLength();
}
}
}
setHighlightRange(start, length, moveCursor);
if (moveCursor) {
start = element.getIdStartPos();
length = element.getIdLength();
if (start == 0 && length == 0 && alternateRegion != null) {
start = alternateRegion.getOffset();
length = alternateRegion.getLength();
}
if (start > -1 && getSourceViewer() != null) {
getSourceViewer().revealRange(start, length);
getSourceViewer().setSelectedRange(start, length);
}
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
}
return;
} catch (IllegalArgumentException x) {
// No information to the user
} catch (BadLocationException e) {
// No information to the user
}
if (moveCursor)
resetHighlightRange();
}
/**
* Checks is the editor active part.
* @return <code>true</code> if editor is the active part of the workbench.
*/
private boolean isActivePart() {
IWorkbenchWindow window = getSite().getWorkbenchWindow();
IPartService service = window.getPartService();
return (this == service.getActivePart());
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Utility Methods for Subclasses
///////////////////////////////////////////////////////////////////////////////////////////////
public void forceOutlineViewUpdate()
{
try
{
CoreModel.getDefault().getCModel().makeConsistent(new NullProgressMonitor());
}
catch (CModelException e)
{
// Ignore
}
}
}