/*
* Boo Development Tools for the Eclipse IDE
* Copyright (C) 2005 Rodrigo B. de Oliveira (rbo@acm.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package monolipse.ui.editors;
import java.util.ArrayList;
import java.util.HashMap;
import monolipse.ui.BooUI;
import monolipse.ui.editors.actions.ExpandCodeAction;
import monolipse.ui.editors.actions.ExpandMacrosAction;
import monolipse.ui.editors.actions.GotoDefinitionAction;
import monolipse.ui.editors.actions.ToggleCommentAction;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.information.IInformationProvider;
import org.eclipse.jface.text.information.IInformationProviderExtension;
import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
public class BooEditor extends TextEditor {
private final class BooOutlineInformationProvider implements
IInformationProvider, IInformationProviderExtension {
public String getInformation(ITextViewer textViewer, IRegion subject) {
return null;
}
public IRegion getSubject(ITextViewer textViewer, int offset) {
return new Region(offset, 1);
}
public Object getInformation2(ITextViewer textViewer, IRegion subject) {
return outlinePage().outline();
}
}
public static final String ID_EDITOR = "monolipse.ui.editors.BooEditor";
private BooContentOutlinePage _outlinePage;
@Override
protected void initializeEditor() {
super.initializeEditor();
setSourceViewerConfiguration(new BooSourceViewerConfiguration(getSharedColors(), this, getPreferenceStore()));
setDocumentProvider(new BooDocumentProvider());
setKeyBindingScopes(new String[] { "monolipse.ui.booEditorScope", "org.eclipse.ui.textEditorScope" });
}
public void createPartControl(Composite parent) {
super.createPartControl(parent);
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
projectionSupport = new ProjectionSupport(viewer,getAnnotationAccess(),getSharedColors());
projectionSupport.install();
//turn projection mode on
viewer.doOperation(ProjectionViewer.TOGGLE);
annotationModel = viewer.getProjectionAnnotationModel();
}
private ProjectionSupport projectionSupport;
private Annotation[] oldAnnotations;
private ProjectionAnnotationModel annotationModel;
public void updateFoldingStructure(ArrayList<Position> positions)
{
Annotation[] annotations = new Annotation[positions.size()];
//this will hold the new annotations along
//with their corresponding positions
HashMap<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();
for(int i = 0;i < positions.size(); i++)
{
ProjectionAnnotation annotation = new ProjectionAnnotation();
newAnnotations.put(annotation,positions.get(i));
annotations[i] = annotation;
}
annotationModel.replaceAnnotations(oldAnnotations, newAnnotations);
oldAnnotations = annotations;
}
/* (non-Javadoc)
* @see org.eclipse.ui.texteditor.AbstractTextEditor#createSourceViewer(org.eclipse.swt.widgets.Composite, org.eclipse.jface.text.source.IVerticalRuler, int)
*/
protected ISourceViewer createSourceViewer(Composite parent,
IVerticalRuler ruler, int styles)
{
ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
// ensure decoration support has been created and configured.
getSourceViewerDecorationSupport(viewer);
return viewer;
}
protected void createActions() {
super.createActions();
ToggleCommentAction action = new ToggleCommentAction(BooUI.getResourceBundle(), "Toggle Comment", this);
//action.setAccelerator(Action.convertAccelerator("M1+/"));
setAction(ToggleCommentAction.ID, action);
//setActionActivationCode(ToggleCommentAction.ID, '/', -1, SWT.MOD1);
//markAsStateDependentAction(ToggleCommentAction.ID, true);
action.configure(getSourceViewer(), getSourceViewerConfiguration());
Action eca = new ExpandCodeAction(this);
setAction(eca.getId(), eca);
Action ema = new ExpandMacrosAction(this);
setAction(ema.getId(), ema);
Action gda = new GotoDefinitionAction(this);
setAction(gda.getId(), gda);
final InformationPresenter quickOutline = new InformationPresenter(quickOutlineCreator()) {
public IInformationProvider getInformationProvider(String contentType) {
return new BooOutlineInformationProvider();
}
};
quickOutline.install(getSourceViewer());
final Action outlineAction = new Action("QuickOutline") {
public void run() {
BusyIndicator.showWhile(getSite().getShell().getDisplay(), new Runnable() {
public void run() {
quickOutline.showInformation();
}
});
}
};
outlineAction.setImageDescriptor(BooUI.sharedImage(ISharedImages.IMG_DEF_VIEW));
outlineAction.setId("monolipse.ui.editors.actions.BooQuickOutlineAction");
outlineAction.setActionDefinitionId(outlineAction.getId());
setAction(outlineAction.getId(), outlineAction);
}
private IInformationControlCreator quickOutlineCreator() {
return new IInformationControlCreator() {
public IInformationControl createInformationControl(Shell parent) {
int shellStyle= SWT.RESIZE;
int treeStyle= SWT.V_SCROLL | SWT.H_SCROLL;
return outlinePage().createQuickOutline(parent, shellStyle, treeStyle);
}
};
}
protected void editorContextMenuAboutToShow(IMenuManager menu) {
super.editorContextMenuAboutToShow(menu);
// menu.appendToGroup(ITextEditorActionConstants.MB_ADDITIONS, getAction(ToggleCommentAction.ID));
menu.appendToGroup(ITextEditorActionConstants.MB_ADDITIONS, getAction(ExpandCodeAction.ID));
menu.appendToGroup(ITextEditorActionConstants.MB_ADDITIONS, getAction(GotoDefinitionAction.ID));
}
@SuppressWarnings("rawtypes")
public Object getAdapter(Class required) {
if (IContentOutlinePage.class.equals(required)) {
return outlinePage();
}
return super.getAdapter(required);
}
public BooContentOutlinePage outlinePage() {
if (_outlinePage == null) {
_outlinePage = new BooContentOutlinePage(getDocumentProvider(), this);
_outlinePage.setInput(getEditorInput());
}
return _outlinePage;
}
public BooDocument getDocument() {
return (BooDocument) getDocumentProvider().getDocument(getEditorInput());
}
public Point getSelectedRange() {
return getSourceViewer().getSelectedRange();
}
public Point getSelectedPosition() {
Point range = getSelectedRange();
try {
int line = getSourceViewer().getDocument().getLineOfOffset(range.x);
int column = calculateColumn(getSourceViewer(), range.x, line);
return new Point(line, column);
} catch (BadLocationException e) {
BooUI.logException(e);
}
return null;
}
private int calculateColumn(ITextViewer textViewer, int offset, int line)
throws BadLocationException {
int startOffset = textViewer.getDocument().getLineOffset(line);
int column = offset - startOffset;
String text = textViewer.getDocument().get(startOffset, column);
int textSize = 0;
int tabSize = 4; // FIX: get real document tab size
for(char ch: text.toCharArray()) {
if (ch == '\t') {
textSize += tabSize;
}
else textSize++;
}
return textSize;
}
}