blob: ef8a7c55f25ff5d0de7350c4949e6f6d257ad3d3 [file] [log] [blame]
/**
* Copyright (c) 2019 Eclipse contributors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*/
package org.eclipse.emf.codegen.presentation;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
import org.eclipse.core.filebuffers.IStateValidationSupport;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IEncodedStorage;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
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.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.codegen.CodeGenPlugin;
import org.eclipse.emf.codegen.jet.JETAttributeItem;
import org.eclipse.emf.codegen.jet.JETAttributeListItem;
import org.eclipse.emf.codegen.jet.JETCommentItem;
import org.eclipse.emf.codegen.jet.JETCompilationUnit;
import org.eclipse.emf.codegen.jet.JETCompilationUnit.JETJavaRange;
import org.eclipse.emf.codegen.jet.JETCompileTemplateOperation;
import org.eclipse.emf.codegen.jet.JETDirectiveItem;
import org.eclipse.emf.codegen.jet.JETException;
import org.eclipse.emf.codegen.jet.JETExpressionItem;
import org.eclipse.emf.codegen.jet.JETItem;
import org.eclipse.emf.codegen.jet.JETJavaItem;
import org.eclipse.emf.codegen.jet.JETLiteralItem;
import org.eclipse.emf.codegen.jet.JETMark;
import org.eclipse.emf.codegen.jet.JETNature;
import org.eclipse.emf.codegen.jet.JETParser;
import org.eclipse.emf.codegen.jet.JETProblemListener;
import org.eclipse.emf.codegen.jet.JETRootItem;
import org.eclipse.emf.codegen.jet.JETScriptletItem;
import org.eclipse.emf.codegen.jet.JETSkeleton;
import org.eclipse.emf.codegen.jet.JETSubItem;
import org.eclipse.emf.codegen.jet.JETTokenItem;
import org.eclipse.emf.codegen.jet.JETValueElementItem;
import org.eclipse.emf.codegen.jet.JETValueItem;
import org.eclipse.emf.codegen.util.CodeGenUtil;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.SegmentSequence;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IBufferChangedListener;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.ui.JavaElementImageDescriptor;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.ui.actions.IJavaEditorActionDefinitionIds;
import org.eclipse.jdt.ui.actions.OpenAction;
import org.eclipse.jdt.ui.refactoring.RenameSupport;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.ui.text.java.hover.IJavaEditorTextHover;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.text.DefaultTextHover;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IPositionUpdater;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ISelectionValidator;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextHoverExtension;
import org.eclipse.jface.text.ITextHoverExtension2;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextPresentationListener;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.ITextViewerExtension4;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.IUndoManager;
import org.eclipse.jface.text.IUndoManagerExtension;
import org.eclipse.jface.text.IViewportListener;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationPresentation;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.ImageUtilities;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.TextInvocationContext;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateProposal;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CaretEvent;
import org.eclipse.swt.custom.CaretListener;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.undo.DocumentUndoEvent;
import org.eclipse.text.undo.DocumentUndoManagerRegistry;
import org.eclipse.text.undo.IDocumentUndoListener;
import org.eclipse.text.undo.IDocumentUndoManager;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.INavigationLocation;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.ISaveablesLifecycleListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.NavigationLocation;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.Saveable;
import org.eclipse.ui.SaveablesLifecycleEvent;
import org.eclipse.ui.SubActionBars;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.handlers.CollapseAllHandler;
import org.eclipse.ui.handlers.ExpandAllHandler;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProviderExtension;
import org.eclipse.ui.texteditor.IElementStateListener;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.spelling.SpellingService;
import org.eclipse.ui.themes.ColorUtil;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
/**
* @since 2.19
*/
public final class JETEditor extends AbstractDecoratedTextEditor
{
public static final String ID = "org.eclipse.emf.codegen.presentation.JETEditorID";
static final String REFACTOR_QUICKMENU_COMMAND_ID = "org.eclipse.codegen.ui.jet.refactor.quickmenu";
private static final String REFACTOR_QUICKMENU_MENU_ID = "org.eclipse.codegen.ui.jet.refactor";
static final String SOURCE_QUICKMENU_COMMAND_ID = "org.eclipse.codegen.ui.jet.source.quickmenu";
static final String SOURCE_QUICKMENU_MENU_ID = "org.eclipse.codegen.ui.jet.source";
static final String SELECT_ENCLOSING_JET_ELEMENT_ACTION_ID = "SelectEnclosingJETElement";
static final String EXTRACT_LOCAL_VARIABLE_ACTION_ID = "ExtractLocalVariable";
static final String GOTO_BRACKET_COMMAND_ID = "org.eclipse.emf.codegen.ui.jet.goto.matching.bracket";
static final String SELECT_ENCLOSING_JET_ELEMENT_COMMAND_ID = "org.eclipse.emf.codegen.ui.jet.select.enclosing";
static final String RENAME_COMMAND_ID = "org.eclipse.codegen.ui.jet.rename";
static final String RENAME_ACTION_ID = "Rename";
static final String FORMAT_COMMAND_ID = "org.eclipse.codegen.ui.jet.format";
static final String FORMAT_ACTION_ID = "Format";
private static boolean trace;
private final BracketInserter bracketInserter = new BracketInserter(this);
private final DelegatingTextHover delegatingTextHover = new DelegatingTextHover(this);
private final JETDocumentManager jetDocumentManager = new JETDocumentManager(this);
private final JETBracketMatcher jetBracketMatcher = new JETBracketMatcher(this);
private final List<Runnable> disposables = new ArrayList<Runnable>();
private final AtomicReference<JETCompilerResult> pendingJETCompilerResult = new AtomicReference<JETCompilerResult>();;
private JETCompilerResult jetCompilerResult;
private JavaEditor javaEditor;
private long expectedModificationStamp;
private JETContentOutlinePage contentOutlinePage;
private JETBreadcrumbViewer breadcrumbViewer;
private Runnable pendingUntilDocumentsAvailable;
private Runnable dismissLandingPage;
private boolean isSaving;
private boolean isShowingContentAssist;
private TrackedPosition jetPosition = new TrackedPosition(TrackedPosition.Type.JET);
private TrackedPosition javaPosition = new TrackedPosition(TrackedPosition.Type.JAVA);
private int[] styleRangeOffsets;
private JETToken[] jetTokens;
private SelectionSynchronizer selectionSynchronizer;
private Runnable deferredInvalidatePresentation;
private boolean editorContextMenuAboutToShow;
public JETEditor()
{
jetPosition.setOpposite(javaPosition);
}
JETNature getJETNature()
{
IFile file = getEditorInputFile();
return file == null ? null : JETNature.getRuntime(file.getProject());
}
@Override
public IEditorInput getEditorInput()
{
return editorContextMenuAboutToShow ? jetDocumentManager.getEditorInput() : super.getEditorInput();
}
SourceViewer getJETSourceViewer()
{
return (SourceViewer)getSourceViewer();
}
JavaEditor getJavaEditor()
{
return javaEditor;
}
SourceViewer getJavaSourceViewer()
{
return getJavaEditor().getJavaSourceViewer();
}
TrackedPosition getJavaPosition()
{
return javaPosition;
}
TrackedPosition getJETPosition()
{
return jetPosition;
}
boolean isJavaEditorInSync()
{
return expectedModificationStamp == getModificationStamp();
}
long getModificationStamp()
{
IDocument document = getSourceViewer().getDocument();
return document == null ? 0 : ((IDocumentExtension4)document).getModificationStamp();
}
void resetExpectedModificationStamp()
{
expectedModificationStamp = 0;
}
void setExpectedModificationStamp()
{
expectedModificationStamp = getModificationStamp();
}
JETDocumentManager getDocumentManager()
{
return jetDocumentManager;
}
int getFileID()
{
return jetDocumentManager.getFileID();
}
IFile getEditorInputFile()
{
return toFile(getEditorInput());
}
JETBreadcrumbViewer getBreadcrumbViewer()
{
return breadcrumbViewer;
}
JETCompilerResult getCompilerResult()
{
return jetCompilerResult;
}
JETCompilationUnit getCompilationUnit()
{
return jetCompilerResult == null ? null : jetCompilerResult.getCompilationUnit();
}
void setShowingContentAssist(boolean isShowingContentAssist)
{
this.isShowingContentAssist = isShowingContentAssist;
if (!isShowingContentAssist)
{
jetDocumentManager.setEnableJavaSynchronization(true);
}
}
void handleCompilerResult(final JETCompilerResult jetCompilerResult)
{
// This is called from the JETDynamicCompiler's thread.
JETCompilerResult oldJETCompilerResult = pendingJETCompilerResult.getAndSet(jetCompilerResult);
// If there is not a value that was already pending consumption, dispatch a new runnable to the UI thread.
if (oldJETCompilerResult == null)
{
getSite().getShell().getDisplay().asyncExec(new Runnable()
{
public void run()
{
// If the pending result is still not consumed by waitForCompilerResult, consume it now.
JETCompilerResult newJETCompilerResult = pendingJETCompilerResult.getAndSet(null);
if (newJETCompilerResult != null)
{
setCompilerResult(newJETCompilerResult);
}
}
});
}
}
void waitForCompilerResult(long timeInMillis)
{
long count = timeInMillis / 100;
for (int i = 0; i < count; ++i)
{
JETCompilerResult jetCompilerResult = pendingJETCompilerResult.getAndSet(null);
if (jetCompilerResult == null)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException exception)
{
Thread.interrupted();
}
}
else
{
setCompilerResult(jetCompilerResult);
break;
}
}
}
void setCompilerResult(JETCompilerResult jetCompilerResult)
{
if (!isShowingContentAssist)
{
this.jetCompilerResult = jetCompilerResult;
jetDocumentManager.setCompilerResult(jetCompilerResult);
handleProblems(getFileID());
IFile javaFile = jetCompilerResult.getJavaFile();
JETCompilationUnit jetCompilationUnit = jetCompilerResult.getCompilationUnit();
if (javaFile != null)
{
final ISourceViewer jetSourceViewer = getSourceViewer();
setExpectedModificationStamp();
ISourceViewer javaSourceViewer = getJavaSourceViewer();
StyledText javaTextWidget = javaSourceViewer.getTextWidget();
try
{
javaTextWidget.setRedraw(false);
String compilationUnit = jetCompilationUnit.getJavaCompilationUnit();
javaEditor.setInput(javaFile, compilationUnit);
IDocument document = javaSourceViewer.getDocument();
if (document != null)
{
String oldDocument = document.get();
if (!compilationUnit.equals(oldDocument))
{
document.set(compilationUnit);
}
else
{
invalidateVisibleTextPresentation(true);
}
// Synchronize the cursor/selection.
jetSourceViewer.getTextWidget().notifyListeners(SWT.Selection, new Event());
}
}
finally
{
javaTextWidget.setRedraw(true);
}
}
if (jetCompilationUnit != null && pendingUntilDocumentsAvailable != null)
{
try
{
pendingUntilDocumentsAvailable.run();
}
finally
{
pendingUntilDocumentsAvailable = null;
}
}
if (dismissLandingPage != null)
{
dismissLandingPage.run();
}
selectionSynchronizer.sync(getSourceViewer());
}
}
List<JETJavaRange> getRanges()
{
JETCompilationUnit compilerResult = getCompilationUnit();
return compilerResult == null ? Collections.<JETJavaRange> emptyList() : compilerResult.getRanges();
}
JETItem getJETItem(int templateOffset, boolean leaf)
{
JETCompilationUnit compilerResult = getCompilationUnit();
return compilerResult == null ? null : compilerResult.getJETItem(getFileID(), templateOffset, leaf);
}
Position getCorrespondingJavaPosition(int templateOffset, int templateLength)
{
JETCompilationUnit compilerResult = getCompilationUnit();
if (compilerResult != null)
{
int[] correspondingJavaPoint = compilerResult.getCorrespondingJavaPoint(getFileID(), templateOffset, templateLength);
if (correspondingJavaPoint != null)
{
return new Position(correspondingJavaPoint[0], correspondingJavaPoint[1]);
}
}
return null;
}
int getCorrespondingTemplateFileID(int javaOffset)
{
JETCompilationUnit compilerResult = getCompilationUnit();
return compilerResult == null ? -1 : compilerResult.getCorrespondingTemplateFileID(javaOffset);
}
Position getCorrespondingTemplatePosition(int javaOffset, int javaLength)
{
JETCompilationUnit compilerResult = getCompilationUnit();
if (compilerResult != null)
{
int[] correspondingTemplatePoint = compilerResult.getCorrespondingTemplatePoint(getFileID(), javaOffset, javaLength);
if (correspondingTemplatePoint != null)
{
return new Position(correspondingTemplatePoint[0], correspondingTemplatePoint[1]);
}
}
return null;
}
void handleFileIDChanged(int fileID)
{
firePropertyChange(PROP_DIRTY);
handleProblems(fileID);
}
void handleProblems(int fileID)
{
if (jetCompilerResult != null)
{
applyProblemAnnotations(jetCompilerResult.getProblems(fileID));
}
}
void applyProblemAnnotations(List<JETProblemAnnotation> jetProblemAnnotations)
{
SourceViewer sourceViewer = getJETSourceViewer();
IAnnotationModel annotationModel = sourceViewer.getAnnotationModel();
List<Annotation> annotationsToRemove = new ArrayList<Annotation>();
for (Iterator<Annotation> i = annotationModel.getAnnotationIterator(); i.hasNext();)
{
Annotation annotation = i.next();
if (annotation instanceof JETProblemAnnotation)
{
annotationsToRemove.add(annotation);
}
else if (annotation instanceof MarkerAnnotation && isDirty())
{
Position position = annotationModel.getPosition(annotation);
annotationModel.addAnnotation(new JETProblemAnnotation((MarkerAnnotation)annotation, position), position);
}
}
for (Annotation annotation : annotationsToRemove)
{
annotationModel.removeAnnotation(annotation);
}
for (JETProblemAnnotation jetProblemAnnotation : jetProblemAnnotations)
{
Position position = jetProblemAnnotation.getPosition();
annotationModel.addAnnotation(jetProblemAnnotation, position);
}
}
@Override
protected void initializeEditor()
{
super.initializeEditor();
configureInsertMode(SMART_INSERT, true);
configureInsertMode(INSERT, false);
configureInsertMode(INSERT, true);
setInsertMode(SMART_INSERT);
IPreferenceStore preferenceStore = getPreferenceStore();
IPreferenceStore jetPreferenceStore = CodeGenUIPlugin.getPlugin().getPreferenceStore();
ChainedPreferenceStore chainedPreferenceStore = new ChainedPreferenceStore(new IPreferenceStore []{ jetPreferenceStore, preferenceStore })
{
@Override
public boolean getBoolean(String name)
{
if ("matchingBrackets".equals(name))
{
return true;
}
return !SpellingService.PREFERENCE_SPELLING_ENABLED.equals(name) && super.getBoolean(name);
}
};
setPreferenceStore(chainedPreferenceStore);
setSourceViewerConfiguration(new JETSourceViewerConfiguration(chainedPreferenceStore, this));
}
@Override
public void createPartControl(Composite parent)
{
final SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
final Composite composite = new Composite(sashForm, SWT.NONE);
GridLayout gridLayout = new GridLayout();
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
gridLayout.verticalSpacing = 0;
gridLayout.horizontalSpacing = 0;
composite.setLayout(gridLayout);
breadcrumbViewer = new JETBreadcrumbViewer(composite, SWT.HORIZONTAL)
{
@Override
public void configureDropDownViewer(TreeViewer viewer, Object input)
{
viewer.setLabelProvider(contentOutlinePage.newLabelProvider());
viewer.setContentProvider(contentOutlinePage.getContentProvider());
}
};
GridData breadcrumbLayoutData = new GridData(SWT.FILL, SWT.FILL, true, false);
breadcrumbViewer.getControl().setLayoutData(breadcrumbLayoutData);
Composite jetSourceViewerComposite = new Composite(composite, SWT.NONE);
jetSourceViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
jetSourceViewerComposite.setLayout(new FillLayout());
super.createPartControl(jetSourceViewerComposite);
ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
final ImageDescriptor up = CodeGenUIPlugin.getPlugin().getImage("full/up.png");
final ImageDescriptor down = CodeGenUIPlugin.getPlugin().getImage("full/down.png");
final Action toggleAction = new Action("", IAction.AS_PUSH_BUTTON)
{
@Override
public void run()
{
if (sashForm.getMaximizedControl() == null)
{
sashForm.setMaximizedControl(composite);
setImageDescriptor(up);
}
else
{
sashForm.setMaximizedControl(null);
setImageDescriptor(down);
}
}
};
toggleAction.setImageDescriptor(down);
toolBarManager.add(toggleAction);
ToolBar toolBar = toolBarManager.createControl(composite);
GridData toolBarLayoutData = new GridData(SWT.CENTER, SWT.BOTTOM, true, false);
toolBarLayoutData.heightHint = 11;
toolBar.setLayoutData(toolBarLayoutData);
StyledText sourceViewerStyledText = getSourceViewer().getTextWidget();
Color sourceViewerBackground = sourceViewerStyledText.getBackground();
breadcrumbViewer.getControl().setBackground(sourceViewerBackground);
composite.setBackground(sourceViewerStyledText.getBackground());
IMenuManager contextMenu = (IMenuManager)sourceViewerStyledText.getMenu().getData("org.eclipse.jface.action.MenuManager.managerKey");
contextMenu.addMenuListener(new IMenuListener()
{
public void menuAboutToShow(IMenuManager manager)
{
editorContextMenuAboutToShow = false;
}
});
JETContentOutlinePage contentOutlinePage = getContentOutlinePage();
breadcrumbViewer.setLabelProvider(contentOutlinePage.newLabelProvider());
breadcrumbViewer.setContentProvider(contentOutlinePage.getContentProvider());
breadcrumbViewer.setInput(contentOutlinePage.itemManager.getRootItem());
jetDocumentManager.initializeDocumentManager();
try
{
javaEditor = new JavaEditor(this);
javaEditor.init(getEditorSite(), getEditorInput());
final Composite javaComposite = new Composite(sashForm, SWT.NONE);
final StackLayout stackLayout = new StackLayout();
javaComposite.setLayout(stackLayout);
javaEditor.createPartControl(javaComposite);
final Control[] javaEditorChildren = javaComposite.getChildren();
final ScrolledComposite scrolledComposite = new ScrolledComposite(javaComposite, SWT.V_SCROLL | SWT.H_SCROLL);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
scrolledComposite.setAlwaysShowScrollBars(false);
final StyledText landingPage = new StyledText(scrolledComposite, SWT.READ_ONLY | SWT.NO_FOCUS);
landingPage.setBackground(sourceViewerStyledText.getBackground());
scrolledComposite.setContent(landingPage);
final Runnable updateLandingPageInfo = new Runnable()
{
public void run()
{
StyledString landingPageInfo = generateLandingPageInfo(landingPage.getLineDelimiter());
landingPage.setText(landingPageInfo.toString());
landingPage.setStyleRanges(landingPageInfo.getStyleRanges());
landingPage.redraw();
landingPage.pack(true);
Point landingPageSize = landingPage.getSize();
scrolledComposite.setMinWidth(landingPageSize.x);
scrolledComposite.setMinHeight(landingPageSize.y);
}
};
updateLandingPageInfo.run();
stackLayout.topControl = scrolledComposite;
final ImageDescriptor star = CodeGenUIPlugin.getPlugin().getImage("full/star.png");
final ImageDescriptor blank = CodeGenUIPlugin.getPlugin().getImage("full/blank.png");
final Action showInfoAction = new Action("", IAction.AS_PUSH_BUTTON)
{
@Override
public void run()
{
if (stackLayout.topControl == scrolledComposite)
{
stackLayout.topControl = javaEditorChildren[0];
}
else
{
stackLayout.topControl = scrolledComposite;
updateLandingPageInfo.run();
}
if (sashForm.getMaximizedControl() == composite)
{
sashForm.setMaximizedControl(null);
toggleAction.setImageDescriptor(down);
}
javaComposite.layout();
}
};
showInfoAction.setImageDescriptor(star);
showInfoAction.setId("show-info");
toolBarManager.add(showInfoAction);
toolBarManager.update(true);
class HyperlinkListener implements MouseTrackListener, MouseMoveListener, MouseListener
{
final Cursor defaultCursor = landingPage.getCursor();
final Cursor handCursor = landingPage.getDisplay().getSystemCursor(SWT.CURSOR_HAND);
final Runnable infoActionAnimator = new Runnable()
{
public void run()
{
if (hyperLinkRange != null && hyperLinkRange.length == 1)
{
showInfoAction.setImageDescriptor(showInfoAction.getImageDescriptor() == blank ? star : blank);
landingPage.getDisplay().timerExec(300, this);
}
else
{
showInfoAction.setImageDescriptor(star);
}
}
};
StyleRange hyperLinkRange;
public void mouseDoubleClick(MouseEvent event)
{
clearHyperlink();
}
public void mouseDown(MouseEvent event)
{
if (hyperLinkRange != null)
{
if (hyperLinkRange.length == 1)
{
showInfoAction.run();
}
else
{
landingPage.getDisplay().asyncExec(new Runnable()
{
final URI documentURI = URI.createPlatformResourceURI(landingPage.getText(hyperLinkRange.start, hyperLinkRange.start + hyperLinkRange.length - 1), true);
public void run()
{
IEditorPart editorPart = open(getEditorSite(), documentURI.toString());
if (editorPart instanceof JETEditor)
{
((JETEditor)editorPart).selectAndReveal(getEditorInput(), 0, 0);
}
}
});
}
}
clearHyperlink();
}
public void mouseUp(MouseEvent event)
{
clearHyperlink();
}
public void mouseEnter(MouseEvent event)
{
clearHyperlink();
}
public void mouseExit(MouseEvent event)
{
clearHyperlink();
}
public void mouseHover(MouseEvent event)
{
}
public void mouseMove(MouseEvent event)
{
updateStyleRange(event);
}
private void clearHyperlink()
{
if (hyperLinkRange != null)
{
hyperLinkRange.fontStyle = SWT.NORMAL;
hyperLinkRange.underline = false;
landingPage.setStyleRange(hyperLinkRange);
hyperLinkRange = null;
landingPage.setCursor(defaultCursor);
}
}
@SuppressWarnings("deprecation")
private int getOffset(MouseEvent event)
{
try
{
try
{
return (Integer)landingPage.getClass().getMethod("getOffsetAtPoint", Point.class).invoke(landingPage, new Point(event.x, event.y));
}
catch (Exception exception)
{
}
return landingPage.getOffsetAtLocation(new Point(event.x, event.y));
}
catch (IllegalArgumentException exception)
{
return -1;
}
}
private void updateStyleRange(MouseEvent event)
{
StyleRange oldHyperLinkRange = hyperLinkRange;
hyperLinkRange = null;
int offsetAtPoint = getOffset(event);
if (offsetAtPoint != -1)
{
StyleRange styleRange = landingPage.getStyleRangeAtOffset(offsetAtPoint);
if (styleRange != null)
{
if (styleRange.data instanceof StyleRange)
{
hyperLinkRange = (StyleRange)styleRange.data;
hyperLinkRange.underline = true;
hyperLinkRange.fontStyle = SWT.BOLD;
landingPage.setStyleRange(hyperLinkRange);
landingPage.setCursor(handCursor);
infoActionAnimator.run();
}
}
}
if (oldHyperLinkRange != null && oldHyperLinkRange != hyperLinkRange)
{
oldHyperLinkRange.fontStyle = SWT.NORMAL;
oldHyperLinkRange.underline = false;
landingPage.setStyleRange(oldHyperLinkRange);
if (hyperLinkRange == null)
{
landingPage.setCursor(defaultCursor);
}
}
}
}
HyperlinkListener hyperlinkListener = new HyperlinkListener();
landingPage.addMouseTrackListener(hyperlinkListener);
landingPage.addMouseListener(hyperlinkListener);
landingPage.addMouseMoveListener(hyperlinkListener);
dismissLandingPage = new Runnable()
{
public void run()
{
dismissLandingPage = null;
JETCompilationUnit compilationUnit = getCompilationUnit();
if (compilationUnit != null)
{
for (JETException problem : compilationUnit.getProblems())
{
String problemKey = problem.getProblemKey();
if (JETProblemListener.FILE_NOT_A_TEMPLATE.equals(problemKey) || JETProblemListener.FILE_NOT_ON_TEMPLATE_SOURCE_PATH.equals(problemKey))
{
return;
}
}
stackLayout.topControl = javaEditorChildren[0];
toggleAction.run();
javaComposite.layout();
}
}
};
selectionSynchronizer = new SelectionSynchronizer(this, javaEditor);
delegatingTextHover.setEditor(javaEditor);
new VisibleCaretHandler(sourceViewerStyledText, javaEditor.getJavaSourceViewer().getTextWidget());
}
catch (PartInitException exception)
{
throw new RuntimeException(exception);
}
if (fSourceViewerDecorationSupport != null)
{
fSourceViewerDecorationSupport.install(getPreferenceStore());
}
new ViewPortHandler(this);
setAction(SELECT_ENCLOSING_JET_ELEMENT_ACTION_ID, new SelectEnclosingJETElementAction(this));
setAction(RENAME_ACTION_ID, new JETRenameLocalVariableAction(this));
setAction(FORMAT_ACTION_ID, new JETFormatAction(this));
}
private StyledString generateLandingPageInfo(String lineDelimiter)
{
StyledString styledString = new StyledString(lineDelimiter);
IEditorInput editorInput = getEditorInput();
IFile file = toFile(editorInput);
String indent = " ";
if (file == null)
{
URI uri = toURI(editorInput);
String name = uri == null ? editorInput.getName() : uri.toString();
styledString.append(indent);
styledString.append("The file ");
styledString.append(name, StyledString.DECORATIONS_STYLER);
styledString.append(" cannot be compiled because it is not located in the workspace.");
}
else if (getJETNature() == null)
{
styledString.append(indent);
styledString.append("The file ");
styledString.append(file.getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(" cannot be compiled because it is not in a project with a JET nature.");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
IJavaProject javaProject = JavaCore.create(file.getProject());
boolean isWellFormedJavaProject = false;
try
{
isWellFormedJavaProject = javaProject.isStructureKnown();
}
catch (JavaModelException e)
{
}
if (!isWellFormedJavaProject)
{
styledString.append(indent);
styledString.append("Furthermore, its containing project ");
styledString.append(file.getParent().getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(" is not in a project with a properly configured Java nature.");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
}
styledString.append(indent);
styledString.append("Use ");
styledString.append(
"File \u2192 New \u2192 Other... \u2192 Java Emitter Templates \u2192 Convert Projects to JET Projects",
JETContentOutlinePage.Item.getFontStyler(SWT.ITALIC));
styledString.append(" to convert a Java project into a JET project.");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
styledString.append(indent);
styledString.append("You will need to reopen this editor after having done so.");
}
else if (getJETNature().getJavaSourceContainer() == null)
{
styledString.append(indent);
styledString.append("The file ");
styledString.append(file.getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(" cannot be compiled because the JET nature is not properly configured.");
styledString.append(lineDelimiter);
}
else
{
JETCompilationUnit compilationUnit = getCompilationUnit();
String className = null;
boolean notOnSourcePath = false;
if (compilationUnit != null)
{
className = compilationUnit.getClassName();
for (JETException problem : compilationUnit.getProblems())
{
if (JETProblemListener.FILE_NOT_ON_TEMPLATE_SOURCE_PATH.equals(problem.getProblemKey()))
{
notOnSourcePath = true;
break;
}
}
}
styledString.append(indent);
styledString.append("The file ");
styledString.append(file.getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(" is being compiled.");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
Styler problemStyler = new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
textStyle.foreground = ColorManager.INSTANCE.getForeground("directive");
}
};
String fileExtension = file.getFileExtension();
boolean isNotTemplate = fileExtension == null || !fileExtension.endsWith("jet");
if (isNotTemplate)
{
styledString.append(indent);
styledString.append("However, the file is not a root JET template.", problemStyler);
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
styledString.append(indent);
styledString.append("A root JET template must have have a file extension that ends with ");
styledString.append("jet", StyledString.DECORATIONS_STYLER);
styledString.append(", e.g, ");
styledString.append("MyTemplate.jet", StyledString.DECORATIONS_STYLER);
styledString.append(" or ");
styledString.append("MyTemplate.xmljet", StyledString.DECORATIONS_STYLER);
styledString.append(".");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
}
else
{
if (notOnSourcePath)
{
styledString.append(indent);
styledString.append("The class ");
if (className != null)
{
styledString.append(className, StyledString.DECORATIONS_STYLER);
styledString.append(' ');
}
styledString.append("would be generated in ");
styledString.append(getJETNature().getJavaSourceContainer().getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(", but the template is not on the template path and it will not be built when the project builds.");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
}
else
{
styledString.append(indent);
styledString.append("The class ");
if (className != null)
{
styledString.append(className, StyledString.DECORATIONS_STYLER);
styledString.append(' ');
}
styledString.append("will be generated in ");
styledString.append(getJETNature().getJavaSourceContainer().getFullPath().toString(), StyledString.DECORATIONS_STYLER);
styledString.append(".");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
}
}
styledString.append(indent);
styledString.append("The following template path is used:");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
List<Object> templateSourceContainers = getJETNature().getTemplateSourceContainers();
for (Object container : getJETNature().getTemplateContainers())
{
String containerName = container instanceof IContainer ? ((IContainer)container).getFullPath().toString() : container.toString();
styledString.append(indent);
styledString.append(" ");
styledString.append("@ ", templateSourceContainers.contains(container) ? new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
textStyle.foreground = getSourceViewer().getTextWidget().getBackground();
}
} : StyledString.COUNTER_STYLER);
styledString.append(containerName, StyledString.DECORATIONS_STYLER);
styledString.append(lineDelimiter);
}
styledString.append(lineDelimiter);
styledString.append(indent);
styledString.append("Click the tiny ", StyledString.COUNTER_STYLER);
styledString.append("\u2605", new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
textStyle.data = textStyle;
textStyle.foreground = ColorManager.INSTANCE.getColor(230, 179, 60);
}
});
styledString.append(" icon on the divider above to preview the Java results.", StyledString.COUNTER_STYLER);
if (isNotTemplate)
{
styledString.append(" Unresolved names will not be reported.", problemStyler);
}
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
Set<URI> includingTemplates = JETNature.getIncludingTemplates(toURI(file));
if (!includingTemplates.isEmpty())
{
Set<String> values = new TreeSet<String>();
for (URI includingTemplate : includingTemplates)
{
values.add(includingTemplate.isPlatformResource() ? includingTemplate.toPlatformString(true) : includingTemplate.toString());
}
styledString.append(indent);
styledString.append("This template is included by the following templates. Click any of these links to open this template in the including context:");
styledString.append(lineDelimiter);
styledString.append(lineDelimiter);
for (String includingTemplate : values)
{
styledString.append(indent);
styledString.append(indent);
Styler linkStyler = new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
StyledString.DECORATIONS_STYLER.applyStyles(textStyle);
textStyle.data = textStyle;
}
};
styledString.append(includingTemplate, linkStyler);
styledString.append(lineDelimiter);
}
}
}
return styledString;
}
void invalidateVisibleTextPresentation(boolean defer)
{
ISourceViewer jetSourceViewer = getSourceViewer();
if (defer)
{
final StyledText textWidget = jetSourceViewer.getTextWidget();
deferredInvalidatePresentation = new Runnable()
{
public void run()
{
if (deferredInvalidatePresentation == this && !textWidget.isDisposed())
{
invalidateVisibleTextPresentation(false);
}
}
};
textWidget.getDisplay().timerExec(200, deferredInvalidatePresentation);
}
else
{
deferredInvalidatePresentation = null;
int start = jetSourceViewer.getTopIndexStartOffset();
int end = jetSourceViewer.getBottomIndexEndOffset();
((ITextViewerExtension2)jetSourceViewer).invalidateTextPresentation(start, end - start);
}
}
@Override
protected void doSetInput(IEditorInput input) throws CoreException
{
super.doSetInput(input);
jetDocumentManager.handleInputChanged(input);
}
@Override
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles)
{
ISourceViewer sourceViewer = super.createSourceViewer(parent, ruler, styles);
ColorManager.INSTANCE.register(sourceViewer);
if (sourceViewer instanceof ITextViewerExtension)
{
((ITextViewerExtension)sourceViewer).prependVerifyKeyListener(bracketInserter);
}
return sourceViewer;
}
@SuppressWarnings("restriction")
@Override
protected void createActions()
{
super.createActions();
Action action = new ContentAssistAction(CodeGenUIPlugin.getResourceBundle(), "_UI_ContentAssistProposal_", this);
String id = ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS;
action.setActionDefinitionId(id);
setAction("ContentAssistProposal", action);
markAsStateDependentAction("ContentAssistProposal", true);
final IHandlerService service = (IHandlerService)getSite().getService(IHandlerService.class);
org.eclipse.jdt.internal.ui.actions.JDTQuickMenuCreator refactorMenuCreator = new org.eclipse.jdt.internal.ui.actions.JDTQuickMenuCreator(getJavaEditor())
{
@Override
protected void fillMenu(IMenuManager menu)
{
addRefactorActions(menu);
}
};
final IHandlerActivation refactorHandlerActivation = service.activateHandler(REFACTOR_QUICKMENU_COMMAND_ID, refactorMenuCreator.createHandler());
org.eclipse.jdt.internal.ui.actions.JDTQuickMenuCreator sourceMenuCreator = new org.eclipse.jdt.internal.ui.actions.JDTQuickMenuCreator(getJavaEditor())
{
@Override
protected void fillMenu(IMenuManager menu)
{
addSourceActions(menu);
}
};
final IHandlerActivation sourceHandlerActivation = service.activateHandler(SOURCE_QUICKMENU_COMMAND_ID, sourceMenuCreator.createHandler());
disposables.add(new Runnable()
{
public void run()
{
service.deactivateHandler(refactorHandlerActivation);
service.deactivateHandler(sourceHandlerActivation);
}
});
}
@Override
protected void editorContextMenuAboutToShow(IMenuManager menu)
{
editorContextMenuAboutToShow = true;
super.editorContextMenuAboutToShow(menu);
Action colorPreferencesAction = new Action(CodeGenUIPlugin.getPlugin().getString("_UI_JETColorPreferences_label"), CodeGenUIPlugin.getPlugin().getImage("full/obj16/JETFile"))
{
@Override
public void run()
{
JETToken token = getTokenAtSelection(0);
String matchingProperty = "selectColor:" + ColorManager.INSTANCE.getProperty(token);
PreferenceDialog preferenceDialog = PreferencesUtil.createPreferenceDialogOn(
getSite().getShell(),
"org.eclipse.ui.preferencePages.ColorsAndFonts",
null,
matchingProperty);
preferenceDialog.open();
}
};
menu.insertAfter(ITextEditorActionConstants.CONTEXT_PREFERENCES, colorPreferencesAction);
IContributionItem quickAssist = menu.find(ITextEditorActionConstants.QUICK_ASSIST);
if (quickAssist != null)
{
MenuManager refactorSubmenu = new MenuManager("Refac&tor", REFACTOR_QUICKMENU_MENU_ID);
refactorSubmenu.setActionDefinitionId(REFACTOR_QUICKMENU_COMMAND_ID);
addRefactorActions(refactorSubmenu);
menu.insertAfter(ITextEditorActionConstants.QUICK_ASSIST, refactorSubmenu);
MenuManager sourceSubmenu = new MenuManager("&Source", SOURCE_QUICKMENU_MENU_ID);
sourceSubmenu.setActionDefinitionId(SOURCE_QUICKMENU_COMMAND_ID);
addSourceActions(sourceSubmenu);
menu.insertAfter(ITextEditorActionConstants.QUICK_ASSIST, sourceSubmenu);
}
}
void addRefactorActions(IMenuManager refactorSubmenu)
{
IAction action = getAction(RENAME_ACTION_ID);
refactorSubmenu.add(action);
action = javaEditor.getAction(EXTRACT_LOCAL_VARIABLE_ACTION_ID);
refactorSubmenu.add(action);
}
void addSourceActions(IMenuManager sourceSubmenu)
{
IAction action = getAction(FORMAT_ACTION_ID);
sourceSubmenu.add(action);
}
@Override
public boolean isSaveAsAllowed()
{
return false;
}
@Override
public void dispose()
{
jetDocumentManager.dispose();
super.dispose();
if (javaEditor != null)
{
((IWorkbenchPart)javaEditor).dispose();
}
if (contentOutlinePage != null)
{
contentOutlinePage.dispose();
}
javaPosition.dispose();
jetPosition.dispose();
for (Runnable runnable : disposables)
{
runnable.run();
}
disposables.clear();
}
@Override
public void saveState(IMemento memento)
{
super.saveState(memento);
memento.putString("document-id", getDocumentManager().getDocumentID());
}
@Override
protected void doRestoreState(IMemento memento)
{
String documentID = memento.getString("document-id");
if (documentID != null)
{
getDocumentManager().setDocumentID(documentID);
}
super.doRestoreState(memento);
}
@Override
public INavigationLocation createEmptyNavigationLocation()
{
return new JETTextSelectionNavigationLocation(this, false);
}
@Override
public INavigationLocation createNavigationLocation()
{
return new JETTextSelectionNavigationLocation(this, true);
}
@Override
protected void editorSaved()
{
INavigationLocation[] locations = getSite().getPage().getNavigationHistory().getLocations();
IEditorInput input = getEditorInput();
for (int i = 0; i < locations.length; i++)
{
if (locations[i] instanceof JETTextSelectionNavigationLocation)
{
if (input.equals(locations[i].getInput()))
{
JETTextSelectionNavigationLocation location = (JETTextSelectionNavigationLocation)locations[i];
location.partSaved(this);
}
}
}
}
@Override
protected void performSave(boolean overwrite, IProgressMonitor progressMonitor)
{
isSaving = true;
try
{
jetDocumentManager.performSave(overwrite, progressMonitor);
}
finally
{
isSaving = false;
}
}
@Override
protected void safelySanityCheckState(IEditorInput input)
{
if (!isSaving)
{
super.safelySanityCheckState(input);
}
}
@Override
protected void performRevert()
{
jetDocumentManager.performRevert();
}
void selectAndReveal(IDocument document, int selectionStart, int selectionLength)
{
jetDocumentManager.selectAndReveal(document, selectionStart, selectionLength);
}
void selectAndReveal(final JETTextSelectionNavigationLocation navigationLocation, final int selectionStart, final int selectionLength)
{
IDocument document = jetDocumentManager.setDocumentID(navigationLocation.getDocumentID());
if (document != null)
{
navigationLocation.restoreDocument(this, document);
selectAndReveal(selectionStart, selectionLength);
selectionSynchronizer.sync(getSourceViewer());
}
else
{
pendingUntilDocumentsAvailable = new Runnable()
{
public void run()
{
selectAndReveal(navigationLocation, selectionStart, selectionLength);
}
};
}
}
void selectAndReveal(final IEditorInput editorInput, final int selectionStart, final int selectionLength)
{
String documentID = jetDocumentManager.getDocumentID(editorInput);
if (documentID != null)
{
jetDocumentManager.setDocumentID(documentID);
selectAndReveal(selectionStart, selectionLength);
selectionSynchronizer.sync(getSourceViewer());
}
else
{
pendingUntilDocumentsAvailable = new Runnable()
{
public void run()
{
selectAndReveal(editorInput, selectionStart, selectionLength);
}
};
}
}
@Override
protected void selectAndReveal(int selectionStart, int selectionLength, int revealStart, int revealLength)
{
super.selectAndReveal(selectionStart, selectionLength, revealStart, revealLength);
invalidateVisibleTextPresentation(false);
}
@Override
public Saveable[] getSaveables()
{
return jetDocumentManager.getSaveables();
}
@Override
public boolean isDirty()
{
return jetDocumentManager != null && jetDocumentManager.isDirty();
}
@Override
public boolean isEditable()
{
return jetDocumentManager.isEditable();
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object getAdapter(Class adapter)
{
if (adapter.equals(IContentOutlinePage.class))
{
return getContentOutlinePage();
}
else if (adapter.equals(IShowInSource.class))
{
return new IShowInSource()
{
public ShowInContext getShowInContext()
{
return new ShowInContext(jetDocumentManager.getEditorInput(), getSelectionProvider().getSelection());
}
};
}
else
{
return super.getAdapter(adapter);
}
}
JETContentOutlinePage getContentOutlinePage()
{
if (contentOutlinePage == null)
{
contentOutlinePage = new JETContentOutlinePage(this);
}
return contentOutlinePage;
}
JETBracketMatcher getJetBracketMatcher()
{
return jetBracketMatcher;
}
@Override
protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support)
{
support.setCharacterPairMatcher(jetBracketMatcher);
support.setMatchingCharacterPainterPreferenceKeys("matchingBrackets", "matchingBracketColor");
super.configureSourceViewerDecorationSupport(support);
}
@Override
protected void initializeKeyBindingScopes()
{
setKeyBindingScopes(new String []{ "org.eclipse.emf.codegen.ui.jetEditorScope" }); //$NON-NLS-1$
}
IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks)
{
List<IHyperlink> hyperlinks = new ArrayList<IHyperlink>();
JETCompilationUnit compilerResult = getCompilationUnit();
if (compilerResult != null)
{
URI templateURI = toPlatformResourceURI(getEditorInput());
if (templateURI != null)
{
JETItem leafJETItem = compilerResult.getJETItem(getFileID(), region.getOffset(), true);
if (leafJETItem != null)
{
JETItem rootJETItem = leafJETItem.getRoot();
if (rootJETItem instanceof JETDirectiveItem)
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)rootJETItem;
String directiveName = jetDirectiveItem.getNameItem().getText();
if ("include".equals(directiveName))
{
Object data = jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE);
if (data != null && Boolean.TRUE.equals(jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE_SUCCESS)))
{
JETAttributeItem fileAttribute = jetDirectiveItem.getAttribute("file");
JETItem valueItem = fileAttribute.getValueToken().getValueItem();
hyperlinks.add(new JETHyperLink(this, toRegion(valueItem), (Integer)jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE_FILE_ID), (String)data));
}
}
else if ("jet".equals(directiveName))
{
JETAttributeItem skeletonAttribute = jetDirectiveItem.getAttribute("skeleton");
if (skeletonAttribute != null && skeletonAttribute.isAncestor(leafJETItem))
{
Object data = jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_SKELETON);
if (data != null)
{
JETItem valueItem = skeletonAttribute.getValueToken().getValueItem();
hyperlinks.add(new JETHyperLink(this, toRegion(valueItem), -1, (String)data));
}
}
JETAttributeItem importsAttribute = jetDirectiveItem.getAttribute("imports");
if (importsAttribute != null && importsAttribute.isAncestor(leafJETItem) && leafJETItem instanceof JETValueElementItem)
{
detectedJavaHyperlinks(hyperlinks, compilerResult, region, canShowMultipleHyperlinks);
}
}
else if ("start".equals(directiveName) || "end".equals(directiveName))
{
JETDirectiveItem otherEndItem = (JETDirectiveItem)jetDirectiveItem.getData(JETDirectiveItem.SECTION_OTHER_END);
if (otherEndItem != null)
{
hyperlinks.add(new JETNavigationHyperLink(this, toRegion(jetDirectiveItem.getNameItem()), toRegion(((JETDirectiveItem)otherEndItem).getNameItem())));
}
}
}
else if (rootJETItem instanceof JETScriptletItem || rootJETItem instanceof JETExpressionItem)
{
detectedJavaHyperlinks(hyperlinks, compilerResult, region, canShowMultipleHyperlinks);
}
}
}
}
return hyperlinks.isEmpty() ? null : hyperlinks.toArray(new IHyperlink [hyperlinks.size()]);
}
void detectedJavaHyperlinks(List<IHyperlink> hyperlinks, JETCompilationUnit compilerResult, IRegion region, boolean canShowMultipleHyperlinks)
{
int fileID = getFileID();
int[] correspondingJavaPoint = compilerResult.getCorrespondingJavaPoint(fileID, region.getOffset(), 0);
if (correspondingJavaPoint != null)
{
javaEditor.selectAndReveal(correspondingJavaPoint[0], 0);
ISourceViewer javaSourceViewer = javaEditor.getJavaSourceViewer();
StyledText textWidget = javaSourceViewer.getTextWidget();
Rectangle bounds = textWidget.getCaret().getBounds();
textWidget.redraw(bounds.x, bounds.y, bounds.width, bounds.height, false);
IHyperlinkDetector[] hyperlinkDetectors = javaEditor.getHyperlinkDetectors();
if (hyperlinkDetectors != null)
{
for (IHyperlinkDetector javaHyperlinkDetector : hyperlinkDetectors)
{
IHyperlink[] javaHyperlinks = javaHyperlinkDetector.detectHyperlinks(javaSourceViewer, new Region(correspondingJavaPoint[0], 0), canShowMultipleHyperlinks);
if (javaHyperlinks != null)
{
for (IHyperlink javaHyperlink : javaHyperlinks)
{
if (!(javaHyperlink instanceof JETHyperLink))
{
IRegion hyperlinkRegion = javaHyperlink.getHyperlinkRegion();
int[] correspondingTemplatePoint = compilerResult.getCorrespondingTemplatePoint(fileID, hyperlinkRegion.getOffset(), hyperlinkRegion.getLength());
if (correspondingTemplatePoint != null)
{
hyperlinks.add(new JavaHyperLink(this, new Region(correspondingTemplatePoint[0], correspondingTemplatePoint[1]), javaHyperlink));
}
}
}
}
}
}
}
}
void setTokenData(int[] styleRangeOffsets, JETToken[] jetTokens)
{
this.styleRangeOffsets = styleRangeOffsets;
this.jetTokens = jetTokens;
}
JETToken getTokenAtSelection(int relativeOffsetFromSelection)
{
Point selectedRange = getSourceViewer().getSelectedRange();
return getTokenAt(selectedRange.x + relativeOffsetFromSelection);
}
JETToken getTokenAt(int offset)
{
ISourceViewer sourceViewer = getSourceViewer();
StyledText textWidget = sourceViewer.getTextWidget();
int charCount = textWidget.getCharCount();
if (charCount != 0)
{
JETTokenRegion tokenRegion = getTokenRegionAt(offset);
if (tokenRegion != null)
{
IToken token = tokenRegion.getToken();
if (token instanceof JETToken)
{
return (JETToken)token;
}
}
}
return JETContentRule.TOKEN;
}
Point getTokenRangeAt(int offset)
{
JETTokenRegion tokenRegion = getTokenRegionAt(offset);
if (tokenRegion != null)
{
return new Point(tokenRegion.getOffset(), tokenRegion.getLength());
}
return new Point(offset, 0);
}
JETTokenRegion getTokenRegionAt(int offset)
{
ISourceViewer sourceViewer = getSourceViewer();
StyledText textWidget = sourceViewer.getTextWidget();
int charCount = textWidget.getCharCount();
if (charCount > 0)
{
int index = Arrays.binarySearch(styleRangeOffsets, offset);
if (index < 0)
{
index = -index - 2;
}
if (index + 1 < styleRangeOffsets.length)
{
JETTokenRegion jetTokenRegion = new JETTokenRegion(styleRangeOffsets[index], styleRangeOffsets[index + 1] - styleRangeOffsets[index], jetTokens[index]);
return jetTokenRegion;
}
}
return null;
}
void openDialog(String title, IStatus status)
{
if (status != null && !status.isOK())
{
String message = status.getMessage();
if (message.length() == 0)
{
Throwable exception = status.getException();
if (exception != null)
{
message = exception.getClass().getName();
}
}
switch (status.getSeverity())
{
case IStatus.INFO:
{
MessageDialog.openInformation(getSite().getShell(), title, message);
break;
}
case IStatus.WARNING:
{
MessageDialog.openWarning(getSite().getShell(), title, message);
break;
}
case IStatus.ERROR:
default:
{
MessageDialog.openError(getSite().getShell(), title, message);
break;
}
}
}
}
static class TrackedPosition extends Position
{
private static final String CATEGORY = "__jet_" + TrackedPosition.class.hashCode();
private static final IPositionUpdater POSITION_UPDATER = new PositionUpdater();
enum Type
{
JET, JAVA
}
private IDocument document;
private final Type type;
private TrackedPosition opposite;
public TrackedPosition(Type type)
{
this.type = type;
}
public void setOpposite(TrackedPosition opposite)
{
this.opposite = opposite;
opposite.opposite = this;
}
public TrackedPosition getOpposite()
{
return opposite;
}
public void addToDocument(IDocument document)
{
if (this.document != null)
{
uninstallFromDocument(document, this, CATEGORY, POSITION_UPDATER);
}
this.document = document;
setOffset(0);
setLength(0);
undelete();
installOnDocument(document, this, CATEGORY, POSITION_UPDATER);
}
public void update(JETJavaItem jetJavaItem)
{
if (type == Type.JAVA)
{
int javaOffset = jetJavaItem.getJavaOffset();
int javaLength = jetJavaItem.getJavaLength();
update(javaOffset, javaLength);
}
else
{
int jetOffset = jetJavaItem.getStartOffset();
int jetLength = jetJavaItem.getLength();
update(jetOffset, jetLength);
}
}
public void update(int offset, int length)
{
undelete();
setOffset(offset);
setLength(length);
}
public String getText()
{
if (document != null && !isDeleted())
{
try
{
return document.get(offset, length);
}
catch (BadLocationException exception)
{
}
}
return null;
}
public void dispose()
{
if (document != null)
{
uninstallFromDocument(document, this, CATEGORY, POSITION_UPDATER);
document = null;
}
delete();
}
@Override
public String toString()
{
String toString = super.toString();
return isDeleted() ? toString : toString + " " + JETItem.toString(getText());
}
public static class PositionUpdater implements IPositionUpdater
{
protected Position position;
protected int originalPositionLength;
protected int originalPositionOffset;
protected int offset;
protected int length;
protected String text;
protected int replaceLength;
protected IDocument document;
public PositionUpdater()
{
}
protected String getCategory()
{
return CATEGORY;
}
protected void adaptToInsert()
{
int myStart = position.offset;
int myEnd2 = position.offset + position.length;
int myEnd = position.offset + position.length - 1;
myEnd = Math.max(myStart, myEnd);
int yourStart = offset;
int yourEnd = offset + length;
if (myStart == yourEnd)
{
position.offset = offset;
position.length = myEnd2 - offset + replaceLength;
}
else if (myEnd2 == yourStart)
{
position.length += replaceLength;
}
else if (myEnd >= yourStart)
{
if (myStart < yourStart)
{
position.length += replaceLength;
}
else
{
position.offset += replaceLength;
}
}
}
protected void adaptToRemove()
{
int myStart = position.offset;
int myEnd = position.offset + position.length - 1;
myEnd = Math.max(myStart, myEnd);
int yoursStart = offset;
int yoursEnd = offset + length - 1;
yoursEnd = Math.max(yoursStart, yoursEnd);
if (myEnd >= yoursStart)
{
if (myStart <= yoursStart)
{
if (yoursEnd <= myEnd)
{
position.length -= length;
}
else
{
position.length -= (myEnd - yoursStart + 1);
}
}
else if (yoursStart < myStart)
{
if (yoursEnd < myStart)
{
position.offset -= length;
}
else
{
position.offset -= (myStart - yoursStart);
position.length -= (yoursEnd - myStart + 1);
}
}
// validate position to allowed values
if (position.offset < 0)
{
position.offset = 0;
}
if (position.length < 0)
{
position.length = 0;
}
}
}
protected void adaptToReplace()
{
if (length > 0 && position.offset <= offset && offset + length <= position.offset + position.length)
{
position.length += replaceLength - length;
}
else
{
if (length > 0)
{
adaptToRemove();
}
if (replaceLength > 0)
{
adaptToInsert();
}
}
}
protected boolean notDeleted()
{
if (offset < position.offset && position.offset + position.length < offset + length)
{
position.delete();
return false;
}
return true;
}
public void update(DocumentEvent event)
{
try
{
document = event.getDocument();
Position[] category = document.getPositions(CATEGORY);
if (category.length > 0)
{
offset = event.getOffset();
length = event.getLength();
text = event.getText();
if (text == null)
{
replaceLength = 0;
text = "";
}
else
{
replaceLength = text.length();
}
for (Position element : category)
{
position = element;
originalPositionOffset = position.offset;
originalPositionLength = position.length;
if (notDeleted())
{
adaptToReplace();
}
}
}
}
catch (BadPositionCategoryException x)
{
}
finally
{
document = null;
text = null;
}
}
}
}
static class JETEditorSaveable extends Saveable
{
private JETEditor jetEditor;
private IEditorInput editorInput;
private IDocument fDocument;
public JETEditorSaveable(JETEditor jetEditor, IEditorInput editorInput)
{
this.jetEditor = jetEditor;
this.editorInput = editorInput;
}
public IEditorInput getEditorInput()
{
return editorInput;
}
public void disconnectEditor()
{
getAdapter(IDocument.class);
jetEditor = null;
}
@Override
public String getName()
{
return editorInput.getName();
}
@Override
public String getToolTipText()
{
return editorInput.getToolTipText();
}
@Override
public ImageDescriptor getImageDescriptor()
{
return editorInput.getImageDescriptor();
}
@Override
public void doSave(IProgressMonitor monitor) throws CoreException
{
jetEditor.doSave(monitor);
}
@Override
public boolean isDirty()
{
return jetEditor.getDocumentProvider().canSaveDocument(editorInput);
}
@Override
public int hashCode()
{
Object document = getAdapter(IDocument.class);
return document == null ? 0 : document.hashCode();
}
@Override
public boolean equals(Object that)
{
if (this == that)
{
return true;
}
if (!(that instanceof Saveable))
{
return false;
}
Object thisDocument = getAdapter(IDocument.class);
Object thatDocument = ((Saveable)that).getAdapter(IDocument.class);
return thisDocument == null ? thatDocument == null : thisDocument.equals(thatDocument);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getAdapter(Class adapter)
{
if (adapter == IDocument.class)
{
if (fDocument == null)
{
IDocumentProvider documentProvider = jetEditor.getDocumentProvider();
if (documentProvider != null)
{
fDocument = documentProvider.getDocument(editorInput);
}
}
return fDocument;
}
return super.getAdapter(adapter);
}
}
static class JETDocumentManager
{
private final JETEditor jetEditor;
private final Map<IEditorInput, IDocument> managedDocuments = new LinkedHashMap<IEditorInput, IDocument>();
private final Map<Integer, IDocument> fileIDs = new LinkedHashMap<Integer, IDocument>();
private final Map<Integer, String> documentIDs = new LinkedHashMap<Integer, String>();
private final Set<JETEditorSaveable> saveables = new LinkedHashSet<JETEditorSaveable>();
private final JavaSynchronizer javaSynchronizer;
private JETDynamicCompilerJob jetDynamicCompilerJob;
private int currentFileID;
private IEditorInput currentEditorInput;
public JETDocumentManager(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
javaSynchronizer = new JavaSynchronizer(jetEditor);
}
public void setEnableJavaSynchronization(boolean enable)
{
javaSynchronizer.setEnableJavaSynchronization(enable);
if (jetDynamicCompilerJob != null)
{
jetDynamicCompilerJob.setDisabled(!enable);
}
}
public void initializeDocumentManager()
{
jetEditor.getDocumentProvider().addElementStateListener(new IElementStateListener()
{
public void elementMoved(Object originalElement, Object movedElement)
{
}
public void elementDirtyStateChanged(Object element, boolean isDirty)
{
JETDocumentManager.this.jetEditor.firePropertyChange(PROP_DIRTY);
}
public void elementDeleted(Object element)
{
}
public void elementContentReplaced(Object element)
{
JETDocumentManager.this.jetEditor.firePropertyChange(PROP_DIRTY);
}
public void elementContentAboutToBeReplaced(Object element)
{
}
});
registerOutlineHandler();
registerBreadcrumbHandler();
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
IDocument document = jetSourceViewer.getDocument();
if (document != null)
{
registerDocument(currentEditorInput, document, 0, "~root");
}
updateDynamicCompilerJob(currentEditorInput);
registerSaveable(currentEditorInput);
}
protected void registerBreadcrumbHandler()
{
jetEditor.getBreadcrumbViewer().addOpenListener(new IOpenListener()
{
public void open(OpenEvent event)
{
handleItemSelection(event.getSelection());
jetEditor.setFocus();
}
});
}
protected void registerOutlineHandler()
{
jetEditor.getContentOutlinePage().addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
if (jetEditor.getContentOutlinePage().getControl().isFocusControl())
{
handleItemSelection(event.getSelection());
}
}
});
}
public void performSave(boolean overwrite, IProgressMonitor progressMonitor)
{
List<IEditorInput> changedEditorInputs = new ArrayList<IEditorInput>();
IDocumentProvider provider = jetEditor.getDocumentProvider();
try
{
for (Map.Entry<IEditorInput, IDocument> entry : managedDocuments.entrySet())
{
IEditorInput editorInput = entry.getKey();
IDocument document = entry.getValue();
if (provider.canSaveDocument(editorInput))
{
provider.aboutToChange(editorInput);
provider.saveDocument(progressMonitor, editorInput, document, overwrite);
changedEditorInputs.add(editorInput);
}
}
jetEditor.editorSaved();
}
catch (CoreException exception)
{
IStatus status = exception.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL)
{
jetEditor.handleExceptionOnSave(exception, progressMonitor);
}
}
finally
{
for (IEditorInput editorInput : changedEditorInputs)
{
provider.changed(editorInput);
}
refreshBreadcrumbs();
}
if (ResourcesPlugin.getWorkspace().isAutoBuilding() && jetDynamicCompilerJob != null)
{
Job job = new Job("Wait for build")
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
boolean wasInterrupted = false;
do
{
try
{
getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, monitor);
jetDynamicCompilerJob.documentChanged(null);
break;
}
catch (OperationCanceledException exception)
{
break;
}
catch (InterruptedException exception)
{
wasInterrupted = true;
}
}
while (wasInterrupted);
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}
public void performRevert()
{
List<IEditorInput> changedEditorInputs = new ArrayList<IEditorInput>();
IDocumentProvider provider = jetEditor.getDocumentProvider();
try
{
for (IEditorInput editorInput : managedDocuments.keySet())
{
if (provider.canSaveDocument(editorInput))
{
provider.aboutToChange(editorInput);
provider.resetDocument(editorInput);
changedEditorInputs.add(editorInput);
}
}
jetEditor.editorSaved();
}
catch (CoreException exception)
{
IStatus status = exception.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL)
{
Shell shell = jetEditor.getSite().getShell();
String title = "Problems while reverting to saved state";
String msg = "Could not revert to saved state.";
ErrorDialog.openError(shell, title, msg, exception.getStatus());
}
}
finally
{
for (IEditorInput editorInput : changedEditorInputs)
{
provider.changed(editorInput);
}
refreshBreadcrumbs();
}
}
public Saveable[] getSaveables()
{
return saveables.toArray(new Saveable [saveables.size()]);
}
public int getFileID()
{
return currentFileID;
}
public String getDocumentID()
{
return getDocumentID(currentFileID);
}
private String getDocumentID(int fileID)
{
return documentIDs.get(fileID);
}
public IDocument getDocument(int fileID)
{
return fileIDs.get(fileID);
}
String getDocumentID(IEditorInput editorInput)
{
for (Map.Entry<Integer, String> entry : this.documentIDs.entrySet())
{
String documentID = entry.getValue();
if (editorInput.equals(getEditorInput(documentID)))
{
return documentID;
}
}
return null;
}
public int getFileID(IDocument document)
{
for (Map.Entry<Integer, IDocument> entry : fileIDs.entrySet())
{
if (entry.getValue() == document)
{
return entry.getKey();
}
}
return -1;
}
public IDocument setDocumentID(String documentID)
{
for (Map.Entry<Integer, String> entry : documentIDs.entrySet())
{
if (entry.getValue().equals(documentID))
{
return setFileID(entry.getKey());
}
}
if (documentID != null)
{
IEditorInput editorInput = getEditorInput(documentID);
int fileID = -1;
while (fileIDs.containsKey(fileID))
{
--fileID;
}
getRegisteredDocument(editorInput, fileID, documentID);
return setFileID(fileID);
}
return null;
}
public void selectAndReveal(IDocument document, int offset, int length)
{
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
if (jetSourceViewer.getDocument() != document)
{
for (Map.Entry<Integer, IDocument> entry : fileIDs.entrySet())
{
if (entry.getValue() == document)
{
basicSetFileID(entry.getKey());
break;
}
}
}
if (!jetSourceViewer.overlapsWithVisibleRegion(offset, length))
{
jetSourceViewer.resetVisibleRegion();
}
jetSourceViewer.setSelectedRange(offset, length);
jetSourceViewer.revealRange(offset, length);
}
public IDocument setFileID(int fileID)
{
IDocument document = basicSetFileID(fileID);
JETContentOutlinePage.Item selectionForFileID = jetEditor.getContentOutlinePage().getSelectionForDocumentID(getDocumentID(fileID));
if (selectionForFileID != null)
{
jetEditor.getBreadcrumbViewer().setInput(selectionForFileID);
jetEditor.getContentOutlinePage().setSelection(new StructuredSelection(selectionForFileID), true);
}
return document;
}
public IEditorInput getEditorInput()
{
IEditorInput editorInput = getEditorInput(getDocument(currentFileID));
return editorInput == null ? jetEditor.getEditorInput() : editorInput;
}
protected IEditorInput getEditorInput(IDocument document)
{
for (Map.Entry<IEditorInput, IDocument> entry : managedDocuments.entrySet())
{
if (entry.getValue() == document)
{
return entry.getKey();
}
}
return null;
}
protected IEditorInput getEditorInput(int fileID)
{
if (fileID == 0)
{
return jetEditor.getEditorInput();
}
else
{
String documentID = documentIDs.get(fileID);
return getEditorInput(documentID);
}
}
private IEditorInput getEditorInput(String documentID)
{
String templateURI = documentID.replaceAll("~[0-9]+$", "");
return toEditorInput(URI.createURI(templateURI));
}
protected IDocument basicSetFileID(int fileID)
{
IEditorInput editorInput = getEditorInput(fileID);
IDocument registeredDocument = getRegisteredDocument(editorInput, fileID, documentIDs.get(fileID));
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
if (registeredDocument != null && registeredDocument != jetSourceViewer.getDocument())
{
IAnnotationModel model = jetEditor.getDocumentProvider().getAnnotationModel(editorInput);
if (model == null)
{
model = new AnnotationModel();
}
boolean javaEditorInSync = jetEditor.isJavaEditorInSync();
setDocument(editorInput, registeredDocument, model);
if (javaEditorInSync)
{
jetEditor.setExpectedModificationStamp();
}
this.currentFileID = fileID;
jetEditor.handleFileIDChanged(fileID);
registerSaveable(editorInput);
hookDynamicCompilerJob(registeredDocument);
}
else if (this.currentFileID != fileID)
{
this.currentFileID = fileID;
jetEditor.handleFileIDChanged(fileID);
}
return registeredDocument;
}
protected void setDocument(IEditorInput editorInput, IDocument document, IAnnotationModel annotationModel)
{
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
jetSourceViewer.setDocument(document, annotationModel);
IDocumentProvider documentProvider = jetEditor.getDocumentProvider();
if (documentProvider instanceof IDocumentProviderExtension)
{
jetSourceViewer.setEditable(!((IDocumentProviderExtension)documentProvider).isReadOnly(editorInput));
}
}
public boolean isEditable()
{
IDocumentProviderExtension documentProvider = (IDocumentProviderExtension)jetEditor.getDocumentProvider();
IDocument document = fileIDs.get(currentFileID);
IEditorInput editorInput = getEditorInput(document);
return editorInput != null && !documentProvider.isReadOnly(editorInput);
}
public boolean isDirty(int fileID)
{
IDocument document = fileIDs.get(fileID);
IEditorInput editorInput = getEditorInput(document);
return editorInput != null && jetEditor.getDocumentProvider().canSaveDocument(editorInput);
}
public boolean isDirty()
{
IDocumentProvider documentProvider = jetEditor.getDocumentProvider();
if (documentProvider != null)
{
for (IEditorInput editorInput : managedDocuments.keySet())
{
if (documentProvider.canSaveDocument(editorInput))
{
return true;
}
}
}
return false;
}
protected void registerSaveable(IEditorInput editorInput)
{
// Equality checking will prevent duplicates.
// The first one added will not send a life cycle event because that happens automatically when the part is opened.
JETEditorSaveable saveable = new JETEditorSaveable(jetEditor, editorInput);
if (saveables.add(saveable) && saveables.size() > 1)
{
ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener)jetEditor.getSite().getService(ISaveablesLifecycleListener.class);
if (listener != null)
{
listener.handleLifecycleEvent(new SaveablesLifecycleEvent(jetEditor, SaveablesLifecycleEvent.POST_OPEN, new Saveable []{ saveable }, false));
}
}
}
public void handleInputChanged(IEditorInput editorInput)
{
ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener)jetEditor.getSite().getService(ISaveablesLifecycleListener.class);
if (listener != null)
{
if (!saveables.isEmpty())
{
listener.handleLifecycleEvent(new SaveablesLifecycleEvent(jetEditor, SaveablesLifecycleEvent.POST_CLOSE, getSaveables(), false));
discardSaveables();
}
registerSaveable(editorInput);
}
this.currentEditorInput = editorInput;
updateDynamicCompilerJob(editorInput);
}
public void dispose()
{
if (jetDynamicCompilerJob != null)
{
jetDynamicCompilerJob.cancel();
for (IDocument document : managedDocuments.values())
{
unhookDynamicCompilerJob(document);
}
}
IDocumentProvider documentProvider = jetEditor.getDocumentProvider();
for (IEditorInput editorInput : managedDocuments.keySet())
{
// The source viewer will disconnect itself from the editor's current input so skip that one.
if (!editorInput.equals(this.currentEditorInput))
{
documentProvider.disconnect(editorInput);
}
}
discardSaveables();
for (IDocument document : managedDocuments.values())
{
document.removeDocumentListener(javaSynchronizer);
}
managedDocuments.clear();
fileIDs.clear();
documentIDs.clear();
}
protected void discardSaveables()
{
for (JETEditorSaveable saveable : saveables)
{
saveable.disconnectEditor();
}
saveables.clear();
}
protected void updateDynamicCompilerJob(IEditorInput input)
{
if (jetDynamicCompilerJob != null)
{
jetDynamicCompilerJob.cancel();
for (IDocument document : managedDocuments.values())
{
unhookDynamicCompilerJob(document);
}
jetDynamicCompilerJob = null;
}
IFile file = toFile(input);
if (file != null)
{
jetDynamicCompilerJob = new JETDynamicCompilerJob(jetEditor, file);
jetDynamicCompilerJob.schedule();
for (IDocument document : managedDocuments.values())
{
hookDynamicCompilerJob(document);
}
}
}
protected void hookDynamicCompilerJob(IDocument document)
{
document.addDocumentListener(jetDynamicCompilerJob);
}
protected void unhookDynamicCompilerJob(IDocument document)
{
document.removeDocumentListener(jetDynamicCompilerJob);
}
protected void handleItemSelection(ISelection selection)
{
if (!selection.isEmpty())
{
JETContentOutlinePage contentOutlinePage = jetEditor.getContentOutlinePage();
int fileID = contentOutlinePage.getFileID(selection);
basicSetFileID(fileID);
Region region = contentOutlinePage.getRegion(selection);
if (region != null)
{
jetEditor.selectAndReveal(region.getOffset(), region.getLength());
}
JETContentOutlinePage.Item selectedItem = contentOutlinePage.getSelectionForDocumentID(getDocumentID(fileID));
if (selectedItem != null)
{
jetEditor.getBreadcrumbViewer().setInput(selectedItem);
contentOutlinePage.setSelection(new StructuredSelection(selectedItem), true);
}
}
}
protected IDocument getRegisteredDocument(IEditorInput editorInput, int fileID, String documentID)
{
IDocument document = fileIDs.get(fileID);
if (document == null && editorInput != null)
{
IDocumentProvider documentProvider = jetEditor.getDocumentProvider();
if (!managedDocuments.containsKey(editorInput))
{
try
{
documentProvider.connect(editorInput);
}
catch (CoreException exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
document = documentProvider.getDocument(editorInput);
if (document != null)
{
registerDocument(editorInput, document, fileID, documentID);
}
}
return document;
}
protected void registerDocument(IEditorInput editorInput, IDocument document, int fileID, String documentID)
{
managedDocuments.put(editorInput, document);
fileIDs.put(fileID, document);
documentIDs.put(fileID, documentID);
document.addDocumentListener(javaSynchronizer);
jetEditor.getJETPosition().addToDocument(document);
}
public void setCompilerResult(JETCompilerResult jetCompilerResult)
{
String currentDocumentID = getDocumentID();
Set<IDocument> orphanDocuments = new LinkedHashSet<IDocument>(fileIDs.values());
JETCompilationUnit compilationUnit = jetCompilerResult.getCompilationUnit();
if (compilationUnit != null)
{
fileIDs.clear();
documentIDs.clear();
int fileID = 0;
for (String templateURI : compilationUnit.getTemplateURIs())
{
String documentID;
if (fileID == 0)
{
documentID = "~root";
documentIDs.put(0, documentID);
}
else
{
documentID = templateURI;
String collision = documentIDs.put(fileID, templateURI);
for (int count = 1; collision != null; ++count)
{
documentIDs.put(fileID, collision);
documentID = templateURI + "~" + count;
collision = documentIDs.put(fileID, documentID);
}
}
IDocument document = managedDocuments.get(toEditorInput(URI.createURI(templateURI)));
if (document != null)
{
fileIDs.put(fileID, document);
if (documentID.equals(currentDocumentID))
{
this.currentFileID = fileID;
}
}
++fileID;
}
// Assign orphaned documents negative file IDs.
orphanDocuments.removeAll(fileIDs.values());
if (!orphanDocuments.isEmpty())
{
fileID = -1;
for (IDocument orphanDocument : orphanDocuments)
{
fileIDs.put(fileID, orphanDocument);
for (Map.Entry<IEditorInput, IDocument> entry : managedDocuments.entrySet())
{
if (entry.getValue() == orphanDocument)
{
URI templateURI = toURI(entry.getKey());
documentIDs.put(fileID, templateURI.toString());
break;
}
}
--fileID;
}
}
}
JETContentOutlinePage contentOutlinePage = jetEditor.getContentOutlinePage();
contentOutlinePage.setCompilerResult(jetCompilerResult, documentIDs);
refreshBreadcrumbs();
}
private void refreshBreadcrumbs()
{
JETBreadcrumbViewer breadcrumbViewer = jetEditor.getBreadcrumbViewer();
JETContentOutlinePage.Item currentInput = (JETContentOutlinePage.Item)breadcrumbViewer.getInput();
JETContentOutlinePage.Item newCurrentInput = jetEditor.getContentOutlinePage().getSelectionForDocumentID(getDocumentID(currentFileID));
if (currentInput != newCurrentInput && newCurrentInput != null)
{
breadcrumbViewer.setInput(newCurrentInput);
jetEditor.getContentOutlinePage().setSelection(new StructuredSelection(newCurrentInput), true);
}
else
{
breadcrumbViewer.refresh(true);
for (JETContentOutlinePage.Item item = currentInput; item != null; item = item.getParent())
{
breadcrumbViewer.update(item, null);
}
}
}
static class JavaSynchronizer implements IDocumentListener
{
private final JETEditor jetEditor;
private boolean disabled;
public JavaSynchronizer(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
public void setEnableJavaSynchronization(boolean enable)
{
this.disabled = !enable;
}
public void documentChanged(DocumentEvent event)
{
if (!disabled)
{
int eventOffset = event.getOffset();
JETTokenRegion tokenRegion = jetEditor.getTokenRegionAt(eventOffset);
if (tokenRegion != null)
{
JETToken token = tokenRegion.getToken();
if (token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN)
{
// Compute the location relative to the start of the Java in the region
// because as we add characters, we might add beyond the currently corresponding region.
tokenRegion.shrinkToJava(event.getDocument());
int tokenJavaStart = tokenRegion.getOffset();
Position correspondingJavaPosition = jetEditor.getCorrespondingJavaPosition(tokenJavaStart, 0);
if (correspondingJavaPosition != null)
{
try
{
ISourceViewer javaSourceViewer = jetEditor.getJavaSourceViewer();
int javaOffset = correspondingJavaPosition.getOffset() + eventOffset - tokenJavaStart;
int eventLength = event.getLength();
javaSourceViewer.getDocument().replace(javaOffset, eventLength, event.getText());
javaSourceViewer.setSelectedRange(javaOffset + 1 - eventLength, 0);
}
catch (BadLocationException exception)
{
}
}
}
}
}
}
public void documentAboutToBeChanged(DocumentEvent event)
{
}
}
}
static class JETContentOutlinePage extends ContentOutlinePage
{
private final ItemManager itemManager = new ItemManager();
private final LabelProvider labelProvider = new LabelProvider();
private final ContentProvider contentProvider = new ContentProvider();
private final ISelectionChangedListener jetSourceViewerSynchronizer = new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
if (treeViewer != null && !treeViewer.getControl().isFocusControl())
{
ITextSelection selection = (ITextSelection)event.getSelection();
int offset = selection.getOffset();
JETItem jetItem = jetEditor.getJETItem(offset, false);
if (jetItem != null)
{
Item correspondingItem = itemManager.getRootItem().getCorrespondingItem(jetItem);
if (correspondingItem != null)
{
setSelection(new StructuredSelection(correspondingItem), true);
}
}
}
}
};
private final JETEditor jetEditor;
private TreeViewer treeViewer;
public JETContentOutlinePage(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
public StyledCellLabelProvider newLabelProvider()
{
return new LabelProvider()
{
@Override
protected StyledString getStyledText(Object element)
{
StyledString styledText = super.getStyledText(element);
if (element instanceof Item)
{
Item item = (Item)element;
if (item.isBreadcumbSurrogate())
{
int fileID = itemManager.getFileID(item);
if (jetEditor.getDocumentManager().isDirty(fileID))
{
StyledString newStyledString = new StyledString();
newStyledString.append('*');
newStyledString.append(styledText);
styledText = newStyledString;
}
if (fileID == jetEditor.getFileID())
{
styledText.setStyle(0, styledText.length(), Item.getFontStyler(SWT.BOLD));
}
}
}
return styledText;
}
};
}
public ITreeContentProvider getContentProvider()
{
return contentProvider;
}
public Item getSelectionForDocumentID(String documentID)
{
return itemManager.getSelectionForDocumentID(documentID);
}
public void setSelection(ISelection selection, boolean reveal)
{
if (treeViewer != null && !treeViewer.getControl().isFocusControl())
{
treeViewer.setSelection(selection, reveal);
}
}
@Override
public void createControl(Composite parent)
{
super.createControl(parent);
treeViewer = getTreeViewer();
treeViewer.setLabelProvider(labelProvider);
treeViewer.setContentProvider(contentProvider);
treeViewer.setInput(itemManager.getRootItem());
jetEditor.getSelectionProvider().addSelectionChangedListener(jetSourceViewerSynchronizer);
registerToolBarActions();
}
@SuppressWarnings("restriction")
private void registerToolBarActions()
{
class ExpandAllAction extends Action
{
public ExpandAllAction()
{
super("", CodeGenUIPlugin.getPlugin().getImage("full/ctool16/ExpandAll.png"));
setToolTipText("Expand all");
setActionDefinitionId(ExpandAllHandler.COMMAND_ID);
}
@Override
public void run()
{
try
{
treeViewer.getControl().setRedraw(false);
treeViewer.expandAll();
}
finally
{
treeViewer.getControl().setRedraw(true);
}
}
}
IToolBarManager toolBarManager = getSite().getActionBars().getToolBarManager();
toolBarManager.add(new ExpandAllAction());
org.eclipse.jdt.internal.ui.actions.CollapseAllAction collapseAllAction = new org.eclipse.jdt.internal.ui.actions.CollapseAllAction(treeViewer);
collapseAllAction.setActionDefinitionId(CollapseAllHandler.COMMAND_ID);
toolBarManager.add(collapseAllAction);
}
@Override
public void dispose()
{
treeViewer = null;
ISelectionProvider selectionProvider = jetEditor.getSelectionProvider();
if (selectionProvider != null)
{
selectionProvider.removeSelectionChangedListener(jetSourceViewerSynchronizer);
}
super.dispose();
}
public void setCompilerResult(JETCompilerResult jetCompilerResult, Map<Integer, String> documentIDs)
{
itemManager.setCompilerResult(jetCompilerResult, documentIDs);
if (treeViewer != null)
{
treeViewer.refresh();
}
}
public int getFileID(ISelection selection)
{
Item item = getSelectedItem(selection);
return item == null ? 0 : itemManager.getFileID(item);
}
public Item getSelectedItem(ISelection selection)
{
IStructuredSelection structuredSelection = (IStructuredSelection)selection;
return (Item)structuredSelection.getFirstElement();
}
protected JETItem getSelectedJETItem(ISelection selection)
{
Item selectedItem = getSelectedItem(selection);
return selectedItem == null ? null : selectedItem.getJETItem();
}
public Region getRegion(ISelection selection)
{
JETItem selectedJETItem = getSelectedJETItem(selection);
if (selectedJETItem != null)
{
int start = selectedJETItem.getStartOffset();
int stop = selectedJETItem.getStopOffset();
return new Region(start, stop - start);
}
else
{
return null;
}
}
private static class LabelProvider extends StyledCellLabelProvider implements ILabelProvider
{
private static final Map<Font, Font[]> FONTS = new HashMap<Font, Font[]>();
@Override
public void update(ViewerCell cell)
{
Object element = cell.getElement();
StyledString styledString = getStyledText(element);
String newText = styledString.toString();
StyleRange[] oldStyleRanges = cell.getStyleRanges();
StyleRange[] newStyleRanges = isOwnerDrawEnabled() ? styledString.getStyleRanges() : null;
if (!Arrays.equals(oldStyleRanges, newStyleRanges))
{
cell.setStyleRanges(newStyleRanges);
if (cell.getText().equals(newText))
{
cell.setText("");
}
}
cell.setText(newText);
cell.setImage(getImage(element));
super.update(cell);
}
private FontData[] getFontData(int style)
{
FontData[] fontDatas = getViewer().getControl().getFont().getFontData();
for (int i = 0; i < fontDatas.length; i++)
{
fontDatas[i].setStyle(style);
}
return fontDatas;
}
private Font getFont(int fontStyle)
{
if (fontStyle > 0 && fontStyle <= (SWT.BOLD | SWT.ITALIC))
{
Font baseFont = getViewer().getControl().getFont();
Font[] fonts = FONTS.get(baseFont);
if (fonts == null)
{
fonts = new Font [SWT.BOLD | SWT.ITALIC];
FONTS.put(baseFont, fonts);
}
Font font = fonts[fontStyle - 1];
if (font == null)
{
font = new Font(baseFont.getDevice(), getFontData(fontStyle));
fonts[fontStyle - 1] = font;
}
return font;
}
else
{
return null;
}
}
@Override
protected StyleRange prepareStyleRange(StyleRange styleRange, boolean applyColors)
{
StyleRange preparedStyledRange = super.prepareStyleRange(styleRange, applyColors);
preparedStyledRange.font = getFont(styleRange.fontStyle);
return preparedStyledRange;
}
public Image getImage(Object element)
{
if (element instanceof Item)
{
return ((Item)element).getImage();
}
return null;
}
protected StyledString getStyledText(Object element)
{
if (element instanceof Item)
{
return ((Item)element).getStyledText();
}
if (element instanceof JETItem)
{
return new StyledString(((JETItem)element).getText());
}
return new StyledString("Root");
}
public String getText(Object element)
{
return getStyledText(element).toString();
}
}
private static class ContentProvider implements ITreeContentProvider
{
public Object[] getElements(Object inputElement)
{
return getChildren(inputElement);
}
public Object[] getChildren(Object parentElement)
{
return ((Item)parentElement).getChildren().toArray();
}
public Object getParent(Object element)
{
return ((Item)element).getParent();
}
public boolean hasChildren(Object element)
{
return getChildren(element).length > 0;
}
public void dispose()
{
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
}
private static class ItemManager extends Item
{
private static final Pattern COMMENT_PATTERN = Pattern.compile("^[^\n\r]*\\[([^\\]\n\r]*)\\]");
private final HashMap<String, Item> managedItems = new HashMap<String, Item>();
private final HashMap<String, Integer> documementIDsToFileIDs = new HashMap<String, Integer>();
public ItemManager()
{
super("~top", null, "top");
Item rootItem = createItem(managedItems, "~root", null, "root");
rootItem.setParent(this);
documementIDsToFileIDs.put("~root", 0);
}
public Item getRootItem()
{
return getChildren().get(0);
}
public int getFileID(Item item)
{
if (item.jetItem != null)
{
return item.jetItem.getFileID();
}
else if ("orphan".equals(item.type))
{
return documementIDsToFileIDs.get(item.signature.substring(0, item.signature.lastIndexOf("~orphan")));
}
else
{
return 0;
}
}
public Item getSelectionForDocumentID(String documentID)
{
Item result = managedItems.get(documentID + "~content");
if (result == null)
{
result = managedItems.get(documentID + "~orphan");
if (result == null)
{
result = managedItems.get(documentID);
}
}
return result;
}
public void setCompilerResult(JETCompilerResult comilerResult, Map<Integer, String> documentIDs)
{
JETCompilationUnit compilerResult = comilerResult.getCompilationUnit();
if (compilerResult != null)
{
Item newTopItem = createItems(compilerResult, documentIDs);
reconcile(newTopItem);
handleProblems(comilerResult);
}
}
@Override
protected void reconcile(Item newItem)
{
super.reconcile(newItem);
managedItems.clear();
rebuildMap(managedItems);
}
private Item createTopItem(Map<String, Item> managedItems)
{
Item topItem = createItem(managedItems, "~top", null, "top");
Item rootItem = createItem(managedItems, "~root", null, "root");
rootItem.setParent(topItem);
return topItem;
}
protected Item createItems(JETCompilationUnit compilerResult, Map<Integer, String> documentIDs)
{
documementIDsToFileIDs.clear();
Map<String, Item> newManagedItems = new HashMap<String, Item>();
Item newTopItem = createTopItem(newManagedItems);
Item newRootItem = newTopItem.getChildren().get(0);
List<Item> items = new ArrayList<Item>();
List<JETItem> jetItems = compilerResult.getItems();
if (!jetItems.isEmpty())
{
newRootItem.setJetItem(jetItems.get(0));
List<Item> resolvedIncludeSuccessItems = new ArrayList<Item>();
List<Item> flatContentItems = new ArrayList<Item>();
for (JETItem jetItem : jetItems)
{
if (jetItem instanceof JETDirectiveItem)
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetItem;
JETSkeleton skeleton = (JETSkeleton)jetDirectiveItem.getData(JETDirectiveItem.SKELETON);
if (skeleton != null)
{
if (jetDirectiveItem.getLength() != 0)
{
String qualifiedClassName = skeleton.getQualifiedClassName();
Item directiveItem = createItem(newManagedItems, qualifiedClassName, jetItem, "jet");
directiveItem.setParent(newRootItem);
items.add(directiveItem);
}
}
else
{
String resolvedInclude = (String)jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE);
if (resolvedInclude != null)
{
Item includeItem = createItem(newManagedItems, resolvedInclude, jetItem, "include");
items.add(includeItem);
includeItem.setParent(newRootItem);
if (Boolean.TRUE.equals(jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE_SUCCESS)))
{
resolvedIncludeSuccessItems.add(includeItem);
JETItem contentStartItem = (JETItem)jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE_START);
Item item = createItem(newManagedItems, documentIDs.get(contentStartItem.getFileID()) + "~content", contentStartItem, "content");
item.setParent(includeItem);
flatContentItems.add(item);
}
}
}
}
else if (jetItem instanceof JETCommentItem)
{
Matcher matcher = COMMENT_PATTERN.matcher(jetItem.getText());
if (matcher.find())
{
String signature = matcher.group(1);
Item commentItem = createItem(newManagedItems, signature + "~comment", jetItem, "comment");
items.add(commentItem);
commentItem.setParent(newRootItem);
}
}
}
List<Item> originalItems = new ArrayList<Item>(items);
List<Item> rootItems = refactorIncludes(items, jetItems, newManagedItems);
refactorInclusion(resolvedIncludeSuccessItems, originalItems, rootItems);
for (Item item : flatContentItems)
{
int fileID = item.getJETItem().getFileID();
Item indexItem = createItem(newManagedItems, documentIDs.get(fileID) + "~root", item.getJETItem(), "root");
indexItem.setParent(newRootItem.getParent());
}
for (Map.Entry<Integer, String> entry : documentIDs.entrySet())
{
int fileID = entry.getKey();
String documentID = entry.getValue();
documementIDsToFileIDs.put(documentID, fileID);
if (fileID < 0)
{
Item indexItem = createItem(newManagedItems, documentID + "~orphan", null, "orphan");
indexItem.setParent(newRootItem.getParent());
}
}
}
return newTopItem;
}
private void refactorInclusion(List<Item> resolvedIncludeSuccessItems, List<Item> items, List<Item> rootItems)
{
for (Item item : items)
{
JETItem jetItem = item.getJETItem();
int fileID = jetItem.getFileID();
if (fileID != 0)
{
if (item.getParent().getJETItem().getFileID() != fileID)
{
Item inclusionItem = resolvedIncludeSuccessItems.get(fileID - 1);
item.setParent(inclusionItem);
rootItems.remove(item);
}
}
}
}
private List<Item> refactorIncludes(List<Item> items, List<JETItem> jetItems, Map<String, Item> managedItems)
{
List<Item> result = new ArrayList<Item>();
while (!items.isEmpty())
{
Item item = items.remove(0);
captureChildren(item, items, jetItems, managedItems);
result.add(item);
}
return result;
}
private void captureChildren(Item item, List<Item> remainingItems, List<JETItem> jetItems, Map<String, Item> managedItems)
{
JETItem jetItem = item.getJETItem();
if (jetItem instanceof JETDirectiveItem)
{
JETDirectiveItem parentJETItem = (JETDirectiveItem)jetItem;
JETDirectiveItem start = (JETDirectiveItem)parentJETItem.getData(JETDirectiveItem.SECTION_START);
JETDirectiveItem end = (JETDirectiveItem)parentJETItem.getData(JETDirectiveItem.SECTION_END);
if (start != null && end != null)
{
String signature = item.getSignature();
createItem(managedItems, signature + "~start", start, "start").setParent(item);
int startIndex = jetItems.indexOf(start) + 1;
int endIndex = jetItems.indexOf(end) - 1;
for (int i = startIndex; i <= endIndex; ++i)
{
JETItem jetChildItem = jetItems.get(i);
if (jetChildItem instanceof JETDirectiveItem || jetChildItem instanceof JETCommentItem)
{
for (Item managedItem : managedItems.values())
{
if (managedItem.getJETItem() == jetChildItem && remainingItems.remove(managedItem))
{
// Recursively capture the children of nested includes.
managedItem.setParent(item);
captureChildren(managedItem, remainingItems, jetItems, managedItems);
break;
}
}
}
}
createItem(managedItems, signature + "~end", end, "end").setParent(item);
}
}
}
private Item createItem(Map<String, Item> managedItems, String signature, JETItem jetItem, String type)
{
String uniqueSignature = signature;
for (Item item = managedItems.get(uniqueSignature); item != null; item = managedItems.get(uniqueSignature))
{
uniqueSignature += "_";
}
Item item = new Item(uniqueSignature, jetItem, type);
managedItems.put(uniqueSignature, item);
return item;
}
}
private static class Item
{
private static final Map<String, Image> IMAGES = new HashMap<String, Image>();
private static final Map<String, Image> ERROR_IMAGES = new HashMap<String, Image>();
private static final Map<String, Image> WARNING_IMAGES = new HashMap<String, Image>();
private static final Map<String, Image> INFO_IMAGES = new HashMap<String, Image>();
private static final Map<Integer, Map<String, Image>> ALL_IMAGES = new HashMap<Integer, Map<String, Image>>();
static
{
CodeGenUIPlugin plugin = CodeGenUIPlugin.getPlugin();
IMAGES.put("start", plugin.getActualImage("full/obj16/DirectiveStart"));
IMAGES.put("end", plugin.getActualImage("full/obj16/DirectiveEnd"));
IMAGES.put("include", plugin.getActualImage("full/obj16/DirectiveInclude"));
IMAGES.put("jet", plugin.getActualImage("full/obj16/JET"));
IMAGES.put("skeleton", plugin.getActualImage("full/obj16/Skeleton"));
IMAGES.put("nlstring", plugin.getActualImage("full/obj16/NLString"));
IMAGES.put("comment", plugin.getActualImage("full/obj16/Comment.png"));
Image content = plugin.getActualImage("full/obj16/IncludeContent");
IMAGES.put("content", content);
IMAGES.put("root", content);
IMAGES.put("orphan", content);
org.eclipse.jdt.ui.ISharedImages sharedImages = JavaUI.getSharedImages();
IMAGES.put("package", sharedImages.getImage(org.eclipse.jdt.ui.ISharedImages.IMG_OBJS_PACKAGE));
IMAGES.put("class", sharedImages.getImage(org.eclipse.jdt.ui.ISharedImages.IMG_OBJS_CLASS));
IMAGES.put("import", sharedImages.getImage(org.eclipse.jdt.ui.ISharedImages.IMG_OBJS_IMPDECL));
Point size = new Point(16, 16);
for (Map.Entry<String, Image> entry : IMAGES.entrySet())
{
// It should use JavaElementImageDescriptor.WARNING but that's not available in Helios.
int info = JavaElementImageDescriptor.WARNING;
try
{
info = (Integer)JavaElementImageDescriptor.class.getField("INFO").get(null);
}
catch (Exception exception)
{
// Ignore;
}
Image image = new JavaElementImageDescriptor(ImageDescriptor.createFromImage(entry.getValue()), info, size).createImage();
INFO_IMAGES.put(entry.getKey(), image);
}
for (Map.Entry<String, Image> entry : IMAGES.entrySet())
{
Image image = new JavaElementImageDescriptor(ImageDescriptor.createFromImage(entry.getValue()), JavaElementImageDescriptor.WARNING, size).createImage();
WARNING_IMAGES.put(entry.getKey(), image);
}
for (Map.Entry<String, Image> entry : IMAGES.entrySet())
{
Image image = new JavaElementImageDescriptor(ImageDescriptor.createFromImage(entry.getValue()), JavaElementImageDescriptor.ERROR, size).createImage();
ERROR_IMAGES.put(entry.getKey(), image);
}
ALL_IMAGES.put(-1, IMAGES);
ALL_IMAGES.put(IMarker.SEVERITY_INFO, INFO_IMAGES);
ALL_IMAGES.put(IMarker.SEVERITY_WARNING, WARNING_IMAGES);
ALL_IMAGES.put(IMarker.SEVERITY_ERROR, ERROR_IMAGES);
}
private static final Styler STRIKE_OUT_STYLER = new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
textStyle.strikeout = true;
}
};
private static final Styler[] FONT_STYLERS = new Styler [SWT.BOLD | SWT.ITALIC];
private static final Styler getFontStyler(final int fontStyle)
{
if (fontStyle > 0 && fontStyle < (SWT.BOLD | SWT.ITALIC))
{
Styler styler = FONT_STYLERS[fontStyle];
if (styler == null)
{
styler = new Styler()
{
@Override
public void applyStyles(TextStyle textStyle)
{
((StyleRange)textStyle).fontStyle = fontStyle;
}
};
FONT_STYLERS[fontStyle] = styler;
}
return styler;
}
else
{
return null;
}
}
private final List<Item> children = new ArrayList<Item>();
private final String type;
private final String signature;
private Item parent;
private JETItem jetItem;
private int problemSeverity = -1;
public Item(String signature, JETItem jetItem, String type)
{
this.signature = signature;
this.jetItem = jetItem;
this.type = type == null ? getDirectiveType(jetItem) : type;
if ("jet".equals(type))
{
createJETChildren();
}
}
public Item getCorrespondingItem(JETItem jetItem)
{
for (Item child : children)
{
Item result = child.getCorrespondingItem(jetItem);
if (result != null)
{
return result;
}
}
return this.jetItem == jetItem ? this : null;
}
public boolean isBreadcumbSurrogate()
{
return "root".equals(type) || "orphan".equals(type);
}
public int handleProblems(JETCompilerResult compilerResult)
{
int maxSeverity = -1;
for (Item child : children)
{
maxSeverity = Math.max(maxSeverity, child.handleProblems(compilerResult));
}
if ("class".equals(type))
{
int overallSeverity = getJavaProblemSeverity(compilerResult.getJavaProblems());
maxSeverity = Math.max(maxSeverity, overallSeverity);
}
else if ("content".equals(type) || "root".equals(type))
{
int overallSeverity = getProblemSeverity(compilerResult.getProblems(jetItem.getFileID()));
maxSeverity = Math.max(maxSeverity, overallSeverity);
}
else if ("jet".equals(type) && Boolean.TRUE.equals(((JETDirectiveItem)jetItem).getData(JETDirectiveItem.MISSING_JET_DIRECTIVE)))
{
maxSeverity = IMarker.SEVERITY_ERROR;
}
else if ("orphan".equals(type))
{
maxSeverity = IMarker.SEVERITY_WARNING;
}
else if (jetItem != null)
{
int localSeverity = getProblemSeverity(compilerResult.getProblem(jetItem));
maxSeverity = Math.max(maxSeverity, localSeverity);
}
this.problemSeverity = maxSeverity;
return maxSeverity;
}
private static final Method INFO_METHOD;
static
{
Method infoMethod = null;
try
{
infoMethod = IProblem.class.getMethod("isInfo");
}
catch (Exception exception)
{
// Ignore.
}
INFO_METHOD = infoMethod;
}
private static boolean isInfo(IProblem problem)
{
try
{
return (Boolean)INFO_METHOD.invoke(problem);
}
catch (Exception exception)
{
return false;
}
}
private int getJavaProblemSeverity(List<IProblem> problems)
{
int result = -1;
for (IProblem problem : problems)
{
int severity = isInfo(problem) ? IMarker.SEVERITY_INFO : problem.isWarning() ? IMarker.SEVERITY_WARNING : problem.isError() ? IMarker.SEVERITY_ERROR : -1;
result = Math.max(result, severity);
if (result == IMarker.SEVERITY_ERROR)
{
return IMarker.SEVERITY_ERROR;
}
}
return result;
}
private int getProblemSeverity(List<JETProblemAnnotation> problems)
{
int result = -1;
for (JETProblemAnnotation problem : problems)
{
result = Math.max(result, problem.getSeverity());
if (result == IMarker.SEVERITY_ERROR)
{
return IMarker.SEVERITY_ERROR;
}
}
return result;
}
protected void rebuildMap(HashMap<String, Item> managedItems)
{
managedItems.put(signature, this);
for (Item child : children)
{
child.rebuildMap(managedItems);
}
}
protected void reconcile(Item newItem)
{
// Remove all the existing children.
Item[] existingChildren = children.toArray(new Item [children.size()]);
Map<String, Item> signatures = new HashMap<String, Item>();
for (Item child : existingChildren)
{
child.setParent(null);
signatures.put(child.getSignature(), child);
}
Item[] newChildren = newItem.children.toArray(new Item [newItem.children.size()]);
for (Item newChild : newChildren)
{
Item correspondingOldChild = signatures.get(newChild.getSignature());
if (correspondingOldChild == null)
{
// Add the new child.
newChild.setParent(this);
}
else
{
// Add the old child back in, transfer the new JET item and recursively reconcile its children.
correspondingOldChild.setParent(this);
correspondingOldChild.jetItem = newChild.jetItem;
correspondingOldChild.reconcile(newChild);
}
}
}
private void createJETChildren()
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetItem;
if (!Boolean.TRUE.equals(jetDirectiveItem.getData(JETDirectiveItem.DUPLICATE_JET_DIRECTIVE)))
{
JETAttributeItem packageAttributeItem = jetDirectiveItem.getAttribute("package");
Item rootItem = this;
if (packageAttributeItem != null)
{
JETValueItem packageValueItem = packageAttributeItem.getValueToken().getValueItem();
Item packageItem = new Item(signature + "~package", packageValueItem, "package");
packageItem.setParent(this);
rootItem = packageItem;
}
JETAttributeItem classAttributeItem = jetDirectiveItem.getAttribute("class");
if (classAttributeItem != null)
{
JETValueItem classValueItem = classAttributeItem.getValueToken().getValueItem();
Item classItem = new Item(rootItem.getSignature() + "~class", classValueItem, "class");
classItem.setParent(rootItem);
rootItem = classItem;
}
JETAttributeItem importsAttribute = jetDirectiveItem.getAttribute("imports");
if (importsAttribute != null)
{
for (JETValueElementItem jetImportItem : importsAttribute.getValueToken().getValueItem().getElements())
{
String importValue = jetImportItem.getValue();
Item importItem = new Item(rootItem.getSignature() + importValue + "~import", jetImportItem, "import");
importItem.setParent(rootItem);
}
}
JETAttributeItem skeletonAttribute = jetDirectiveItem.getAttribute("skeleton");
if (skeletonAttribute != null)
{
JETValueItem skeletonValueItem = skeletonAttribute.getValueToken().getValueItem();
Item skeletonItem = new Item(signature + "~skeleton", skeletonValueItem, "skeleton");
skeletonItem.setParent(this);
}
JETAttributeItem nlString = jetDirectiveItem.getAttribute("nlString");
if (nlString != null)
{
JETValueItem nlStringValue = nlString.getValueToken().getValueItem();
Item skeletonItem = new Item(signature + "~nlstring", nlStringValue, "nlstring");
skeletonItem.setParent(this);
}
}
}
protected void setJetItem(JETItem jetItem)
{
this.jetItem = jetItem;
}
public Item getParent()
{
return parent;
}
protected void setParent(Item parent)
{
if (this.parent != null)
{
this.parent.children.remove(this);
}
this.parent = parent;
if (parent != null)
{
parent.children.add(this);
}
}
public String getSignature()
{
return signature;
}
public JETItem getJETItem()
{
return jetItem;
}
public Image getImage()
{
return ALL_IMAGES.get(problemSeverity).get(type);
}
public List<Item> getChildren()
{
return children;
}
public StyledString getStyledText()
{
if ("jet".equals(type))
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetItem;
JETSkeleton skeleton = (JETSkeleton)jetDirectiveItem.getData(JETDirectiveItem.SKELETON);
String className = skeleton.getClassName();
String packageName = skeleton.getPackageName();
StyledString result = new StyledString(className);
if (packageName.length() != 0)
{
result.append(" - " + packageName, StyledString.DECORATIONS_STYLER);
}
if (Boolean.TRUE.equals(jetDirectiveItem.getData(JETDirectiveItem.DUPLICATE_JET_DIRECTIVE)))
{
result.setStyle(0, result.length(), STRIKE_OUT_STYLER);
}
return result;
}
else if ("include".equals(type))
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetItem;
boolean resolvedIncludeSuccess = Boolean.TRUE.equals(jetDirectiveItem.getData(JETDirectiveItem.RESOLVED_INCLUDE_SUCCESS));
return new StyledString(
jetDirectiveItem.getAttribute("file").getValueToken().getValueItem().getText(),
resolvedIncludeSuccess
? jetDirectiveItem.isSkipped() ? STRIKE_OUT_STYLER : getFontStyler(SWT.BOLD) : getChildren().isEmpty() ? STRIKE_OUT_STYLER : getFontStyler(SWT.ITALIC));
}
else if ("content".equals(type) || "root".equals(type) || "orphan".equals(type))
{
if (jetItem == null && !"orphan".equals(type))
{
return new StyledString("Analyzing...");
}
else
{
JETMark start = jetItem == null ? null : jetItem.getStart();
URI uri = URI.createURI(start == null ? signature.substring(0, signature.lastIndexOf("~orphan")) : start.getResolvedURI());
String fileName = uri.lastSegment();
StyledString result = new StyledString(fileName);
URI baseURI = uri.trimSegments(1);
String relativeLocation = baseURI.isPlatformResource() ? baseURI.toPlatformString(true) : baseURI.toString();
if (start != null)
{
while (start.getParentMark() != null)
{
start = start.getParentMark();
}
}
URI rootURI = URI.createURI(start == null ? parent.getChildren().get(0).jetItem.getStart().getResolvedURI() : start.getResolvedURI());
if (rootURI.isPlatformResource() && uri.isPlatformResource())
{
URI deresolvedURI = uri.deresolve(rootURI, true, true, false);
if (deresolvedURI.segmentCount() > 1 && !"..".equals(deresolvedURI.segment(0)))
{
relativeLocation = deresolvedURI.trimSegments(1).toString();
}
}
result.append(" - " + relativeLocation, StyledString.DECORATIONS_STYLER);
if ("content".equals(type) && ((JETDirectiveItem)parent.jetItem).isSkipped() || "orphan".equals(type))
{
result.setStyle(0, result.length(), STRIKE_OUT_STYLER);
}
return result;
}
}
else if ("top".equals(type))
{
return new StyledString("top");
}
else if ("start".equals(type) || "end".equals(type))
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetItem;
return new StyledString(jetItem.getText(), jetDirectiveItem.isSkipped() ? STRIKE_OUT_STYLER : null);
}
else if ("comment".equals(type))
{
return new StyledString(signature.substring(0, signature.lastIndexOf("~comment")));
}
if (jetItem instanceof JETValueItem)
{
return new StyledString(((JETValueItem)jetItem).getValue());
}
if (jetItem instanceof JETValueElementItem)
{
return new StyledString(((JETValueElementItem)jetItem).getValue());
}
return new StyledString(jetItem == null ? "" : jetItem.getText());
}
private static String getDirectiveType(JETItem jetItem)
{
if (jetItem instanceof JETDirectiveItem)
{
return ((JETDirectiveItem)jetItem).getNameItem().getText();
}
else
{
return null;
}
}
}
}
static class ViewPortHandler implements IViewportListener, Runnable
{
private final JETEditor jetEditor;
private final StyledText jetStyledText;
private int topIndex;
public ViewPortHandler(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
jetSourceViewer.addViewportListener(this);
jetStyledText = jetSourceViewer.getTextWidget();
}
public void viewportChanged(int verticalOffset)
{
topIndex = jetStyledText.getTopIndex();
jetStyledText.getDisplay().timerExec(200, this);
}
public void run()
{
if (!jetStyledText.isDisposed() && topIndex == jetStyledText.getTopIndex())
{
jetEditor.invalidateVisibleTextPresentation(false);
}
}
}
static class JavaHyperLink implements IHyperlink
{
private final JETEditor jetEditor;
private final IRegion region;
private final IHyperlink javaHyperlink;
public JavaHyperLink(JETEditor jetEditor, IRegion region, IHyperlink javaHyperlink)
{
this.jetEditor = jetEditor;
this.region = region;
this.javaHyperlink = javaHyperlink;
}
public IRegion getHyperlinkRegion()
{
return region;
}
public String getTypeLabel()
{
return javaHyperlink.getTypeLabel();
}
public String getHyperlinkText()
{
return javaHyperlink.getHyperlinkText();
}
public void open()
{
jetEditor.markInNavigationHistory();
javaHyperlink.open();
}
}
static class JETHyperLink implements IHyperlink
{
private final IRegion region;
private JETEditor jetEditor;
private final int fileID;
private final String locationURI;
public JETHyperLink(JETEditor jetEditor, IRegion region, int fileID, String locationURI)
{
this.jetEditor = jetEditor;
this.region = region;
this.fileID = fileID;
this.locationURI = locationURI;
}
public IRegion getHyperlinkRegion()
{
return region;
}
public String getTypeLabel()
{
return "Open";
}
public String getHyperlinkText()
{
URI uri = URI.createURI(locationURI);
return "Open JET " + (uri.isPlatformResource() ? uri.toPlatformString(true) : uri.toString());
}
public void open()
{
jetEditor.markInNavigationHistory();
if (fileID == -1)
{
JETEditor.open(jetEditor.getEditorSite(), locationURI);
}
else
{
jetEditor.getDocumentManager().setFileID(fileID);
Position correspondingTemplatePoint = jetEditor.getCorrespondingTemplatePosition(region.getOffset(), region.getLength());
if (correspondingTemplatePoint != null)
{
jetEditor.selectAndReveal(correspondingTemplatePoint.offset, correspondingTemplatePoint.length);
}
else
{
jetEditor.markInNavigationHistory();
}
}
}
}
static class JETNavigationHyperLink implements IHyperlink
{
protected final JETEditor jetEditor;
private final IRegion region;
protected final IRegion targetRegion;
public JETNavigationHyperLink(JETEditor jetEditor, IRegion region, IRegion targetRegion)
{
this.jetEditor = jetEditor;
this.region = region;
this.targetRegion = targetRegion;
}
public IRegion getHyperlinkRegion()
{
return region;
}
public String getTypeLabel()
{
return "Navigate";
}
public String getHyperlinkText()
{
return "Navigate in Template";
}
public void open()
{
jetEditor.markInNavigationHistory();
jetEditor.selectAndReveal(targetRegion.getOffset(), targetRegion.getLength());
}
}
static class SelectionSynchronizer
{
private final JETEditor jetEditor;
private final JavaEditor javaEditor;
private final ISourceViewer jetUnderlyingSourceViewer;
private final ISourceViewer javaUnderlyingSourceViewer;
private CaretAndSelectionListener jetToJava;
private CaretAndSelectionListener javaToJET;
public SelectionSynchronizer(JETEditor jetEditor, final JavaEditor javaEditor)
{
this.jetEditor = jetEditor;
this.javaEditor = javaEditor;
this.jetUnderlyingSourceViewer = jetEditor.getSourceViewer();
this.javaUnderlyingSourceViewer = javaEditor.getJavaSourceViewer();
jetToJava = new CaretAndSelectionListener(jetUnderlyingSourceViewer, javaUnderlyingSourceViewer);
javaToJET = new CaretAndSelectionListener(javaUnderlyingSourceViewer, jetUnderlyingSourceViewer);
}
public void sync(ISourceViewer viewer)
{
(viewer == jetUnderlyingSourceViewer ? jetToJava : javaToJET).handle();
}
class CaretAndSelectionListener implements CaretListener, SelectionListener
{
private final ISourceViewer source;
private final ISourceViewer target;
public CaretAndSelectionListener(ISourceViewer source, ISourceViewer target)
{
this.source = source;
this.target = target;
StyledText textWidget = source.getTextWidget();
textWidget.addCaretListener(this);
textWidget.addSelectionListener(this);
}
public void widgetSelected(SelectionEvent event)
{
if (isEnabled(event))
{
if (event.widget == javaUnderlyingSourceViewer.getTextWidget() && javaEditor.isNavigating())
{
Point javaSelectedRange = source.getSelectedRange();
int javaOffset = javaSelectedRange.x;
int correspondingTemplateFileID = jetEditor.getCorrespondingTemplateFileID(javaOffset);
if (correspondingTemplateFileID != -1 && correspondingTemplateFileID != jetEditor.getFileID())
{
jetEditor.getDocumentManager().setFileID(correspondingTemplateFileID);
}
}
handle();
}
}
public void widgetDefaultSelected(SelectionEvent event)
{
if (isEnabled(event))
{
handle();
}
}
public void caretMoved(CaretEvent event)
{
if (isEnabled(event))
{
// A caret move event doesn't generate a selection event if the selection was empty and is also now empty.
// Furthermore, the queried selection range is stale during the notification, so we must post an event check the range again.
final StyledText styledText = (StyledText)event.widget;
if (styledText.getSelectionRange().y == 0)
{
event.widget.getDisplay().asyncExec(new Runnable()
{
public void run()
{
// If the range is still empty, we need to generate a notification so that the cursors can stay in sync.
Point selection = styledText.getSelectionRange();
if (selection.y == 0)
{
Event fakeEvent = new Event();
fakeEvent.x = fakeEvent.y = selection.x;
styledText.notifyListeners(SWT.Selection, fakeEvent);
}
}
});
}
}
}
protected boolean isEnabled(TypedEvent event)
{
if (((Control)event.widget).isFocusControl())
{
// Don't synchronize anything if the document contents are out of sync with the Java contents.
return jetEditor.isJavaEditorInSync();
}
else
{
return event.widget == javaUnderlyingSourceViewer.getTextWidget() && javaEditor.isNavigating();
}
}
protected void handle()
{
Point selectedRange = source.getSelectedRange();
if (source == jetUnderlyingSourceViewer)
{
JETItem startItem = jetEditor.getJETItem(selectedRange.x, false);
JETItem endItem = jetEditor.getJETItem(selectedRange.x + selectedRange.y, false);
TrackedPosition jetPosition = jetEditor.getJETPosition();
if (startItem == endItem && startItem instanceof JETJavaItem && !(startItem instanceof JETLiteralItem))
{
JETJavaItem jetJavaItem = (JETJavaItem)startItem;
jetPosition.update(jetJavaItem);
jetEditor.getJavaPosition().update(jetJavaItem);
}
else
{
int start = startItem == null ? selectedRange.x : startItem.getStartOffset();
int end = endItem == null ? startItem == null ? selectedRange.x + selectedRange.y : startItem.getStopOffset() : endItem.getStopOffset();
int length = end - start;
if (start != 0 && startItem instanceof JETLiteralItem)
{
JETToken token = jetEditor.getTokenAt(start - 1);
if (token == JETDirectiveRule.TOKEN || token == JETCommentRule.TOKEN || token == JETScriptletRule.TOKEN)
{
// These items all consume the line delimiter that immediately follows.
IDocument document = jetUnderlyingSourceViewer.getDocument();
try
{
char character = document.getChar(start);
if (character == '\n' || character == '\r')
{
++start;
--length;
if (character == '\r' && document.getChar(start) == '\n')
{
++start;
--length;
}
}
}
catch (BadLocationException exception)
{
}
}
}
if (endItem instanceof JETLiteralItem)
{
// Always exclude the final line delimiter.
IDocument document = jetUnderlyingSourceViewer.getDocument();
try
{
char character = document.getChar(start + length);
if (character == '\n' || character == '\r')
{
--length;
if (character == '\n' && document.getChar(start) == '\r')
{
--length;
}
}
}
catch (BadLocationException exception)
{
}
}
jetPosition.update(start, length);
}
jetUnderlyingSourceViewer.setRangeIndication(jetPosition.getOffset(), jetPosition.getLength(), false);
}
Position correspondingPoint = source == jetUnderlyingSourceViewer
? jetEditor.getCorrespondingJavaPosition(selectedRange.x, selectedRange.y) : jetEditor.getCorrespondingTemplatePosition(selectedRange.x, selectedRange.y);
if (correspondingPoint != null)
{
Position correspondingPointEnd = null;
for (int i = 0; i < 100 && correspondingPointEnd == null && selectedRange.y > 0; ++i, --selectedRange.y)
{
int endOffset = selectedRange.x + selectedRange.y;
correspondingPointEnd = source == jetUnderlyingSourceViewer
? jetEditor.getCorrespondingJavaPosition(endOffset, 0) : jetEditor.getCorrespondingTemplatePosition(endOffset, 0);
}
int length = correspondingPointEnd == null ? correspondingPoint.length : correspondingPointEnd.offset + correspondingPointEnd.length - correspondingPoint.offset;
(target == jetUnderlyingSourceViewer ? jetEditor : javaEditor).selectAndReveal(correspondingPoint.offset, length);
StyledText textWidget = target.getTextWidget();
Rectangle bounds = textWidget.getCaret().getBounds();
textWidget.redraw(bounds.x, bounds.y, bounds.width, bounds.height, false);
}
}
}
}
@SuppressWarnings("restriction")
static class DelegatingTextHover implements IJavaEditorTextHover, ITextHoverExtension, ITextHoverExtension2
{
private final org.eclipse.jdt.internal.ui.text.java.hover.JavadocHover javadocHover = new org.eclipse.jdt.internal.ui.text.java.hover.JavadocHover();
private final JETEditor jetEditor;
private DefaultTextHover defaultTextHover;
private ISourceViewer javaTextViewer;
public DelegatingTextHover(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
public void setEditor(IEditorPart editor)
{
javadocHover.setEditor(editor);
javaTextViewer = ((JavaEditor)editor).getJavaSourceViewer();
defaultTextHover = new DefaultTextHover(jetEditor.getSourceViewer());
}
public IRegion getHoverRegion(ITextViewer textViewer, int offset)
{
return defaultTextHover.getHoverRegion(textViewer, offset);
}
@SuppressWarnings("deprecation")
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion)
{
IRegion javaRegion = toJava(hoverRegion);
return javaRegion == null ? defaultTextHover.getHoverInfo(textViewer, hoverRegion) : javadocHover.getHoverInfo(javaTextViewer, javaRegion);
}
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion)
{
IRegion javaRegion = toJava(hoverRegion);
return javaRegion == null ? null : javadocHover.getHoverInfo2(javaTextViewer, javaRegion);
}
public IInformationControlCreator getHoverControlCreator()
{
return javadocHover.getHoverControlCreator();
}
private IRegion toJava(IRegion templateRegion)
{
Position correspondingJavaPoint = jetEditor.getCorrespondingJavaPosition(templateRegion.getOffset(), templateRegion.getLength());
if (correspondingJavaPoint != null)
{
return new Region(correspondingJavaPoint.getOffset(), correspondingJavaPoint.getLength());
}
return null;
}
}
static class CompletionProposalDelegate
implements
ICompletionProposal,
ICompletionProposalExtension2,
ICompletionProposalExtension3,
ICompletionProposalExtension4,
ICompletionProposalExtension5,
ICompletionProposalExtension6
{
private final JETEditor jetEditor;
private final ICompletionProposal delegate;
private final ITextViewer delegateViewer;
final IDocument delegateDocument;
final TrackedPosition javaPosition;
final TrackedPosition jetPosition;
public CompletionProposalDelegate(ICompletionProposal delelgate, JETEditor jetEditor)
{
this.delegate = delelgate;
this.jetEditor = jetEditor;
this.delegateViewer = jetEditor.getJavaSourceViewer();
this.delegateDocument = delegateViewer.getDocument();
this.jetPosition = jetEditor.getJETPosition();
this.javaPosition = jetEditor.getJavaPosition();
}
public void apply(IDocument document)
{
JavaDocumentTransaction javaDocumentTransaction = new CompletionTransaction(jetEditor);
javaDocumentTransaction.modify(delegateDocument, new SneakyRunnable()
{
@Override
public void execute() throws Exception
{
Method performChangeMethod = null;
// We do this ugliness because directly applying the proposal will often want to open the Java editor and we definitely don't want that.
for (Class<?> delegateClass = delegate.getClass(); delegateClass != null; delegateClass = delegateClass.getSuperclass())
{
try
{
performChangeMethod = delegateClass.getDeclaredMethod("performChange", IEditorPart.class, IDocument.class);
performChangeMethod.setAccessible(true);
break;
}
catch (Exception exception)
{
}
}
if (performChangeMethod != null)
{
performChangeMethod.invoke(delegate, jetEditor.getJavaEditor(), delegateDocument);
}
else
{
delegate.apply(delegateDocument);
}
}
});
jetEditor.openDialog("Proposal Failed", javaDocumentTransaction.getStatus());
}
public void apply(ITextViewer viewer, final char trigger, final int stateMask, int offset)
{
if (delegate instanceof ICompletionProposalExtension2)
{
JavaDocumentTransaction javaDocumentTransaction = new CompletionTransaction(jetEditor);
javaDocumentTransaction.modify(delegateDocument, new Runnable()
{
public void run()
{
((ICompletionProposalExtension2)delegate).apply(delegateViewer, trigger, stateMask, delegateViewer.getSelectedRange().x);
}
});
jetEditor.openDialog("Proposal Failed", javaDocumentTransaction.getStatus());
}
else
{
apply(delegateDocument);
}
}
public Point getSelection(IDocument document)
{
return null;
}
public String getAdditionalProposalInfo()
{
return delegate.getAdditionalProposalInfo();
}
public String getDisplayString()
{
return delegate.getDisplayString();
}
public Image getImage()
{
return delegate.getImage();
}
public IContextInformation getContextInformation()
{
return delegate.getContextInformation();
}
public StyledString getStyledDisplayString()
{
return delegate instanceof ICompletionProposalExtension6 ? ((ICompletionProposalExtension6)delegate).getStyledDisplayString() : new StyledString(getDisplayString());
}
public Object getAdditionalProposalInfo(IProgressMonitor monitor)
{
return delegate instanceof ICompletionProposalExtension5 ? ((ICompletionProposalExtension5)delegate).getAdditionalProposalInfo(monitor) : null;
}
public boolean isAutoInsertable()
{
return delegate instanceof ICompletionProposalExtension4 && ((ICompletionProposalExtension4)delegate).isAutoInsertable();
}
public IInformationControlCreator getInformationControlCreator()
{
return delegate instanceof ICompletionProposalExtension3 ? ((ICompletionProposalExtension3)delegate).getInformationControlCreator() : null;
}
private int jetToJava(int templateOffset)
{
return javaPosition.getOffset() + templateOffset - jetPosition.getOffset();
}
public CharSequence getPrefixCompletionText(IDocument document, int completionOffset)
{
return delegate instanceof ICompletionProposalExtension3
? ((ICompletionProposalExtension3)delegate).getPrefixCompletionText(delegateDocument, jetToJava(completionOffset)) : null;
}
public int getPrefixCompletionStart(IDocument document, int completionOffset)
{
return delegate instanceof ICompletionProposalExtension3
? ((ICompletionProposalExtension3)delegate).getPrefixCompletionStart(delegateDocument, jetToJava(completionOffset)) : null;
}
public void selected(ITextViewer viewer, boolean smartToggle)
{
if (delegate instanceof ICompletionProposalExtension2)
{
((ICompletionProposalExtension2)delegate).selected(delegateViewer, smartToggle);
}
}
public void unselected(ITextViewer viewer)
{
if (delegate instanceof ICompletionProposalExtension2)
{
((ICompletionProposalExtension2)delegate).unselected(delegateViewer);
}
}
public boolean validate(IDocument document, int offset, DocumentEvent event)
{
return delegate instanceof ICompletionProposalExtension2 && ((ICompletionProposalExtension2)delegate).validate(delegateDocument, jetToJava(offset), event);
}
class CompletionTransaction extends JavaDocumentTransaction
{
public CompletionTransaction(JETEditor jetEditor)
{
super(jetEditor, Collections.singletonList(jetEditor.getJETPosition()), true, false);
}
@Override
protected void postCommit(List<TrackedPosition> jetPositions)
{
Point finalJavaSelectionRange = delegate.getSelection(delegateDocument);
if (finalJavaSelectionRange != null)
{
int offset = finalJavaSelectionRange.x - javaPosition.getOffset();
if (offset > 0)
{
jetEditor.getSourceViewer().setSelectedRange(jetPosition.getOffset() + offset, finalJavaSelectionRange.y);
}
}
// Ensure that pop-up in Java view, if any, is dismissed.
Event event = new Event();
event.character = SWT.ESC;
event.keyCode = SWT.ESC;
jetEditor.getJavaSourceViewer().getTextWidget().notifyListeners(SWT.KeyDown, event);
}
}
}
static class JavaDocumentTransaction implements IDocumentListener
{
private static final Pattern IMPORT_PATTERN = Pattern.compile("import ([^;]+);");
protected final JETEditor jetEditor;
protected final List<TrackedPosition> jetPositions;
private final boolean transformBraces;
private final boolean ignoreOutOfScopeChanges;
public JavaDocumentTransaction(JETEditor jetEditor, List<TrackedPosition> jetPositions, boolean transformBraces, boolean ignoreOutOfScopeChanges)
{
this.jetEditor = jetEditor;
this.jetPositions = jetPositions;
this.transformBraces = transformBraces;
this.ignoreOutOfScopeChanges = ignoreOutOfScopeChanges;
}
public void modify(IDocument document, Runnable javaModifier)
{
start();
jetEditor.getDocumentManager().setEnableJavaSynchronization(false);
document.addDocumentListener(this);
try
{
javaModifier.run();
if (status == null)
{
commit(document);
}
}
catch (Exception exception)
{
status = CodeGenUIPlugin.toStatus(IStatus.ERROR, exception);
}
finally
{
document.removeDocumentListener(this);
jetEditor.getDocumentManager().setEnableJavaSynchronization(true);
stop();
}
}
protected void startDocumentRewriteSession(ISourceViewer sourceViewer, DocumentRewriteSessionType type, boolean rememberSelection)
{
if (rememberSelection)
{
try
{
Method rememberSelectionMethod = SourceViewer.class.getDeclaredMethod("rememberSelection");
rememberSelectionMethod.setAccessible(true);
rememberSelectionMethod.invoke(sourceViewer);
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
((IDocumentExtension4)sourceViewer.getDocument()).startRewriteSession(type);
}
protected void stopDocumentRewriteSession(ISourceViewer sourceViewer, boolean restoreSelection)
{
IDocumentExtension4 extension = (IDocumentExtension4)sourceViewer.getDocument();
extension.stopRewriteSession(extension.getActiveRewriteSession());
if (restoreSelection)
{
try
{
Method rememberSelectionMethod = SourceViewer.class.getDeclaredMethod("restoreSelection");
rememberSelectionMethod.setAccessible(true);
rememberSelectionMethod.invoke(sourceViewer);
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
}
protected void start()
{
}
protected void stop()
{
}
private List<String> imports = new ArrayList<String>();
private IStatus status;
public IStatus getStatus()
{
return status == null ? Status.OK_STATUS : status;
}
public void documentAboutToBeChanged(DocumentEvent event)
{
}
public void documentChanged(DocumentEvent event)
{
if (status == null)
{
for (TrackedPosition jetPosition : jetPositions)
{
TrackedPosition javaPosition = jetPosition.getOpposite();
if (javaPosition.overlapsWith(event.getOffset(), event.getLength()))
{
return;
}
}
String replacement = event.getText();
Matcher matcher = IMPORT_PATTERN.matcher(replacement);
if (matcher.matches())
{
String newImport = matcher.group(1);
imports.add(newImport);
}
else if (!ignoreOutOfScopeChanges && replacement.trim().length() != 0)
{
status = new Status(IStatus.ERROR, CodeGenUIPlugin.getPlugin().getBundle().getSymbolicName(), "Changes outside the scope of the current document occurred.");
}
}
}
protected void commit(IDocument delegateDocument) throws Exception
{
SourceViewer jetSourceViewer = jetEditor.getJETSourceViewer();
IUndoManager undoManager = jetSourceViewer.getUndoManager();
undoManager.beginCompoundChange();
try
{
MultiTextEdit textEdit = new MultiTextEdit();
for (TrackedPosition jetPosition : jetPositions)
{
TrackedPosition javaPosition = jetPosition.getOpposite();
if (!javaPosition.isDeleted())
{
String finalJavaText = javaPosition.getText();
String originalTemplateJavaText = jetPosition.getText();
if (!originalTemplateJavaText.equals(finalJavaText))
{
int orginalTemplateJavaTextLength = jetPosition.getLength();
int finalJavaTextLength = javaPosition.getLength();
int start = 0;
while (start < finalJavaTextLength && start < orginalTemplateJavaTextLength && finalJavaText.charAt(start) == originalTemplateJavaText.charAt(start))
{
++start;
}
if (start != orginalTemplateJavaTextLength - 1 || orginalTemplateJavaTextLength != finalJavaTextLength)
{
int end = 0;
while (finalJavaTextLength - end > 0 && orginalTemplateJavaTextLength - end > 0
&& finalJavaText.charAt(finalJavaTextLength - end - 1) == originalTemplateJavaText.charAt(orginalTemplateJavaTextLength - end - 1))
{
++end;
}
int replacementOffset = jetPosition.getOffset() + start;
int replacementLength = orginalTemplateJavaTextLength - end - start;
while (replacementLength < 0)
{
// The replacement length could be negative because the tail end of the actual Java replacement text could exactly match the text in the original string.
// And that part will have been trimmed from the replacement text we've computed for application to the template.
++replacementLength;
--end;
}
int finalJavaTextEnd = finalJavaTextLength - end;
String replacementText = finalJavaTextEnd < start ? "" : handleReplacement(finalJavaText.substring(start, finalJavaTextEnd));
ReplaceEdit replaceEdit = new ReplaceEdit(replacementOffset, replacementLength, replacementText);
textEdit.addChild(replaceEdit);
}
}
}
}
int jetDirectiveFileID = -1;
int importsOffset = -1;
boolean needsImportsAttribute = false;
StringBuilder newImports = new StringBuilder();
if (!imports.isEmpty())
{
JETDirectiveItem jetJETDirectiveItem = jetEditor.getCompilationUnit().getJETJETDirectiveItem();
jetDirectiveFileID = jetJETDirectiveItem.getFileID();
JETAttributeItem imports = jetJETDirectiveItem.getAttribute("imports");
for (String newImport : this.imports)
{
if (imports == null)
{
importsOffset = jetJETDirectiveItem.getAttributes().getStopOffset();
needsImportsAttribute = true;
if (newImports.length() != 0)
{
newImports.append(' ');
}
}
else
{
JETTokenItem importValue = imports.getValueToken();
if (importsOffset == -1)
{
JETValueItem valueItem = importValue.getValueItem();
importsOffset = valueItem.getStopOffset();
if (!valueItem.getElements().isEmpty())
{
newImports.append(' ');
}
}
else
{
newImports.append(' ');
}
}
newImports.append(newImport);
}
}
if (importsOffset != -1)
{
String insertion = needsImportsAttribute ? " imports=\"" + newImports + "\"" : newImports.toString();
ReplaceEdit insertImportsEdit = new ReplaceEdit(importsOffset, 0, insertion);
if (jetDirectiveFileID != jetEditor.getFileID())
{
IDocument jetDirectiveDocument = jetEditor.getDocumentManager().getDocument(jetDirectiveFileID);
if (jetDirectiveDocument != null)
{
try
{
insertImportsEdit.apply(jetDirectiveDocument);
}
catch (Exception exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
}
else
{
textEdit.addChild(insertImportsEdit);
}
}
try
{
TextEdit[] children = textEdit.getChildren();
if (children.length > 0)
{
startDocumentRewriteSession(jetSourceViewer, children.length > 50 ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL, false);
IDocument document = jetSourceViewer.getDocument();
textEdit.apply(document);
}
postCommit(jetPositions);
}
finally
{
stopDocumentRewriteSession(jetSourceViewer, false);
}
}
finally
{
undoManager.endCompoundChange();
}
}
private static Pattern BRACE_COLLAPSE_PATTERN = Pattern.compile("\\s\\s+\\{");
private static Pattern TAB_REPLACEMENT_PATTERN = Pattern.compile("\t");
private static Pattern INDENT_FIX_PATTERN_ = Pattern.compile("(\r?\n) ");
protected String handleReplacement(String replacement)
{
if (transformBraces)
{
String result = BRACE_COLLAPSE_PATTERN.matcher(replacement).replaceAll(" {");
result = TAB_REPLACEMENT_PATTERN.matcher(result).replaceAll(" ");
result = INDENT_FIX_PATTERN_.matcher(result).replaceAll("$1");
return result;
}
return replacement;
}
protected void postCommit(List<TrackedPosition> jetPositions)
{
}
}
static class DelegatingContentAssistProcessor implements IContentAssistProcessor
{
private static final Pattern IGNORED_PROPOSAL_PATTERN = Pattern.compile("^(((TEXT)?_([0-9]+))|nl|(NL(_[0-9]+)?)) : String");
private final JETEditor jetEditor;
private final JETContentAssistProcessor jetContentAssistProcessor;
private IContentAssistProcessor javaContentAssistProcessor;
private IContentAssistProcessor delegate;
public DelegatingContentAssistProcessor(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
jetContentAssistProcessor = new JETContentAssistProcessor(jetEditor);
}
protected IContentAssistProcessor getJavaAssistProcessor()
{
if (javaContentAssistProcessor == null)
{
IContentAssistant contentAssist = jetEditor.getJavaEditor().getContentAssist();
javaContentAssistProcessor = contentAssist.getContentAssistProcessor(IDocument.DEFAULT_CONTENT_TYPE);
}
return javaContentAssistProcessor;
}
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset)
{
final JETToken token = jetEditor.getTokenAt(offset);
if (token == JETContentRule.TOKEN || token == JETTrailingWhitespaceContentRule.TOKEN || token == JETDirectiveRule.TOKEN || token == null)
{
delegate = jetContentAssistProcessor;
return jetContentAssistProcessor.computeCompletionProposals(viewer, offset);
}
else if (token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN)
{
delegate = getJavaAssistProcessor();
final ISourceViewer javaSourceViewer = jetEditor.getJavaEditor().getJavaSourceViewer();
final Point javaSelectionRange = javaSourceViewer.getSelectedRange();
final int javaCaretOffset = javaSelectionRange.x + javaSelectionRange.y;
ICompletionProposal[] proposals = delegate.computeCompletionProposals(javaSourceViewer, javaCaretOffset);
List<ICompletionProposal> filteredProposals = new ArrayList<ICompletionProposal>();
Set<String> duplicates = new HashSet<String>();
for (final ICompletionProposal completionProposal : proposals)
{
String displayString = completionProposal.getDisplayString();
if (duplicates.add(displayString) && !IGNORED_PROPOSAL_PATTERN.matcher(displayString).find())
{
filteredProposals.add(new CompletionProposalDelegate(completionProposal, jetEditor));
}
}
return filteredProposals.toArray(new ICompletionProposal [filteredProposals.size()]);
}
else
{
return null;
}
}
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset)
{
return null;
}
public char[] getCompletionProposalAutoActivationCharacters()
{
JETToken token = jetEditor.getTokenAtSelection(0);
return token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN ? getJavaAssistProcessor().getCompletionProposalAutoActivationCharacters() : null;
}
public char[] getContextInformationAutoActivationCharacters()
{
JETToken token = jetEditor.getTokenAtSelection(0);
return token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN ? getJavaAssistProcessor().getContextInformationAutoActivationCharacters() : null;
}
public String getErrorMessage()
{
return delegate != null ? delegate.getErrorMessage() : null;
}
public IContextInformationValidator getContextInformationValidator()
{
return null;
}
}
static class DelegatingQuickAssistProcessor implements IQuickAssistProcessor
{
private JETEditor jetEditor;
public DelegatingQuickAssistProcessor(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
@SuppressWarnings("restriction")
protected IQuickAssistProcessor getJavaAssistProcessor(IQuickAssistInvocationContext invocationContext)
{
JavaEditor javaEditor = jetEditor.getJavaEditor();
IQuickAssistAssistant quickAssistAssistant = javaEditor.getQuickAssistAssistant();
if (invocationContext != null)
{
try
{
ArrayList<Annotation> resultingAnnotations = new ArrayList<Annotation>();
org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionAssistant.collectQuickFixableAnnotations(
javaEditor,
invocationContext.getOffset(),
invocationContext.getLength() != 0,
resultingAnnotations);
Field fCurrentAnnotationsField = quickAssistAssistant.getClass().getDeclaredField("fCurrentAnnotations");
fCurrentAnnotationsField.setAccessible(true);
fCurrentAnnotationsField.set(quickAssistAssistant, resultingAnnotations.toArray(new Annotation [resultingAnnotations.size()]));
}
catch (Exception exception)
{
}
}
return quickAssistAssistant.getQuickAssistProcessor();
}
protected IQuickAssistInvocationContext getJavaInvocationContext(IQuickAssistInvocationContext invocationContext)
{
final JETToken token = jetEditor.getTokenAt(invocationContext.getOffset());
if (token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN)
{
final ISourceViewer javaSourceViewer = jetEditor.getJavaEditor().getJavaSourceViewer();
final Point javaSelectionRange = javaSourceViewer.getSelectedRange();
return new TextInvocationContext(javaSourceViewer, javaSelectionRange.x, javaSelectionRange.y);
}
else
{
return null;
}
}
public boolean canAssist(IQuickAssistInvocationContext invocationContext)
{
IQuickAssistInvocationContext javaInvocationContext = getJavaInvocationContext(invocationContext);
return javaInvocationContext != null && getJavaAssistProcessor(javaInvocationContext).canAssist(javaInvocationContext);
}
public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext)
{
IQuickAssistInvocationContext javaInvocationContext = getJavaInvocationContext(invocationContext);
if (javaInvocationContext != null)
{
ICompletionProposal[] quickAssistProposals = getJavaAssistProcessor(javaInvocationContext).computeQuickAssistProposals(javaInvocationContext);
if (quickAssistProposals != null)
{
List<ICompletionProposal> delegatingProposals = new ArrayList<ICompletionProposal>(quickAssistProposals.length);
for (ICompletionProposal completionProposal : quickAssistProposals)
{
delegatingProposals.add(new CompletionProposalDelegate(completionProposal, jetEditor));
}
return delegatingProposals.toArray(new ICompletionProposal [delegatingProposals.size()]);
}
}
return null;
}
public String getErrorMessage()
{
return getJavaAssistProcessor(null).getErrorMessage();
}
public boolean canFix(Annotation annotation)
{
return getJavaAssistProcessor(null).canFix(annotation);
}
}
static class JETContentAssistProcessor extends TemplateCompletionProcessor
{
private static final Map<String, JETTemplateContextType> JET_CONTEXT_TYPES = new HashMap<String, JETTemplateContextType>();
private static final Map<JETToken, JETTemplateContextType> JET_TOKEN_CONTEXT_TYPES = new HashMap<JETToken, JETTemplateContextType>();
private static Image JET_IMAGE = CodeGenUIPlugin.getPlugin().getActualImage("full/obj16/JET");
private final JETEditor jetEditor;
static
{
new JETContentContextType();
new JETDirectiveContextType();
}
public JETContentAssistProcessor(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
@Override
protected Template[] getTemplates(String contextTypeId)
{
JETTemplateContextType jetTemplateContextType = JET_CONTEXT_TYPES.get(contextTypeId);
return jetTemplateContextType == null ? null : jetTemplateContextType.getTemplates(jetEditor.getEditorInput());
}
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset)
{
try
{
return super.computeCompletionProposals(viewer, offset);
}
finally
{
for (JETTemplateContextType jetTemplateContextType : JET_CONTEXT_TYPES.values())
{
jetTemplateContextType.resetContext();
}
}
}
@Override
protected String extractPrefix(ITextViewer viewer, int offset)
{
return "";
}
@Override
protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region, int relevance)
{
return new JETTemplateProposal(template, context, region, getImage(template), relevance);
}
@Override
protected TemplateContextType getContextType(ITextViewer viewer, IRegion region)
{
JETTokenRegion tokenRegion = jetEditor.getTokenRegionAt(region.getOffset());
// If we are right at the start, even in an empty file, treat it like we are in content.
JETToken token = tokenRegion == null || tokenRegion.getOffset() == region.getOffset() ? JETContentRule.TOKEN : tokenRegion.getToken();
JETTemplateContextType jetTemplateContextType = JET_TOKEN_CONTEXT_TYPES.get(token.getBaseToken());
if (jetTemplateContextType != null)
{
jetTemplateContextType.setContext(jetEditor, region);
}
return jetTemplateContextType;
}
@Override
protected Image getImage(Template template)
{
return JET_IMAGE;
}
private static class JETTemplateProposal extends TemplateProposal implements ICompletionProposalExtension6
{
private StyledString displayString;
public JETTemplateProposal(Template template, TemplateContext context, IRegion region, Image image, int relevance)
{
super(template, context, region, image, relevance);
}
@Override
public String getDisplayString()
{
return getStyledDisplayString().toString();
}
public StyledString getStyledDisplayString()
{
if (displayString == null)
{
String name = getTemplate().getName();
String description = getTemplate().getDescription();
displayString = new StyledString(name, StyledString.COUNTER_STYLER);
displayString.append(" - ");
displayString.append(description, StyledString.QUALIFIER_STYLER);
}
return displayString;
}
}
static class JETTemplateContextType extends TemplateContextType
{
private JETEditor jetEditor;
private IRegion region;
public JETTemplateContextType(String id, JETToken token)
{
super(id);
JET_CONTEXT_TYPES.put(id, this);
JET_TOKEN_CONTEXT_TYPES.put(token, this);
}
public JETEditor getEditor()
{
return jetEditor;
}
public IRegion getRegion()
{
return region;
}
public void setContext(JETEditor jetEditor, IRegion region)
{
this.jetEditor = jetEditor;
this.region = region;
}
public void resetContext()
{
jetEditor = null;
region = null;
}
public Template[] getTemplates(IEditorInput input)
{
return null;
}
}
static class JETContentContextType extends JETTemplateContextType
{
private static String ID = "org.eclipse.code.ui.jet.content";
private static Pattern JET_DIRECTIVE_PATTERN = Pattern.compile("\\s*<%@\\s*jet\\s+.*%>", Pattern.DOTALL);
private static final Template JET_DIRECTIVE_TEMPLATE = new Template(
"<%@jet%>",
"@jet directive to minimally specify the Java class name",
ID,
"<%@jet package=\"${java_package_name}\" class=\"${java_class_name}\" imports=\"${java_imports}\"%>\n",
true);
private static final Template JET_SCRIPTLET_TEMPLATE = new Template("<%%>", "scriptlet for specifying Java statement logic", JETContentContextType.ID, "<%${}%>", true);
private static final Template JET_EXPRESSION_TEMPLATE = new Template("<%=%>", "expression for specifying Java expression logic", JETContentContextType.ID, "<%=${}%>", true);
private static final Template JET_SIMPLE_INCLUDE_TEMPLATE = new Template(
"<%@include%>",
"@include directive for including a 'jetinc' file",
ID,
"<%@include file=\"${file}\"%>",
true);
private static final Template JET_OPTIONAL_INCLUDE_TEMPLATE = new Template(
"<%@include fail=\"silent\"%>",
"@include directive for including a 'jetinc' file, ignoring when it doesn't exist",
ID,
"<%@include file=\"${file}\" fail=\"silent\"%>",
true);
private static final Template JET_ALTERNATIVE_INCLUDE_TEMPLATE = new Template(
"<%@include fail=\"alternative\"%>",
"@include directive for including a 'jetinc' file, using the @start/@end block when it doesn't exist",
ID,
"<%@include file=\"${file}\" fail=\"alternative\"%>\n<%@start%>\n${}<%@end%>\n",
true);
private static final Template JET_COPYRIGHT_COMMENT_TEMPLATE = new Template(
"<%--copyright--%>",
"a comment at the start of the file for specifying the copyright",
ID,
"<%--\nCopyright " + System.getProperty("user.name") + " " + Calendar.getInstance().get(Calendar.YEAR) + "\n--%>\n",
true);
private static final Template JET_COMMENT_TEMPLATE = new Template("<%--%>", "comment for specifying excluded content", JETContentContextType.ID, "<%-${}-%>", true);
private static final Template JET_COMMENT_TEMPLATE_WITH_TAG = new Template(
"<%-[]-%>",
"comment for specifying a tag in the content outline",
JETContentContextType.ID,
"<%-[${Tag}]-%>",
true);
public JETContentContextType()
{
super(ID, JETContentRule.TOKEN);
}
private Template convert(Template template, String lineDelimeter)
{
return new Template(
template.getName(),
template.getDescription(),
template.getContextTypeId(),
template.getPattern().replace("\n", lineDelimeter),
template.isAutoInsertable());
}
@Override
public Template[] getTemplates(IEditorInput input)
{
ITextViewer viewer = getEditor().getSourceViewer();
IDocument document = viewer.getDocument();
String lineDelimiter = TextUtilities.getDefaultLineDelimiter(document);
List<Template> result = new ArrayList<Template>();
if (viewer.getSelectedRange().x == 0)
{
result.add(convert(JET_COPYRIGHT_COMMENT_TEMPLATE, lineDelimiter));
}
boolean isJET = input == null || input.getName() == null || input.getName().endsWith("jet");
if (isJET)
{
try
{
IRegion lineInformation = document.getLineInformation(0);
String firstLine = document.get(lineInformation.getOffset(), lineInformation.getLength());
if (!JET_DIRECTIVE_PATTERN.matcher(firstLine).matches())
{
JETCompilationUnit compilationUnit = getEditor().getCompilationUnit();
if (compilationUnit == null || compilationUnit.getJETJETDirectiveItem() == null || compilationUnit.getJETJETDirectiveItem().getLength() == 0)
{
result.add(convert(JET_DIRECTIVE_TEMPLATE, lineDelimiter));
}
}
}
catch (BadLocationException exception)
{
}
}
result.add(convert(JET_SCRIPTLET_TEMPLATE, lineDelimiter));
result.add(convert(JET_EXPRESSION_TEMPLATE, lineDelimiter));
result.add(convert(JET_SIMPLE_INCLUDE_TEMPLATE, lineDelimiter));
result.add(convert(JET_OPTIONAL_INCLUDE_TEMPLATE, lineDelimiter));
result.add(convert(JET_ALTERNATIVE_INCLUDE_TEMPLATE, lineDelimiter));
result.add(convert(JET_COMMENT_TEMPLATE, lineDelimiter));
result.add(convert(JET_COMMENT_TEMPLATE_WITH_TAG, lineDelimiter));
return result.toArray(new Template [result.size()]);
}
}
private static class JETDirectiveContextType extends JETTemplateContextType
{
private static String ID = "org.eclipse.code.ui.jet.directive";
private static final Map<String, List<Template>> ATTRIBUTE_TEMPLATES = new HashMap<String, List<Template>>();
static
{
List<Template> jetTemplates = new ArrayList<Template>();
jetTemplates.add(new Template("class", "specify the Java class name of the class", ID, "class=\"${java_class_name}\"", false));
jetTemplates.add(new Template("package", "specify the Java package name of the class", ID, "package=\"${java_package_name}\"", false));
jetTemplates.add(new Template("imports", "specify the Java imports for the class", ID, "imports=\"${java_imports}\"", false));
jetTemplates.add(
new Template("builder", "specify the builder to be used in the generate method of the class", ID, "builder=\"StringBuilder ${builder} = new StringBuilder()\"", false));
jetTemplates.add(new Template("minimize", "whether to mimize the footprint of the literal constants of the class", ID, "minimize=\"${true}\"", false));
jetTemplates.add(
new Template("nlString", "specify the Java expression used to extract the default line delimiter of the class", ID, "nlString=\"${global_expression}\"", false));
jetTemplates.add(new Template("skeleton", "specify a Java class to be used as the skeleton of the class", ID, "skeleton=\"${skeleton_java_file}\"", false));
jetTemplates.add(new Template("version", "specify and arbtirary used version for the templates", ID, "version=\"${version}\"", false));
ATTRIBUTE_TEMPLATES.put("jet", jetTemplates);
List<Template> includeTemplates = new ArrayList<Template>();
includeTemplates.add(new Template("file", "specify file to include in the template", ID, "file=\"${file}\"", false));
includeTemplates.add(new Template("fail", "specify to ignore a missing file", ID, "fail=\"${silent}\"", false));
ATTRIBUTE_TEMPLATES.put("include", includeTemplates);
}
public JETDirectiveContextType()
{
super(ID, JETDirectiveRule.TOKEN);
}
private Template convert(Template template, String prefix, String suffix)
{
return new Template(template.getName(), template.getDescription(), template.getContextTypeId(), prefix + template.getPattern() + suffix, template.isAutoInsertable());
}
@Override
public Template[] getTemplates(IEditorInput input)
{
JETEditor jetEditor = getEditor();
// Ignore the prefix.
IRegion region = getRegion();
int offset = region.getOffset() + region.getLength();
JETTokenRegion tokenRegion = jetEditor.getTokenRegionAt(offset);
try
{
List<Template> result = new ArrayList<Template>();
int tokenRegionOffset = tokenRegion.getOffset();
int tokenRegionLength = tokenRegion.getLength();
String directive = jetEditor.getSourceViewer().getDocument().get(tokenRegionOffset, tokenRegionLength);
JETDirectiveItem jetDirectiveItem = JETParser.parseDirective(directive);
JETAttributeListItem attributes = jetDirectiveItem.getAttributes();
int relativeOffset = offset - tokenRegionOffset;
JETItem nameItem = jetDirectiveItem.getNameItem();
String directiveName = nameItem.getText();
List<Template> templates = ATTRIBUTE_TEMPLATES.get(directiveName);
if (templates != null)
{
boolean valid = false;
JETItem previousItem = nameItem;
for (JETAttributeItem jetAttributeItem : attributes.getAttributes())
{
int previousStopOffset = previousItem.getStopOffset();
int nextStartOffset = jetAttributeItem.getStartOffset();
if (relativeOffset >= previousStopOffset && relativeOffset <= nextStartOffset)
{
valid = true;
break;
}
else
{
previousItem = jetAttributeItem;
}
}
if (!valid && relativeOffset >= attributes.getStopOffset() && relativeOffset <= tokenRegionLength - 2)
{
valid = true;
}
if (valid)
{
char characterBeforeInsertion = directive.charAt(relativeOffset - 1);
char characterAfterInsertion = directive.charAt(relativeOffset);
String prefix = Character.isWhitespace(characterBeforeInsertion) ? "" : " ";
String suffix = Character.isWhitespace(characterAfterInsertion) || characterAfterInsertion == '%' ? "" : " ";
for (Template template : templates)
{
if (jetDirectiveItem.getAttribute(template.getName()) == null)
{
result.add(convert(template, prefix, suffix));
}
}
}
}
return result.toArray(new Template [result.size()]);
}
catch (Exception exception)
{
return null;
}
}
}
}
static class JETProblemAnnotation extends Annotation implements IAnnotationPresentation
{
private static final Image[] SEVERITY_IMAGES;
private static final Image[] DISABLED_SEVERITY_IMAGES;
static
{
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
SEVERITY_IMAGES = new Image []{
sharedImages.getImage(ISharedImages.IMG_OBJS_INFO_TSK),
sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK),
sharedImages.getImage(ISharedImages.IMG_OBJS_ERROR_TSK) };
DISABLED_SEVERITY_IMAGES = new Image []{
new Image(SEVERITY_IMAGES[0].getDevice(), SEVERITY_IMAGES[0], SWT.IMAGE_GRAY),
new Image(SEVERITY_IMAGES[1].getDevice(), SEVERITY_IMAGES[1], SWT.IMAGE_GRAY),
new Image(SEVERITY_IMAGES[2].getDevice(), SEVERITY_IMAGES[2], SWT.IMAGE_GRAY) };
}
private static final String[] SEVERITY_TYPES = new String []{
"org.eclipse.ui.workbench.texteditor.info",
"org.eclipse.ui.workbench.texteditor.warning",
"org.eclipse.ui.workbench.texteditor.error" };
private final boolean disabled;
private final int severity;
private final Position position;
public JETProblemAnnotation(int severity, String message, Position position)
{
super(SEVERITY_TYPES[severity], false, message);
this.severity = severity;
this.position = position;
this.disabled = false;
}
public JETProblemAnnotation(MarkerAnnotation annotation, Position position)
{
super(SEVERITY_TYPES[getSeverity(annotation)], false, annotation.getText());
severity = getSeverity(annotation);
this.position = position;
this.disabled = true;
}
public Position getPosition()
{
return position;
}
public int getSeverity()
{
return severity;
}
public int getLayer()
{
return 6 + severity + (disabled ? 1 : 0);
}
private Image getImage()
{
return (disabled ? DISABLED_SEVERITY_IMAGES : SEVERITY_IMAGES)[severity];
}
public void paint(GC gc, Canvas canvas, Rectangle bounds)
{
ImageUtilities.drawImage(getImage(), gc, canvas, bounds, SWT.CENTER, SWT.TOP);
}
private static int getSeverity(MarkerAnnotation markerAnnotation)
{
try
{
IMarker marker = markerAnnotation.getMarker();
if (marker != null)
{
Object severity = marker.getAttribute(IMarker.SEVERITY);
return severity instanceof Integer ? (Integer)severity : IMarker.SEVERITY_INFO;
}
}
catch (CoreException exception)
{
}
return IMarker.SEVERITY_ERROR;
}
}
static class ColorManager implements IPropertyChangeListener
{
private static ColorManager INSTANCE = new ColorManager();
private static final String PROPERTY_PREFIX = "org.eclipse.emf.codegen.ui.jet.";
private final Set<JETToken> tokens = new LinkedHashSet<JETEditor.JETToken>();
private final Map<Control, ISourceViewer> sourceViewers = new HashMap<Control, ISourceViewer>();
private final Map<Color, Map<Color, Color>> blendedColors = new HashMap<Color, Map<Color, Color>>();
private final Map<RGB, Color> colors = new HashMap<RGB, Color>();
private final DisposeListener disposeListener = new DisposeListener()
{
public void widgetDisposed(DisposeEvent event)
{
sourceViewers.remove(event.widget);
if (sourceViewers.isEmpty())
{
if (trace)
{
System.out.println("unhook color");
}
JFaceResources.getColorRegistry().removeListener(ColorManager.this);
}
}
};
private ColorManager()
{
}
public Color getColor(int red, int green, int blue)
{
RGB rgb = new RGB(red, green, blue);
Color color = colors.get(rgb);
if (color == null)
{
color = new Color(Display.getDefault(), rgb);
colors.put(rgb, color);
}
return color;
}
public Color getBlendedColor(Color foreground, Color background)
{
Map<Color, Color> blendedBackgroundColors = blendedColors.get(foreground);
if (blendedBackgroundColors == null)
{
blendedBackgroundColors = new HashMap<Color, Color>();
blendedColors.put(foreground, blendedBackgroundColors);
}
Color blendedColor = blendedBackgroundColors.get(background);
if (blendedColor == null)
{
blendedColor = new Color(foreground.getDevice(), ColorUtil.blend(foreground.getRGB(), background.getRGB(), 50));
blendedBackgroundColors.put(background, blendedColor);
}
return blendedColor;
}
public String getProperty(JETToken token)
{
return "org.eclipse.emf.codegen.ui.jet." + (token == null ? JETContentRule.TOKEN : token.getBaseToken()).getType() + "Background";
}
public void register(ISourceViewer sourceViewer)
{
if (sourceViewers.isEmpty())
{
JFaceResources.getColorRegistry().addListener(this);
}
StyledText control = sourceViewer.getTextWidget();
sourceViewers.put(control, sourceViewer);
control.addDisposeListener(disposeListener);
}
public void register(JETToken token)
{
tokens.add(token);
update(token);
}
private void update(JETToken token)
{
String type = token.getBaseToken().getType();
token.setData(new JETTextAttribute(getForeground(type), getBackground(type), token.getTextStyle(), token.getBorderStyle(), null, token));
}
private Color getForeground(String type)
{
return JFaceResources.getColorRegistry().get("org.eclipse.emf.codegen.ui.jet." + type + "Foreground");
}
private Color getBackground(String type)
{
return JFaceResources.getColorRegistry().get("org.eclipse.emf.codegen.ui.jet." + type + "Background");
}
public void propertyChange(PropertyChangeEvent event)
{
if (event.getProperty().startsWith(PROPERTY_PREFIX))
{
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
for (JETToken token : tokens)
{
update(token);
}
for (ISourceViewer sourceViewer : sourceViewers.values())
{
sourceViewer.invalidateTextPresentation();
}
}
});
}
}
private static class JETTextAttribute extends TextAttribute
{
private final JETToken token;
private final int borderStyle;
public JETTextAttribute(Color foreground, Color background, int textStyle, int borderStyle, Font font, JETToken token)
{
super(foreground, background, textStyle, font);
this.token = token;
this.borderStyle = borderStyle;
}
public JETToken getToken()
{
return token;
}
public int getBorderStyle()
{
return borderStyle;
}
@Override
public boolean equals(Object object)
{
return object == this;
}
}
}
static class JETBracketMatcher extends DefaultCharacterPairMatcher
{
private final static char[] BRACKETS = { //
'{',
'}', //
'(',
')', //
'[',
']', //
'<',
'>', //
'%',
'%', //
'=',
'%', //
'@',
'%' //
};
private final JETEditor jetEditor;
private int customAnchor;
public JETBracketMatcher(JETEditor jetEditor)
{
super(BRACKETS);
this.jetEditor = jetEditor;
}
private JETToken getToken(int offset)
{
return jetEditor.getTokenAt(offset);
}
private Point getTokenRange(int offset)
{
return jetEditor.getTokenRangeAt(offset);
}
@Override
public IRegion match(IDocument document, int offset)
{
JETToken token = getToken(offset);
if (token == null)
{
return null;
}
Point tokenRange;
if (token.getBaseToken() == JETContentRule.TOKEN)
{
if (offset > 1)
{
token = getToken(offset - 1);
if (token == null || token.getBaseToken() == JETContentRule.TOKEN)
{
return null;
}
tokenRange = getTokenRange(offset - 1);
}
else
{
return null;
}
}
else
{
tokenRange = getTokenRange(offset);
}
for (;;)
{
try
{
// Trim of the preceding white space that's included in comments, scriptlets, and directives.
if (document.getChar(tokenRange.x) == ' ')
{
++tokenRange.x;
--tokenRange.y;
}
else
{
break;
}
}
catch (BadLocationException exception)
{
break;
}
}
int effectiveOffset = offset;
boolean isCloseBrace = false;
if (token == JETScriptletRule.TOKEN && tokenRange.y == 5)
{
try
{
isCloseBrace = "<%}%>".equals(document.get(tokenRange.x, tokenRange.y));
if (isCloseBrace)
{
effectiveOffset = tokenRange.x + 3;
}
}
catch (BadLocationException exception)
{
}
}
if (!isCloseBrace)
{
IRegion jetMatch = token.match(tokenRange, offset);
if (jetMatch != null)
{
customAnchor = offset > jetMatch.getOffset() + jetMatch.getLength() - 2 ? RIGHT : LEFT;
return jetMatch;
}
}
if (token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN)
{
JavaEditor javaEditor = jetEditor.getJavaEditor();
if (javaEditor != null)
{
ISourceViewer javaSourceViewer = javaEditor.getJavaSourceViewer();
IDocument javaDocument = javaSourceViewer.getDocument();
DefaultCharacterPairMatcher javaBracketMatcher = javaEditor.getJavaBracketMatcher();
if (javaBracketMatcher != null)
{
Position correspondingJavaPoint = jetEditor.getCorrespondingJavaPosition(effectiveOffset, 0);
if (correspondingJavaPoint == null)
{
return null;
}
IRegion javaRegion = javaBracketMatcher.match(javaDocument, correspondingJavaPoint.offset);
if (javaRegion == null)
{
return null;
}
Position correspondingTemplatePointStart = jetEditor.getCorrespondingTemplatePosition(javaRegion.getOffset(), 0);
if (correspondingTemplatePointStart == null)
{
return null;
}
Position correspondingTemplatePositionEnd = jetEditor.getCorrespondingTemplatePosition(javaRegion.getOffset() + javaRegion.getLength() - 1, 0);
if (correspondingTemplatePositionEnd == null)
{
return null;
}
customAnchor = javaBracketMatcher.getAnchor();
if (customAnchor != -1)
{
return new Region(correspondingTemplatePointStart.offset, correspondingTemplatePositionEnd.offset - correspondingTemplatePointStart.offset + 1);
}
}
}
}
customAnchor = -1;
return null;
}
@Override
public int getAnchor()
{
return customAnchor == -1 ? super.getAnchor() : customAnchor;
}
}
static class JETSourceViewerConfiguration extends TextSourceViewerConfiguration
{
private final DelegatingContentAssistProcessor delegatingContentAssistProcessor;
private final DelegatingQuickAssistProcessor delegatingQuickAssistProcessor;
private final BufferedRuleBasedScanner scanner = new BufferedRuleBasedScanner(1000);
private final CompletionListener completionListener;
private final JETEditor jetEditor;
public JETSourceViewerConfiguration(IPreferenceStore preferenceStore, JETEditor jetEditor)
{
super(preferenceStore);
this.jetEditor = jetEditor;
delegatingContentAssistProcessor = new DelegatingContentAssistProcessor(jetEditor);
delegatingQuickAssistProcessor = new DelegatingQuickAssistProcessor(jetEditor);
completionListener = new CompletionListener(jetEditor);
scanner.setRules(
new IRule []{
new JETCommentRule(),
new JETExpressionRule(),
new JETDirectiveRule(),
new JETScriptletRule(),
new JETContentRule(),
new JETTrailingWhitespaceContentRule(),
new JETCommentErrorRule(),
new JETExpressionErrorRule(),
new JETDirectiveErrorRule(),
new JETScriptletErrorRule() });
}
@Override
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer)
{
PresentationReconciler reconciler = createPresentationReconciler();
reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
DefaultDamagerRepairer damageRepairer = new JETDamageRepairer(jetEditor, scanner);
reconciler.setDamager(damageRepairer, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(damageRepairer, IDocument.DEFAULT_CONTENT_TYPE);
return reconciler;
}
protected PresentationReconciler createPresentationReconciler()
{
return new JETPresentationReconciler(jetEditor);
}
@Override
@SuppressWarnings("restriction")
public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer)
{
return new org.eclipse.jdt.internal.ui.text.HTMLAnnotationHover(false)
{
@Override
protected boolean isIncluded(Annotation annotation)
{
return isShowInVerticalRuler(annotation);
}
};
}
@Override
public IUndoManager getUndoManager(ISourceViewer sourceViewer)
{
int undoLevel = fPreferenceStore == null || !fPreferenceStore.contains(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE)
? 25 : fPreferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE);
return new CompositeUndoManager(jetEditor, undoLevel);
}
@SuppressWarnings("restriction")
@Override
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer)
{
ContentAssistant contentAssistant = new ContentAssistant();
contentAssistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
contentAssistant.setContentAssistProcessor(delegatingContentAssistProcessor, IDocument.DEFAULT_CONTENT_TYPE);
contentAssistant.addCompletionListener(completionListener);
org.eclipse.jdt.internal.ui.text.ContentAssistPreference.configure(contentAssistant, org.eclipse.jdt.internal.ui.JavaPlugin.getDefault().getPreferenceStore());
contentAssistant.enableColoredLabels(true);
return contentAssistant;
}
@SuppressWarnings("restriction")
@Override
public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer)
{
QuickAssistAssistant assistant = new QuickAssistAssistant();
assistant.setQuickAssistProcessor(delegatingQuickAssistProcessor);
try
{
// Not available until 3.7, i.e., Helios.
assistant.getClass().getMethod("setRestoreCompletionProposalSize", IDialogSettings.class).invoke(
assistant,
CodeGenUIPlugin.getPlugin().getDialogSettingsSection("quick_assist_proposal_size"));
}
catch (Exception exception)
{
// Ignore.
}
assistant.setInformationControlCreator(new IInformationControlCreator()
{
public IInformationControl createInformationControl(Shell parent)
{
return new DefaultInformationControl(parent, org.eclipse.ui.internal.editors.text.EditorsPlugin.getAdditionalInfoAffordanceString());
}
});
assistant.addCompletionListener(completionListener);
return assistant;
}
@Override
public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer)
{
return new IInformationControlCreator()
{
public IInformationControl createInformationControl(Shell parent)
{
return new DefaultInformationControl(parent, false);
}
};
}
@Override
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType)
{
return jetEditor.delegatingTextHover;
}
@Override
protected Map<String, IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer)
{
Map<String, IAdaptable> targets = super.getHyperlinkDetectorTargets(sourceViewer);
targets.put("org.eclipse.emf.codegen.ui.jetTemplate", jetEditor);
return targets;
}
static class CompletionListener implements ICompletionListener
{
private final JETEditor jetEditor;
public CompletionListener(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
public void assistSessionStarted(ContentAssistEvent event)
{
jetEditor.setShowingContentAssist(true);
}
public void assistSessionEnded(ContentAssistEvent event)
{
jetEditor.setShowingContentAssist(false);
}
public void selectionChanged(ICompletionProposal proposal, boolean smartToggle)
{
}
}
}
static final class CompositeUndoManager implements IUndoManager, IUndoManagerExtension, ITextInputListener
{
private final JETEditor jetEditor;
private final int undoLevel;
private int compoundChange;
private final Map<IDocument, SharedTextViewerUndoManager> managers = new HashMap<IDocument, SharedTextViewerUndoManager>();
private final IUndoContext undoContext = new IUndoContext()
{
public boolean matches(IUndoContext context)
{
for (SharedTextViewerUndoManager undoManager : managers.values())
{
IUndoContext undoContext = undoManager.getUndoContext();
if (undoContext.matches(context))
{
return true;
}
}
return false;
}
public String getLabel()
{
return "Shared Undo Context";
}
};
private ITextViewer textViewer;
private IDocument document;
public CompositeUndoManager(JETEditor jetEditor, int undoLevel)
{
this.jetEditor = jetEditor;
this.undoLevel = undoLevel;
}
protected SharedTextViewerUndoManager getUndoManager()
{
return managers.get(document);
}
public IUndoContext getUndoContext()
{
return undoContext;
}
public void connect(ITextViewer textViewer)
{
if (this.textViewer == null)
{
textViewer.addTextInputListener(this);
}
this.textViewer = textViewer;
inputDocumentAboutToBeChanged(this.document, textViewer.getDocument());
}
public void disconnect()
{
textViewer.removeTextInputListener(this);
textViewer = null;
document = null;
for (SharedTextViewerUndoManager undoManager : managers.values())
{
undoManager.disconnect();
}
managers.clear();
}
public void reset()
{
// This is called when switching documents and we don't want to lose our undo history for each document so don't do anything.
}
public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput)
{
SharedTextViewerUndoManager undoManager = getUndoManager();
if (undoManager != null)
{
undoManager.removeListeners();
}
}
public void inputDocumentChanged(IDocument oldInput, IDocument newInput)
{
this.document = newInput;
SharedTextViewerUndoManager undoManager = getUndoManager();
if (undoManager == null)
{
undoManager = new SharedTextViewerUndoManager(undoLevel, jetEditor, textViewer, document);
managers.put(document, undoManager);
}
undoManager.addListeners();
}
public void beginCompoundChange()
{
if (compoundChange++ == 0)
{
for (SharedTextViewerUndoManager sharedTextViewerUndoManager : managers.values())
{
sharedTextViewerUndoManager.beginCompoundChange();
}
}
}
public void endCompoundChange()
{
if (--compoundChange == 0)
{
for (SharedTextViewerUndoManager sharedTextViewerUndoManager : managers.values())
{
sharedTextViewerUndoManager.endCompoundChange();
}
}
}
public void setMaximalUndoLevel(int undoLevel)
{
getUndoManager().setMaximalUndoLevel(undoLevel);
}
public boolean undoable()
{
return getUndoManager().undoable();
}
public boolean redoable()
{
return getUndoManager().redoable();
}
public void undo()
{
getUndoManager().undo();
}
public void redo()
{
getUndoManager().redo();
}
}
static class SharedTextViewerUndoManager implements IUndoManager, IUndoManagerExtension, IDocumentUndoListener, KeyListener, MouseListener
{
private final JETEditor jetEditor;
private final ITextViewer textViewer;
private final IDocumentUndoManager documentUndoManager;
private final IDocument document;
private int undoLevel;
public SharedTextViewerUndoManager(int undoLevel, JETEditor jetEditor, ITextViewer textViewer, IDocument document)
{
this.undoLevel = undoLevel;
this.jetEditor = jetEditor;
this.textViewer = textViewer;
this.document = document;
DocumentUndoManagerRegistry.connect(document);
documentUndoManager = DocumentUndoManagerRegistry.getDocumentUndoManager(document);
documentUndoManager.connect(this);
setMaximalUndoLevel(undoLevel);
documentUndoManager.addDocumentUndoListener(this);
}
public void beginCompoundChange()
{
documentUndoManager.beginCompoundChange();
}
public void endCompoundChange()
{
documentUndoManager.endCompoundChange();
}
public void addListeners()
{
StyledText text = textViewer.getTextWidget();
if (text != null)
{
text.addMouseListener(this);
text.addKeyListener(this);
}
}
public void removeListeners()
{
StyledText text = textViewer.getTextWidget();
if (text != null)
{
text.removeMouseListener(this);
text.removeKeyListener(this);
}
}
public void setMaximalUndoLevel(int newUndoLevel)
{
undoLevel = Math.max(0, newUndoLevel);
documentUndoManager.setMaximalUndoLevel(undoLevel);
}
public void connect(ITextViewer newTextViewer)
{
// This is never called because we connect during construction.
}
public void disconnect()
{
removeListeners();
documentUndoManager.disconnect(this);
DocumentUndoManagerRegistry.disconnect(document);
documentUndoManager.removeDocumentUndoListener(this);
}
public void reset()
{
documentUndoManager.reset();
}
public boolean redoable()
{
return documentUndoManager.redoable();
}
public boolean undoable()
{
return documentUndoManager.undoable();
}
public void redo()
{
try
{
documentUndoManager.redo();
}
catch (ExecutionException ex)
{
openErrorDialog("Redo Failed", ex);
}
}
public void undo()
{
try
{
documentUndoManager.undo();
}
catch (ExecutionException ex)
{
openErrorDialog("Undo Failed", ex);
}
}
private void selectAndReveal(int offset, int length)
{
jetEditor.selectAndReveal(document, offset, length);
}
public IUndoContext getUndoContext()
{
return documentUndoManager.getUndoContext();
}
private void openErrorDialog(final String title, final Exception ex)
{
Shell shell = null;
StyledText st = textViewer.getTextWidget();
if (st != null && !st.isDisposed())
{
shell = st.getShell();
}
if (Display.getCurrent() != null)
{
MessageDialog.openError(shell, title, ex.getLocalizedMessage());
}
else
{
Display display;
final Shell finalShell = shell;
if (finalShell != null)
{
display = finalShell.getDisplay();
}
else
{
display = Display.getDefault();
}
display.syncExec(new Runnable()
{
public void run()
{
MessageDialog.openError(finalShell, title, ex.getLocalizedMessage());
}
});
}
}
public void mouseDoubleClick(MouseEvent event)
{
}
public void mouseUp(MouseEvent event)
{
}
public void mouseDown(MouseEvent event)
{
if (event.button == 1)
{
documentUndoManager.commit();
}
}
public void keyReleased(KeyEvent event)
{
}
public void keyPressed(KeyEvent event)
{
switch (event.keyCode)
{
case SWT.ARROW_UP:
case SWT.ARROW_DOWN:
case SWT.ARROW_LEFT:
case SWT.ARROW_RIGHT:
{
documentUndoManager.commit();
break;
}
}
}
public void documentUndoNotification(DocumentUndoEvent event)
{
int eventType = event.getEventType();
if ((eventType & DocumentUndoEvent.ABOUT_TO_UNDO) != 0 || (eventType & DocumentUndoEvent.ABOUT_TO_REDO) != 0)
{
if (event.isCompound())
{
((ITextViewerExtension)textViewer).setRedraw(false);
}
}
else if (((eventType & DocumentUndoEvent.UNDONE) != 0) || ((eventType & DocumentUndoEvent.REDONE) != 0))
{
if (event.isCompound())
{
((ITextViewerExtension)textViewer).setRedraw(true);
}
StyledText widget = textViewer.getTextWidget();
if (widget != null && !widget.isDisposed() && widget.isFocusControl())
{
selectAndReveal(event.getOffset(), event.getText() == null ? 0 : event.getText().length());
}
}
}
}
static class JETDamageRepairer extends DefaultDamagerRepairer
{
private final JETEditor jetEditor;
private int capacity = 8;
private int size = 0;
private int[] offsets = new int [capacity];
private JETToken[] tokens = new JETToken [capacity];
public JETDamageRepairer(JETEditor jetEditor, ITokenScanner scanner)
{
super(scanner);
this.jetEditor = jetEditor;
}
private void ensureCapacity(int capacity)
{
if (this.capacity < capacity)
{
int newCapacity = capacity << 1;
int[] newOffsets = new int [newCapacity];
JETToken[] newTokens = new JETToken [newCapacity];
System.arraycopy(offsets, 0, newOffsets, 0, this.capacity);
System.arraycopy(tokens, 0, newTokens, 0, this.capacity);
this.offsets = newOffsets;
this.tokens = newTokens;
this.capacity = newCapacity;
}
}
private void add(int offset, int length, JETToken token)
{
ensureCapacity(size + 2);
tokens[size] = token;
offsets[size] = offset;
tokens[++size] = null;
offsets[size] = offset + length;
}
@Override
public void createPresentation(TextPresentation presentation, ITypedRegion region)
{
try
{
super.createPresentation(presentation, region);
}
finally
{
int[] offsets = new int [size + 1];
JETToken[] tokens = new JETToken [size + 1];
System.arraycopy(this.offsets, 0, offsets, 0, size + 1);
System.arraycopy(this.tokens, 0, tokens, 0, size + 1);
jetEditor.setTokenData(offsets, tokens);
size = 0;
this.offsets[0] = 0;
this.offsets[1] = 0;
}
}
@Override
protected void addRange(TextPresentation presentation, int offset, int length, TextAttribute textAttribute)
{
if (textAttribute instanceof ColorManager.JETTextAttribute)
{
JETEditor.ColorManager.JETTextAttribute jetTextAttribute = (ColorManager.JETTextAttribute)textAttribute;
JETToken token = jetTextAttribute.getToken();
add(offset, length, token);
int style = textAttribute.getStyle();
int fontStyle = style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL);
StyleRange styleRange = new StyleRange(offset, length, textAttribute.getForeground(), textAttribute.getBackground(), fontStyle);
styleRange.strikeout = (style & TextAttribute.STRIKETHROUGH) != 0;
styleRange.underline = (style & TextAttribute.UNDERLINE) != 0;
styleRange.font = textAttribute.getFont();
styleRange.data = token;
styleRange.borderStyle = jetTextAttribute.getBorderStyle();
if (styleRange.borderStyle != SWT.NONE)
{
styleRange.borderColor = styleRange.foreground;
}
presentation.addStyleRange(styleRange);
}
}
}
static class JETTokenRegion
{
private final JETToken token;
private int offset;
private int length;
public JETTokenRegion(int offset, int length, JETToken token)
{
this.offset = offset;
this.length = length;
this.token = token;
}
public JETToken getToken()
{
return token;
}
public void shrinkToJava(IDocument document)
{
if (token == JETScriptletRule.TOKEN)
{
int delta = 0;
try
{
while (Character.isWhitespace(document.getChar(offset + delta)))
{
++delta;
}
}
catch (BadLocationException exception)
{
// Should not happen.
}
offset += delta + 2;
length -= delta + 2;
}
else if (token == JETExpressionRule.TOKEN)
{
offset += 3;
length -= 5;
}
}
public void expand()
{
--offset;
length += 2;
}
public int getOffset()
{
return offset;
}
public void setOffset(int offset)
{
this.offset = offset;
}
public int getLength()
{
return length;
}
public void setLength(int length)
{
this.length = length;
}
}
static class JETPresentationReconciler extends PresentationReconciler
{
private final JETEditor jetEditor;
private IDocument document;
public JETPresentationReconciler(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
@Override
public TextPresentation createPresentation(IRegion damage, IDocument document)
{
if (document != this.document)
{
setDocument(document);
}
List<JETJavaItem> javaItems = null;
List<JETRootItem> skippedItems = null;
ITextViewerExtension5 javaViewer = null;
StyledText javaStyledText = null;
if (jetEditor.isJavaEditorInSync())
{
JETCompilationUnit compilerResult = jetEditor.getCompilationUnit();
if (compilerResult != null)
{
ISourceViewer underlyingSourceViewer = jetEditor.getJavaEditor().getJavaSourceViewer();
if (compilerResult.getJavaCompilationUnit().equals(underlyingSourceViewer.getDocument().get()))
{
int fileID = jetEditor.getFileID();
int templateOffset = damage.getOffset();
int templateLength = damage.getLength();
javaItems = compilerResult.getJavaItems(fileID, templateOffset, templateLength);
skippedItems = compilerResult.getSkippedItems(fileID, templateOffset, templateLength);
javaStyledText = underlyingSourceViewer.getTextWidget();
javaViewer = (ITextViewerExtension5)underlyingSourceViewer;
}
}
}
// Create the full presentation because we can only find tokens if we start from the start.
//
Region fullRegion = new Region(0, document.getLength());
TextPresentation fullTextPresentation = super.createPresentation(fullRegion, document);
if (javaItems == null && damage.equals(fullRegion))
{
return fullTextPresentation;
}
// Filter these down to the ones within the actual damaged region because updating so many takes long.
//
TextPresentation textPresentation = new TextPresentation(damage, 1000);
int offset = damage.getOffset();
int end = offset + damage.getLength();
for (Iterator<StyleRange> i = fullTextPresentation.getAllStyleRangeIterator(); i.hasNext();)
{
StyleRange styleRange = i.next();
if (styleRange.start + styleRange.length >= offset && styleRange.start <= end)
{
if (javaItems == null)
{
textPresentation.addStyleRange(styleRange);
}
else
{
applySemanticStyle(textPresentation, styleRange, javaItems, skippedItems, javaStyledText, javaViewer);
}
}
}
return textPresentation;
}
private void applySemanticStyle(
TextPresentation textPresentation,
StyleRange styleRange,
List<JETJavaItem> javaItems,
List<JETRootItem> skippedItems,
StyledText textWidget,
ITextViewerExtension5 javaModelViewer)
{
IToken token = (IToken)styleRange.data;
int start = styleRange.start;
int end = styleRange.start + styleRange.length;
for (JETRootItem jetRootItem : skippedItems)
{
if (jetRootItem.getStartOffset() < end && jetRootItem.getStopOffset() > start)
{
styleRange.strikeout = true;
Color blendedColor = ColorManager.INSTANCE.getBlendedColor(styleRange.foreground, styleRange.background);
styleRange.strikeoutColor = blendedColor;
styleRange.foreground = blendedColor;
break;
}
}
Color defaultForeground = textWidget.getForeground();
// Only do this work for scriptlets and expressions.
if (token == JETScriptletRule.TOKEN || token == JETExpressionRule.TOKEN)
{
for (JETJavaItem javaItem : javaItems)
{
int delta = javaItem.getStartOffset() - start;
if (delta >= 0 && javaItem.getStopOffset() <= end)
{
int javaOffset = javaItem.getJavaOffset();
int javaLength = javaItem.getJavaLength();
int javaWidgetOffset = javaModelViewer.modelOffset2WidgetOffset(javaOffset);
StyleRange[] styleRanges = textWidget.getStyleRanges(javaWidgetOffset, javaLength);
if (trace)
{
String text = javaItem.getText();
String javaText = textWidget.getTextRange(javaWidgetOffset, javaLength);
if (!text.equals(javaText))
{
if (trace)
{
System.out.println("mismatched text when applying styles");
}
break;
}
}
List<StyleRange> newStyleRanges = new ArrayList<StyleRange>();
// Whatever text range appears before the start of the Java style range keeps the existing style.
// This will definitely include the leading <%= or the leading <% and any pure whitespace before it.
//
StyleRange leadingNewStyleRanage = (StyleRange)styleRange.clone();
leadingNewStyleRanage.length = delta;
newStyleRanges.add(leadingNewStyleRanage);
start += delta;
int consumedLength = 0;
for (StyleRange javaStyleRange : styleRanges)
{
StyleRange newStyleRange = (StyleRange)styleRange.clone();
newStyleRange.start = start + consumedLength;
newStyleRange.length = javaStyleRange.length;
if (javaStyleRange.foreground == null || !javaStyleRange.foreground.equals(defaultForeground))
{
newStyleRange.foreground = javaStyleRange.foreground;
}
newStyleRange.foreground = newStyleRange.strikeout
? ColorManager.INSTANCE.getBlendedColor(newStyleRange.foreground, newStyleRange.background) : newStyleRange.foreground;
newStyleRange.fontStyle = javaStyleRange.fontStyle;
consumedLength += newStyleRange.length;
newStyleRanges.add(newStyleRange);
}
// This will include the style range for the %>
//
StyleRange trailingNewStyleRange = (StyleRange)styleRange.clone();
trailingNewStyleRange.start = start + consumedLength;
trailingNewStyleRange.length = end - trailingNewStyleRange.start;
newStyleRanges.add(trailingNewStyleRange);
for (StyleRange newStyleRange : newStyleRanges)
{
textPresentation.addStyleRange(newStyleRange);
}
return;
}
}
}
// If we don't find a corresponding Java item, just handle it like normal.
textPresentation.addStyleRange(styleRange);
}
protected void setDocument(IDocument document)
{
setDocumentToDamagers(document);
setDocumentToRepairers(document);
this.document = document;
}
}
static class BracketInserter implements VerifyKeyListener
{
private final JETEditor jetEditor;
private final ISelectionProvider jetSelectionProvider;
public BracketInserter(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
jetSelectionProvider = jetEditor.getSelectionProvider();
}
private boolean edit(ITextViewer jetSourceViewer, int offset, int length, String replacement, int selectionOffset)
{
try
{
IDocument document = jetSourceViewer.getDocument();
document.replace(offset, length, replacement);
jetSourceViewer.setSelectedRange(selectionOffset, 0);
return false;
}
catch (BadLocationException exception)
{
return true;
}
}
public void verifyKey(VerifyEvent event)
{
if (event.doit && jetEditor.getInsertMode() == SMART_INSERT && !isMultilineSelection())
{
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
final Point selection = jetSourceViewer.getSelectedRange();
final int offset = selection.x;
final int length = selection.y;
if (length == 0 && offset > 0)
{
if (event.character == '%')
{
JETToken tokenAtSelection = jetEditor.getTokenAtSelection(0);
JETToken tokenBeforeSelection = jetEditor.getTokenAtSelection(-1);
if (tokenAtSelection != null && tokenAtSelection.getBaseToken() == JETContentRule.TOKEN
|| tokenBeforeSelection != null && tokenBeforeSelection.getBaseToken() == JETContentRule.TOKEN)
{
String text = jetSourceViewer.getTextWidget().getTextRange(offset - 1, 1);
if ("<".equals(text))
{
event.doit = edit(jetSourceViewer, offset, 0, "%%>", offset + 1);
}
}
}
else if (event.character == '-')
{
JETToken token = jetEditor.getTokenAt(offset);
if (token == JETScriptletRule.TOKEN)
{
IDocument document = jetSourceViewer.getDocument();
try
{
if ("<%%>".equals(document.get(offset - 2, 4)))
{
event.doit = edit(jetSourceViewer, offset, 0, "--", offset + 1);
}
}
catch (BadLocationException e)
{
}
}
}
else if (event.character == '>')
{
JETToken tokenAtSelection = jetEditor.getTokenAtSelection(0);
if (tokenAtSelection == JETScriptletRule.TOKEN)
{
IDocument document = jetSourceViewer.getDocument();
try
{
char character = document.getChar(offset - 1);
if (character == '%')
{
int documentLength = document.getLength();
StringBuilder additionalWhiteSpace = new StringBuilder();
for (int i = offset; i < documentLength; ++i)
{
character = document.getChar(i);
if (!Character.isWhitespace(character))
{
// {
if (character != '}')
{
additionalWhiteSpace.setLength(0);
}
break;
}
additionalWhiteSpace.append(character);
}
event.doit = edit(jetSourceViewer, offset, additionalWhiteSpace.length(), ">" + additionalWhiteSpace + "<%", offset + 1);
}
}
catch (BadLocationException e)
{
}
}
}
else if (event.keyCode == 0x8)
{
JETTokenRegion tokenRegion = jetEditor.getTokenRegionAt(offset);
if (tokenRegion != null)
{
JETToken token = tokenRegion.getToken();
if (token == JETCommentRule.TOKEN)
{
if (offset - tokenRegion.getOffset() == 3 && tokenRegion.getLength() == 6)
{
event.doit = edit(jetSourceViewer, offset - 1, 2, "", offset - 1);
}
}
else if (token == JETScriptletRule.TOKEN)
{
if (offset - tokenRegion.getOffset() == 2 && tokenRegion.getLength() == 4)
{
event.doit = edit(jetSourceViewer, offset - 1, 3, "", offset - 1);
}
}
}
}
}
}
}
private boolean isMultilineSelection()
{
ISelection selection = jetSelectionProvider.getSelection();
if (selection instanceof ITextSelection)
{
ITextSelection ts = (ITextSelection)selection;
return ts.getStartLine() != ts.getEndLine();
}
return false;
}
}
static final class JETToken extends Token
{
private final String type;
private final int textStyle;
private final int borderStyle;
private final JETToken baseToken;
public JETToken(String type)
{
this(type, SWT.NONE, SWT.NONE);
}
public JETToken(String type, int textStyle, int borderStyle)
{
super(null);
this.type = type;
this.textStyle = textStyle;
this.borderStyle = borderStyle;
this.baseToken = this;
ColorManager.INSTANCE.register(this);
}
public JETToken(JETToken baseToken, String type, int textStyle)
{
this(baseToken, type, textStyle, SWT.NONE);
}
public JETToken(JETToken baseToken, String type, int textStyle, int borderStyle)
{
super(null);
this.type = type + '.' + baseToken.getType();
this.textStyle = textStyle;
this.baseToken = baseToken;
this.borderStyle = borderStyle;
ColorManager.INSTANCE.register(this);
}
public final String getType()
{
return type;
}
public final JETToken getBaseToken()
{
return baseToken;
}
public final int getTextStyle()
{
return textStyle;
}
public final int getBorderStyle()
{
return borderStyle;
}
public final void setData(TextAttribute textAttribute)
{
super.setData(textAttribute);
}
@Override
public final void setData(Object data)
{
super.setData((TextAttribute)data);
}
@Override
public final String toString()
{
return "JETToken:" + type;
}
public final IRegion match(Point tokenRange, int offset)
{
int prefixLength = -1;
if (type.equals("scriptlet"))
{
prefixLength = 2;
}
else if (type.equals("expression") || type.equals("directive") || type.equals("comment"))
{
prefixLength = 3;
}
if (prefixLength != -1)
{
if (offset == tokenRange.x + tokenRange.y || offset == tokenRange.x + 1)
{
return new Region(tokenRange.x, tokenRange.y);
}
if (offset == tokenRange.x + tokenRange.y - 1 || offset == tokenRange.x + 2)
{
return new Region(tokenRange.x + 1, tokenRange.y - 2);
}
if (prefixLength == 3 && (offset == tokenRange.x + tokenRange.y - 1 || offset == tokenRange.x + 3))
{
return new Region(tokenRange.x + 2, tokenRange.y - 3);
}
}
return null;
}
}
static abstract class JETRule
{
private final JETToken successToken;
private final char[] prefix;
private int count;
public JETRule(JETToken successToken, char[] prefix)
{
this.successToken = successToken;
this.prefix = prefix;
}
protected int getCount()
{
return count;
}
public final JETToken getSuccessToken()
{
return successToken;
}
protected boolean scanForStart(ICharacterScanner scanner)
{
for (int i = 0; i < prefix.length; ++i)
{
if (prefix[i] != read(scanner))
{
return false;
}
}
return true;
}
protected boolean scanForEnd(ICharacterScanner scanner)
{
for (int character = read(scanner); character != ICharacterScanner.EOF; character = read(scanner))
{
if (character == '%')
{
if (read(scanner) == '>')
{
return true;
}
unread(scanner);
}
}
return false;
}
protected int read(ICharacterScanner scanner)
{
++count;
int read = scanner.read();
if (trace)
{
if (read == ICharacterScanner.EOF)
{
System.out.print("'eof'");
}
else if (read == ' ')
{
System.out.print("~");
}
else if (read == '\n')
{
System.out.print("\\n");
}
else if (read == '\r')
{
System.out.print("\\r");
}
else
{
System.out.print((char)read);
}
}
return read;
}
protected void unread(ICharacterScanner scanner)
{
--count;
scanner.unread();
}
protected void unreadAll(ICharacterScanner scanner)
{
while (count-- > 0)
{
scanner.unread();
}
count = 0;
}
protected boolean isGreedy()
{
return true;
}
protected void skipLeading(ICharacterScanner scanner)
{
if (trace)
{
System.out.println("-----------");
}
if (isGreedy())
{
for (int read = read(scanner); read == ' ' || read == '\t'; read = read(scanner))
{
}
unread(scanner);
}
}
public final IToken evaluate(ICharacterScanner scanner)
{
try
{
return doEvaluate(scanner);
}
finally
{
count = 0;
}
}
protected IToken doEvaluate(ICharacterScanner scanner)
{
skipLeading(scanner);
if (scanForStart(scanner))
{
if (scanForEnd(scanner))
{
return getSuccessToken();
}
}
unreadAll(scanner);
return Token.UNDEFINED;
}
}
static class JETDirectiveRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char []{ '<', '%', '@' };
public static final JETToken TOKEN = new JETToken("directive");
@Override
protected boolean isGreedy()
{
return false;
}
public JETDirectiveRule()
{
super(TOKEN, PREFIX);
}
}
static class JETScriptletRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char []{ '<', '%' };
public static final JETToken TOKEN = new JETToken("scriptlet");
public JETScriptletRule()
{
super(TOKEN, PREFIX);
}
@Override
protected boolean scanForStart(ICharacterScanner scanner)
{
if (super.scanForStart(scanner))
{
int read = read(scanner);
unread(scanner);
if (read == '@' || read == '=' || read == '-')
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}
}
static class JETCommentRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char []{ '<', '%', '-' };
public static final JETToken TOKEN = new JETToken("comment");
public JETCommentRule()
{
super(TOKEN, PREFIX);
}
@Override
protected boolean scanForEnd(ICharacterScanner scanner)
{
for (int character = read(scanner); character != ICharacterScanner.EOF; character = read(scanner))
{
if (character == '-')
{
if (read(scanner) == '%')
{
if (read(scanner) == '>')
{
return true;
}
unread(scanner);
}
else
{
unread(scanner);
}
}
}
return false;
}
}
static class JETExpressionRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char []{ '<', '%', '=' };
public static final JETToken TOKEN = new JETToken("expression");
public JETExpressionRule()
{
super(TOKEN, PREFIX);
}
@Override
protected boolean isGreedy()
{
return false;
}
}
static class JETContentRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char [0];
public static final JETToken TOKEN = new JETToken("content");
public JETContentRule()
{
super(TOKEN, PREFIX);
}
@Override
protected IToken doEvaluate(ICharacterScanner scanner)
{
int trailingWhitespaceCount = 0;
for (int read = read(scanner); read != ICharacterScanner.EOF; read = read(scanner))
{
if (read == '<')
{
if (read(scanner) == '%')
{
unread(scanner);
unread(scanner);
if (getCount() == 0)
{
return Token.UNDEFINED;
}
else
{
return getSuccessToken();
}
}
}
else if (read == '\n')
{
if (trailingWhitespaceCount != 0)
{
for (int i = 0; i <= trailingWhitespaceCount; ++i)
{
unread(scanner);
}
return getCount() == 0 ? Token.UNDEFINED : getSuccessToken();
}
else
{
return getSuccessToken();
}
}
else if (read == '\r')
{
if (trailingWhitespaceCount != 0)
{
++trailingWhitespaceCount;
}
}
else if (read == ' ' || read == '\t')
{
++trailingWhitespaceCount;
}
else
{
trailingWhitespaceCount = 0;
}
}
if (getCount() == 1)
{
return Token.EOF;
}
else
{
if (trailingWhitespaceCount != 0)
{
for (int i = 0; i <= trailingWhitespaceCount; ++i)
{
unread(scanner);
}
}
return getCount() == 0 ? Token.UNDEFINED : getSuccessToken();
}
}
}
static class JETTrailingWhitespaceContentRule extends JETRule implements IRule
{
private static final char[] PREFIX = new char [0];
public static final JETToken TOKEN = new JETToken(JETContentRule.TOKEN, "trailing-whitespace-content", SWT.NONE, SWT.BORDER_SOLID);
public JETTrailingWhitespaceContentRule()
{
super(TOKEN, PREFIX);
}
@Override
protected IToken doEvaluate(ICharacterScanner scanner)
{
for (int read = read(scanner); read != ICharacterScanner.EOF; read = read(scanner))
{
if (read == '\n')
{
return getSuccessToken();
}
else if (read != ' ' && read != '\t' && read != '\r')
{
unreadAll(scanner);
return Token.UNDEFINED;
}
}
return getCount() == 1 ? Token.EOF : getSuccessToken();
}
}
static class JETBaseErrorRule extends JETRule implements IRule
{
public JETBaseErrorRule(JETToken successToken, char[] prefix)
{
super(successToken, prefix);
}
@Override
protected IToken doEvaluate(ICharacterScanner scanner)
{
if (scanForStart(scanner))
{
for (int read = read(scanner); read != ICharacterScanner.EOF; read = read(scanner))
{
}
return getSuccessToken();
}
if (read(scanner) == ICharacterScanner.EOF)
{
return Token.EOF;
}
else
{
unreadAll(scanner);
return Token.UNDEFINED;
}
}
}
static class JETScriptletErrorRule extends JETBaseErrorRule
{
public static final JETToken TOKEN = new JETToken(JETScriptletRule.TOKEN, "error", TextAttribute.STRIKETHROUGH);
public JETScriptletErrorRule()
{
super(TOKEN, JETScriptletRule.PREFIX);
}
}
static class JETExpressionErrorRule extends JETBaseErrorRule
{
public static final JETToken TOKEN = new JETToken(JETExpressionRule.TOKEN, "error", TextAttribute.STRIKETHROUGH);
public JETExpressionErrorRule()
{
super(TOKEN, JETExpressionRule.PREFIX);
}
}
static class JETCommentErrorRule extends JETBaseErrorRule
{
public static final JETToken TOKEN = new JETToken(JETCommentRule.TOKEN, "error", TextAttribute.STRIKETHROUGH);
public JETCommentErrorRule()
{
super(TOKEN, JETCommentRule.PREFIX);
}
}
static class JETDirectiveErrorRule extends JETBaseErrorRule
{
public static final JETToken TOKEN = new JETToken(JETDirectiveRule.TOKEN, "error", TextAttribute.STRIKETHROUGH);
public JETDirectiveErrorRule()
{
super(TOKEN, JETDirectiveRule.PREFIX);
}
}
@SuppressWarnings("restriction")
static class JETBreadcrumbViewer extends org.eclipse.jdt.internal.ui.javaeditor.breadcrumb.BreadcrumbViewer
{
public JETBreadcrumbViewer(Composite parent, int style)
{
super(parent, style);
addDoubleClickListener(new IDoubleClickListener()
{
public void doubleClick(DoubleClickEvent event)
{
Object element = ((IStructuredSelection)event.getSelection()).getFirstElement();
Widget item = findItem(((ITreeContentProvider)getContentProvider()).getParent(element));
if (item != null)
{
try
{
Method openDropDownMenuMethod = item.getClass().getDeclaredMethod("openDropDownMenu");
openDropDownMenuMethod.setAccessible(true);
openDropDownMenuMethod.invoke(item);
}
catch (Exception ex)
{
// Ignore.
}
}
}
});
}
@Override
protected void configureDropDownViewer(TreeViewer viewer, Object input)
{
}
@Override
public Control getControl()
{
// Ensure the callers don't get warnings about restricted access.
return super.getControl();
}
}
static class JETTextSelectionNavigationLocation extends NavigationLocation
{
private static final String TAG_X = "x";
private static final String TAG_Y = "y";
private static final String TAG_DOCUMENT_ID = "document_id";
private static final String TAG_INFO = "info";
private static final String INFO_DELETED = "deleted";
private static final String INFO_NOT_DELETED = "not_deleted";
private static final String CATEGORY = "__navigation_" + JETTextSelectionNavigationLocation.class.hashCode();
private static final IPositionUpdater POSITION_UPDATER = new DefaultPositionUpdater(CATEGORY);
private Position position;
private String documentID;
private IDocument document;
private Position savedPosition;
public JETTextSelectionNavigationLocation(JETEditor jetEditor, boolean initialize)
{
super(jetEditor);
if (initialize)
{
ITextSelection selection = (ITextSelection)jetEditor.getSelectionProvider().getSelection();
IDocument document = getDocument(jetEditor);
Position position = new Position(selection.getOffset(), selection.getLength());
if (installOnDocument(document, position, CATEGORY, POSITION_UPDATER))
{
this.document = document;
this.documentID = getDocumentID(jetEditor);
Assert.isNotNull(this.documentID, "The document ID must be specified");
this.position = position;
if (!jetEditor.isDirty())
{
savedPosition = new Position(position.offset, position.length);
}
}
}
}
public String getDocumentID()
{
return documentID;
}
private String getDocumentID(JETEditor jetEditor)
{
return jetEditor.getDocumentManager().getDocumentID();
}
private IDocument getDocument(JETEditor jetEditor)
{
return jetEditor.getSourceViewer().getDocument();
}
@Override
public void dispose()
{
free();
super.dispose();
}
private void free()
{
uninstallFromDocument(document, position, CATEGORY, POSITION_UPDATER);
document = null;
position = null;
savedPosition = null;
documentID = null;
}
@Override
public void releaseState()
{
free();
super.releaseState();
}
public boolean mergeInto(INavigationLocation location)
{
if (location == null || location.getClass() != getClass())
{
return false;
}
JETTextSelectionNavigationLocation jetLocation = (JETTextSelectionNavigationLocation)location;
if (!jetLocation.documentID.equals(documentID))
{
return false;
}
if (position == null || position.isDeleted || document == null)
{
return true;
}
if (jetLocation.position == null || jetLocation.position.isDeleted)
{
uninstallFromDocument(document, position, CATEGORY, POSITION_UPDATER);
jetLocation.document = document;
jetLocation.position = position;
jetLocation.savedPosition = savedPosition;
jetLocation.documentID = documentID;
return true;
}
if (jetLocation.document == document)
{
if (jetLocation.position.overlapsWith(position.offset, position.length) || position.offset + position.length == jetLocation.position.offset
|| jetLocation.position.offset + jetLocation.position.length == position.offset)
{
jetLocation.position.offset = position.offset;
jetLocation.position.length = position.length;
return true;
}
}
return false;
}
public void restoreLocation()
{
if (position != null && !position.isDeleted)
{
IEditorPart part = getEditorPart();
if (part instanceof JETEditor)
{
JETEditor editor = (JETEditor)getEditorPart();
editor.selectAndReveal(this, position.offset, position.length);
}
}
}
public void saveState(IMemento memento)
{
if (savedPosition != null)
{
memento.putInteger(TAG_X, savedPosition.offset);
memento.putInteger(TAG_Y, savedPosition.length);
memento.putString(TAG_INFO, (savedPosition.isDeleted ? INFO_DELETED : INFO_NOT_DELETED));
memento.putString(TAG_DOCUMENT_ID, documentID);
}
}
public void restoreState(IMemento memento)
{
IEditorPart part = getEditorPart();
if (part instanceof JETEditor)
{
documentID = memento.getString(TAG_DOCUMENT_ID);
Integer offset = memento.getInteger(TAG_X);
Integer length = memento.getInteger(TAG_Y);
String deleted = memento.getString(TAG_INFO);
if (offset != null && length != null)
{
Position position = new Position(offset.intValue(), length.intValue());
this.position = position;
if (deleted != null)
{
position.isDeleted = INFO_DELETED.equals(deleted) ? true : false;
}
}
}
}
public void restoreDocument(JETEditor jetEditor, IDocument document)
{
this.document = document;
if (installOnDocument(document, position, CATEGORY, POSITION_UPDATER))
{
if (!jetEditor.isDirty())
{
savedPosition = new Position(position.offset, position.length);
}
}
}
public void partSaved(IEditorPart part)
{
savedPosition = position == null || position.isDeleted() ? null : new Position(position.offset, position.length);
}
private boolean samePosition(JETEditor jetEditor)
{
if (position == null)
{
return true;
}
if (position.isDeleted)
{
return false;
}
if (!getDocumentID(jetEditor).equals(documentID))
{
return false;
}
ITextSelection textSelection = (ITextSelection)jetEditor.getSelectionProvider().getSelection();
if (textSelection.getOffset() == position.offset && textSelection.getLength() == position.length)
{
String text = textSelection.getText();
if (text != null)
{
try
{
return text.equals(document.get(position.offset, position.length));
}
catch (BadLocationException exception)
{
}
}
}
return false;
}
public void update()
{
IEditorPart part = getEditorPart();
if (part instanceof JETEditor)
{
JETEditor textEditor = (JETEditor)part;
if (!samePosition(textEditor))
{
ITextSelection selection = (ITextSelection)textEditor.getSelectionProvider().getSelection();
if (selection.getOffset() != 0 || selection.getLength() != 0)
{
position.offset = selection.getOffset();
position.length = selection.getLength();
position.isDeleted = false;
if (!part.isDirty())
{
savedPosition = new Position(position.offset, position.length);
}
}
}
}
}
@Override
public String toString()
{
return "Selection<" + position + ">";
}
}
static class JETDynamicCompilerJob extends Job implements IDocumentListener
{
private final JETEditor jetEditor;
private final IFile file;
private volatile boolean disabled;
public JETDynamicCompilerJob(JETEditor jetEditor, IFile file)
{
super("JET Dynamic Compiler");
setSystem(true);
this.jetEditor = jetEditor;
this.file = file;
}
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
if (disabled)
{
cancel();
}
else
{
documentChanged(null);
}
}
@Override
protected IStatus run(IProgressMonitor monitor)
{
if (!disabled)
{
try
{
final WorkingCopyCompilationMonitor compilationMonitor = new WorkingCopyCompilationMonitor();
JETCompileTemplateOperation jetCompileTemplateOperation = new JETCompileTemplateOperation(file, compilationMonitor)
{
@Override
public void run(IProgressMonitor progressMonitor) throws CoreException
{
if (files.isEmpty())
{
files.add(file);
}
super.run(progressMonitor);
}
};
long startTime = System.currentTimeMillis();
jetCompileTemplateOperation.run(monitor);
if (!monitor.isCanceled())
{
final JETCompilationUnit compilerResult = compilationMonitor.getResult();
if (compilerResult != null)
{
JETNature nature = jetEditor.getJETNature();
IContainer sourceContainer = nature.getJavaSourceContainer();
IProject project = sourceContainer.getProject();
IJavaProject javaProject = JavaCore.create(project);
String className = compilerResult.getClassName();
final IFile javaFile = sourceContainer.getFile(new Path(className.replace('.', '/') + ".java"));
ICompilationUnit compilationUnit = JavaCore.createCompilationUnitFrom(javaFile);
LocalWorkingCopy localWorkingCopy = new LocalWorkingCopy(compilerResult.getJavaCompilationUnit());
ICompilationUnit workingCopy = compilationUnit.getWorkingCopy(localWorkingCopy, null);
ASTParser astParser = CodeGenUtil.EclipseUtil.newASTParser(true);
String fileExtension = file.getFileExtension();
if (fileExtension != null && fileExtension.endsWith("jet"))
{
astParser.setResolveBindings(true);
}
astParser.setProject(javaProject);
ASTRequestor astRequestor = new ASTRequestor()
{
@Override
public void acceptAST(ICompilationUnit sourceUnit, CompilationUnit compiledUnit)
{
IProblem[] problems = compiledUnit.getProblems();
JETCompilerResult jetCompilerResult = new JETCompilerResult(javaFile, compilerResult, Arrays.asList(problems), compilationMonitor.getException());
handleJavaResult(jetCompilerResult);
}
};
astParser.createASTs(new ICompilationUnit []{ workingCopy }, new String [0], astRequestor, null);
}
else if (compilationMonitor.getException() != null)
{
JETCompilerResult jetCompilerResult = new JETCompilerResult(compilationMonitor.getException());
handleJavaResult(jetCompilerResult);
}
}
long stop = System.currentTimeMillis();
if (trace)
{
System.out.println("elapsed=" + (stop - startTime));
}
}
catch (CoreException exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
return Status.OK_STATUS;
}
private void handleJavaResult(final JETCompilerResult jetCompilerResult)
{
if (!disabled)
{
jetEditor.handleCompilerResult(jetCompilerResult);
}
}
public void documentAboutToBeChanged(DocumentEvent event)
{
if (!disabled)
{
cancel();
}
}
public void documentChanged(DocumentEvent event)
{
if (!disabled)
{
jetEditor.resetExpectedModificationStamp();
schedule(100);
}
}
}
static class JETCompilerResult
{
private final IFile javaFile;
private final JETCompilationUnit compilationUnit;
private final List<IProblem> javaProblems;
private final JETException jetException;
private final Map<Integer, List<JETProblemAnnotation>> problemAnnotations = new HashMap<Integer, List<JETProblemAnnotation>>();
public JETCompilerResult(IFile javaFile, JETCompilationUnit compilationUnit, List<IProblem> javaProblems, JETException jetException)
{
this.javaFile = javaFile;
this.compilationUnit = compilationUnit;
this.javaProblems = javaProblems;
this.jetException = jetException;
}
public JETCompilerResult(JETException jetException)
{
this.javaFile = null;
this.compilationUnit = null;
this.javaProblems = Collections.emptyList();
this.jetException = jetException;
}
public IFile getJavaFile()
{
return javaFile;
}
public JETException getJETException()
{
return jetException;
}
public List<IProblem> getJavaProblems()
{
return javaProblems;
}
public JETCompilationUnit getCompilationUnit()
{
return compilationUnit;
}
public List<JETProblemAnnotation> getProblem(JETItem jetItem)
{
int fileID = jetItem.getFileID();
List<JETProblemAnnotation> allProblems = getProblems(fileID);
if (!allProblems.isEmpty())
{
List<JETProblemAnnotation> result = new ArrayList<JETProblemAnnotation>();
int startOffset = jetItem.getStartOffset();
int stopOffset = jetItem.getStopOffset();
for (JETProblemAnnotation problem : allProblems)
{
Position position = problem.getPosition();
if (stopOffset > position.offset && startOffset < position.offset + position.length)
{
result.add(problem);
}
}
return result;
}
else
{
return Collections.emptyList();
}
}
public List<JETProblemAnnotation> getProblems(int fileID)
{
if (fileID < 0)
{
JETProblemAnnotation jetOrphanProblemAnnotation = new JETProblemAnnotation(IMarker.SEVERITY_WARNING, "This file is no longer included by the template", new Position(0, 0));
return Collections.singletonList(jetOrphanProblemAnnotation);
}
else
{
List<JETProblemAnnotation> jetProblemAnnotations = problemAnnotations.get(fileID);
if (jetProblemAnnotations == null)
{
jetProblemAnnotations = new ArrayList<JETProblemAnnotation>();
JETException jetException = getJETException();
if (jetException != null)
{
JETProblemAnnotation jetExceptionProblemAnnotation = getExceptionProblem(fileID, jetException);
if (jetExceptionProblemAnnotation != null)
{
jetProblemAnnotations.add(jetExceptionProblemAnnotation);
}
}
JETCompilationUnit result = getCompilationUnit();
if (compilationUnit != null)
{
List<JETException> jetProblems = result.getProblems();
for (JETException jetProblem : jetProblems)
{
JETProblemAnnotation jetExceptionProblemAnnotation = getExceptionProblem(fileID, jetProblem);
if (jetExceptionProblemAnnotation != null)
{
jetProblemAnnotations.add(jetExceptionProblemAnnotation);
}
}
List<IProblem> javaProblems = getJavaProblems();
for (IProblem problem : javaProblems)
{
int start = problem.getSourceStart();
int end = problem.getSourceEnd() + 1;
int[] correspondingTemplatePoint = result.getClosestCorrespondingTemplatePoint(fileID, start, end == 0 ? 0 : end - start);
if (correspondingTemplatePoint != null)
{
String message = problem.getMessage();
JETProblemAnnotation jetProblemAnnotation = new JETProblemAnnotation(
problem.isError() ? IMarker.SEVERITY_ERROR : problem.isWarning() ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_INFO,
message,
new Position(correspondingTemplatePoint[0], correspondingTemplatePoint[1]));
jetProblemAnnotations.add(jetProblemAnnotation);
}
}
}
}
problemAnnotations.put(fileID, jetProblemAnnotations);
return jetProblemAnnotations;
}
}
protected JETProblemAnnotation getExceptionProblem(int fileID, JETException exception)
{
int offset = -1;
int length = 0;
boolean locatedInThisFile = false;
for (JETMark start = exception.getStart(); start != null; start = start.getParentMark())
{
if (start.getFileId() == fileID)
{
offset = start.getCursor();
JETMark stop = exception.getStop();
locatedInThisFile = stop.getFileId() == fileID;
if (locatedInThisFile)
{
length = stop.getCursor() - offset;
}
break;
}
}
if (offset == -1)
{
String message = exception.getLocalizedMessage();
int severity = exception.getDiagnostic().getSeverity();
int problemSeverity = severity == Diagnostic.INFO ? IMarker.SEVERITY_INFO : severity == Diagnostic.WARNING ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR;
JETProblemAnnotation jetProblemAnnotation = new JETProblemAnnotation(problemSeverity, message, new Position(0, length));
return jetProblemAnnotation;
}
else
{
String message = exception.getLocalizedMessage();
if (locatedInThisFile)
{
int index = message.indexOf(" in ");
if (index != -1)
{
message = message.substring(0, index);
}
}
int severity = exception.getDiagnostic().getSeverity();
int problemSeverity = severity == Diagnostic.INFO ? IMarker.SEVERITY_INFO : severity == Diagnostic.WARNING ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR;
JETProblemAnnotation jetProblemAnnotation = new JETProblemAnnotation(problemSeverity, message, new Position(offset, length));
return jetProblemAnnotation;
}
}
}
static class VisibleCaretHandler extends FocusAdapter implements PaintListener
{
private final StyledText styledText;
private final StyledText otherStyledText;
public VisibleCaretHandler(StyledText styledText, StyledText otherStyledText)
{
this.styledText = styledText;
this.otherStyledText = otherStyledText;
styledText.addFocusListener(this);
otherStyledText.addFocusListener(this);
styledText.addPaintListener(this);
}
@Override
public void focusGained(FocusEvent event)
{
Rectangle caretBounds = getCaretBounds();
styledText.redraw(caretBounds.x, caretBounds.y, caretBounds.width, caretBounds.height, false);
}
@Override
public void focusLost(FocusEvent event)
{
Rectangle caretBounds = getCaretBounds();
styledText.redraw(caretBounds.x, caretBounds.y, caretBounds.width, caretBounds.height, false);
}
public void paintControl(PaintEvent event)
{
if (!styledText.isFocusControl() && otherStyledText.isFocusControl())
{
Color background = event.gc.getBackground();
event.gc.setBackground(ColorManager.INSTANCE.getBlendedColor(ColorManager.INSTANCE.getForeground(JETDirectiveRule.TOKEN.getType()), background));
Rectangle caretBounds = getCaretBounds();
event.gc.fillRectangle(caretBounds);
event.gc.setBackground(background);
}
}
private Rectangle getCaretBounds()
{
return styledText.getCaret().getBounds();
}
}
static class SelectEnclosingJETElementAction extends Action
{
private JETEditor jetEditor;
public SelectEnclosingJETElementAction(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
@Override
public void run()
{
ISourceViewer sourceViewer = jetEditor.getSourceViewer();
Point selectedRange = sourceViewer.getSelectedRange();
JETItem startItem = jetEditor.getJETItem(selectedRange.x, false);
JETItem stopItem = jetEditor.getJETItem(selectedRange.x + selectedRange.y, false);
if (startItem != null)
{
Point startRange = getRange(startItem);
int offset = startRange.x;
int end = startRange.x + startRange.y;
if (stopItem != null)
{
Point stopRange = getRange(stopItem);
end = stopRange.x + stopRange.y;
}
jetEditor.selectAndReveal(offset, end - offset);
}
}
private Point getRange(JETItem jetItem)
{
if (jetItem instanceof JETScriptletItem || jetItem instanceof JETExpressionItem || jetItem instanceof JETCommentItem)
{
Point tokenRange = jetEditor.getTokenRangeAt(jetItem.getStartOffset());
if (tokenRange != null)
{
return tokenRange;
}
}
int start = jetItem.getStartOffset();
int stop = jetItem.getStopOffset();
return new Point(start, stop - start);
}
}
static abstract class JETAbstractBaseAction extends Action
{
protected final JETEditor jetEditor;
public JETAbstractBaseAction(JETEditor jetEditor, String text, ImageDescriptor imageDescriptor)
{
super(text, imageDescriptor);
this.jetEditor = jetEditor;
}
@Override
public void run()
{
SourceViewer jetSourceViewer = jetEditor.getJETSourceViewer();
final IDocument jetDocument = jetSourceViewer.getDocument();
final SourceViewer javaSourceViewer = jetEditor.getJavaSourceViewer();
IDocument javaDocument = javaSourceViewer.getDocument();
JETCompilationUnit compilationUnit = jetEditor.getCompilationUnit();
List<JETJavaItem> javaItems = compilationUnit.getJavaItems(jetEditor.getFileID());
List<TrackedPosition> jetPositions = new ArrayList<TrackedPosition>(javaItems.size());
try
{
for (JETJavaItem jetJavaItem : javaItems)
{
if (jetJavaItem instanceof JETScriptletItem || jetJavaItem instanceof JETExpressionItem)
{
TrackedPosition jetPosition = new TrackedPosition(TrackedPosition.Type.JET);
jetPosition.addToDocument(jetDocument);
jetPosition.update(jetJavaItem);
TrackedPosition javaPosition = new TrackedPosition(TrackedPosition.Type.JAVA);
javaPosition.addToDocument(javaDocument);
javaPosition.update(jetJavaItem);
jetPosition.setOpposite(javaPosition);
jetPositions.add(jetPosition);
}
}
JavaDocumentTransaction javaDocumentTransaction = new JavaDocumentTransaction(jetEditor, jetPositions, isTransformBraces(), isIgnoreOutOfScopeChanges())
{
@Override
protected void start()
{
DocumentRewriteSessionType documentRewriteSessionType = getDocumentRewriteSessionType();
if (documentRewriteSessionType != null)
{
startDocumentRewriteSession(javaSourceViewer, documentRewriteSessionType, isRememberSelection());
}
JETAbstractBaseAction.this.start();
}
@Override
protected void postCommit(List<TrackedPosition> jetPositions)
{
postProcess(jetDocument, jetPositions);
}
@Override
protected void stop()
{
for (TrackedPosition jetPosition : jetPositions)
{
TrackedPosition javaPosition = jetPosition.getOpposite();
jetPosition.dispose();
javaPosition.dispose();
}
JETAbstractBaseAction.this.stop();
DocumentRewriteSessionType documentRewriteSessionType = getDocumentRewriteSessionType();
if (documentRewriteSessionType != null)
{
stopDocumentRewriteSession(javaSourceViewer, isRememberSelection());
}
}
};
javaDocumentTransaction.modify(javaDocument, new SneakyRunnable()
{
@Override
public void execute() throws Exception
{
doRun();
}
});
jetEditor.openDialog(getText().replace("&", "") + " Failure", javaDocumentTransaction.getStatus());
}
catch (Exception exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
protected DocumentRewriteSessionType getDocumentRewriteSessionType()
{
return null;
}
protected boolean isRememberSelection()
{
return getDocumentRewriteSessionType() != null;
}
protected boolean isTransformBraces()
{
return false;
}
boolean isIgnoreOutOfScopeChanges()
{
return false;
}
protected void start()
{
}
protected abstract void doRun() throws Exception;
protected void postProcess(IDocument jetDocument, List<TrackedPosition> jetPositions)
{
}
protected void stop()
{
}
}
static class JETExtractLocalVariableAction extends JETAbstractBaseAction
{
private final IAction javaAction;
public JETExtractLocalVariableAction(JETEditor jetEditor, IAction javaAction)
{
super(jetEditor, javaAction.getText(), javaAction.getImageDescriptor());
this.javaAction = javaAction;
setActionDefinitionId(javaAction.getActionDefinitionId());
}
@Override
protected void doRun()
{
javaAction.run();
}
}
static class JETRenameLocalVariableAction extends JETAbstractBaseAction
{
public JETRenameLocalVariableAction(JETEditor jetEditor)
{
super(jetEditor, "Re&name...", null);
setActionDefinitionId(RENAME_COMMAND_ID);
}
@Override
protected void doRun() throws Exception
{
IJavaElement[] selectedElements = jetEditor.getJavaEditor().getSelectedElements();
if (selectedElements != null)
{
for (IJavaElement element : selectedElements)
{
if (element instanceof ILocalVariable)
{
ILocalVariable localVariable = (ILocalVariable)element;
RenameSupport renameLocalVariableSupport = RenameSupport.create(localVariable, localVariable.getElementName(), RenameSupport.UPDATE_REFERENCES);
renameLocalVariableSupport.openDialog(jetEditor.getSite().getShell());
return;
}
}
}
throw new CoreException(new Status(IStatus.ERROR, CodeGenUIPlugin.getPlugin().getBundle().getSymbolicName(), "A local variable must be selected"));
}
}
static class JETFormatAction extends JETAbstractBaseAction
{
public JETFormatAction(JETEditor jetEditor)
{
super(jetEditor, "&Format", null);
setActionDefinitionId(FORMAT_COMMAND_ID);
}
@Override
protected DocumentRewriteSessionType getDocumentRewriteSessionType()
{
return DocumentRewriteSessionType.UNRESTRICTED;
}
@Override
boolean isIgnoreOutOfScopeChanges()
{
return true;
}
@Override
protected void start()
{
}
@Override
protected void stop()
{
jetEditor.waitForCompilerResult(1000);
}
@Override
protected void doRun() throws Exception
{
IJavaProject javaProject = JavaCore.create(jetEditor.getJETNature().getProject());
Map<String, String> options = javaProject.getOptions(true);
for (Map.Entry<String, String> entry : options.entrySet())
{
String key = entry.getKey();
if (key.contains(".formatter.brace_position_for"))
{
entry.setValue(DefaultCodeFormatterConstants.END_OF_LINE);
}
}
options.put(JavaCore.PLUGIN_ID + ".formatter.align_with_spaces", DefaultCodeFormatterConstants.TRUE);
options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE);
options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "2");
options.put(DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE, "2");
options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT, DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_ELSE_STATEMENT_ON_SAME_LINE, DefaultCodeFormatterConstants.TRUE);
options.put(DefaultCodeFormatterConstants.FORMATTER_COMPACT_ELSE_IF, DefaultCodeFormatterConstants.TRUE);
CodeFormatter codeFormatter = ToolFactory.createCodeFormatter(options);
JavaEditor javaEditor = jetEditor.getJavaEditor();
IDocument document = javaEditor.getJavaSourceViewer().getDocument();
String source = document.get();
TextEdit edit = ((CodeFormatter)codeFormatter).format(
CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS,
source,
0,
source.length(),
0,
TextUtilities.getDefaultLineDelimiter(document));
if (edit != null)
{
edit.apply(document);
}
}
@Override
protected void postProcess(IDocument jetDocument, List<TrackedPosition> jetPositions)
{
IDocument javaDocument = jetEditor.getJavaSourceViewer().getDocument();
MultiTextEdit multiTextEdit = new MultiTextEdit();
List<JETRootItem> rootItems = JETParser.parseRootItems(jetDocument.get());
for (JETRootItem jetRootItem : rootItems)
{
int start = jetRootItem.getStartOffset();
int stop = jetRootItem.getStopOffset();
if (jetRootItem instanceof JETScriptletItem)
{
JETScriptletItem jetScriptletItem = (JETScriptletItem)jetRootItem;
String body = jetScriptletItem.getText();
reformatScriptletBody(jetDocument, jetPositions, javaDocument, multiTextEdit, start, stop, body);
}
else if (jetRootItem instanceof JETDirectiveItem)
{
JETDirectiveItem jetDirectiveItem = (JETDirectiveItem)jetRootItem;
String directive = jetDirectiveItem.getText();
String directiveName = jetDirectiveItem.getNameItem().getText();
if (!directiveName.isEmpty() && Character.isUpperCase(directiveName.codePointAt(0)))
{
multiTextEdit.addChild(new ReplaceEdit(start + 2, 0, " "));
reformatScriptletBody(jetDocument, jetPositions, javaDocument, multiTextEdit, start + 2, stop - 2, directive.substring(2, directive.length() - 2));
}
else
{
reformatDirective(jetDocument, multiTextEdit, start, stop, directiveName, directive, jetDirectiveItem);
}
}
}
stripTrailingWhitespace(jetDocument, multiTextEdit);
if (multiTextEdit.hasChildren())
{
try
{
multiTextEdit.apply(jetDocument);
// As a second pass, to avoid overlapping edits, we correct the indentation of lines within the scriptlet bodies.
multiTextEdit = new MultiTextEdit();
rootItems = JETParser.parseRootItems(jetDocument.get());
for (JETRootItem jetRootItem : rootItems)
{
if (jetRootItem instanceof JETScriptletItem)
{
int start = jetRootItem.getStartOffset();
int stop = jetRootItem.getStopOffset();
try
{
// Subsequent line starts within the scriptlet will simply have 2 spaces too much indentation.
// Actually 4 because that's the generate method body's indentation,
// but in order to line up with the start of the scriptlet, which has <% in it, it will have 2 too many.
int lineOffset;
for (int i = jetDocument.getLineOfOffset(start) + 1; (lineOffset = jetDocument.getLineOffset(i)) < stop; ++i)
{
if (jetDocument.getChar(lineOffset) == ' ' && jetDocument.getChar(lineOffset + 1) == ' ')
{
multiTextEdit.addChild(new ReplaceEdit(lineOffset, 2, ""));
}
}
}
catch (BadLocationException exception)
{
}
}
}
if (multiTextEdit.hasChildren())
{
multiTextEdit.apply(jetDocument);
}
}
catch (Exception exception)
{
}
}
}
private static final Map<String, String[]> JET_DIRECTIVE_ORDERED_ATTRIBUTES = new HashMap<String, String[]>();
static
{
JET_DIRECTIVE_ORDERED_ATTRIBUTES.put("jet", new String []{ "package", "class", "imports", "builder", "nlString", "minimize", "skeleton", "version" });
JET_DIRECTIVE_ORDERED_ATTRIBUTES.put("include", new String []{ "file", "fail" });
}
private void reformatDirective(
IDocument jetDocument,
MultiTextEdit multiTextEdit,
int start,
int stop,
String directiveName,
String directive,
JETDirectiveItem jetDirectiveItem)
{
StringBuilder result = new StringBuilder();
result.append(directiveName);
boolean isMultiLine = directive.contains("\n");
String lineDelimiter = TextUtilities.getDefaultLineDelimiter(jetDocument);
JETAttributeListItem attributes = jetDirectiveItem.getAttributes();
List<JETAttributeItem> items = new ArrayList<JETAttributeItem>(attributes.getAttributes());
String[] orderedAttributes = JET_DIRECTIVE_ORDERED_ATTRIBUTES.get(directiveName);
if (orderedAttributes != null)
{
for (int i = orderedAttributes.length; --i >= 0;)
{
JETAttributeItem attribute = attributes.getAttribute(orderedAttributes[i]);
if (items.remove(attribute))
{
items.add(0, attribute);
}
}
}
for (JETAttributeItem jetAttributeItem : items)
{
if (isMultiLine)
{
result.append(lineDelimiter);
result.append(" ");
}
else if (result.length() != 0)
{
result.append(' ');
}
String nameText = jetAttributeItem.getNameToken().getText();
result.append(nameText);
result.append('=');
JETTokenItem valueToken = jetAttributeItem.getValueToken();
String valueText = valueToken.getText();
if ("imports".equals(nameText))
{
char quote = valueText.length() == 0 ? '"' : valueText.charAt(0);
boolean isMultiLineImport = valueText.contains("\n");
if (isMultiLineImport)
{
result.append(lineDelimiter).append(" ");
}
result.append(quote);
List<String> imports = sortImports(valueToken);
int count = 0;
for (String importedName : imports)
{
if (isMultiLineImport)
{
result.append(lineDelimiter).append(" ");
}
else if (count++ != 0)
{
result.append(' ');
}
result.append(importedName);
}
if (isMultiLineImport)
{
result.append(lineDelimiter).append(" ");
}
result.append(quote);
}
else
{
result.append(valueText);
}
}
multiTextEdit.addChild(new ReplaceEdit(start + 3, stop - start - 5, result.toString()));
}
private static final Comparator<SegmentSequence> COMPARATOR = new Comparator<SegmentSequence>()
{
Comparator<String> comparator = CommonPlugin.INSTANCE.getComparator();
public int compare(SegmentSequence o1, SegmentSequence o2)
{
int count1 = o1.segmentCount();
int count2 = o2.segmentCount();
for (int i = 0; i < count1 && i < count2; ++i)
{
int comparision = comparator.compare(o1.segment(i), o2.segment(i));
if (comparision != 0)
{
return comparision;
}
}
return count1 == count2 ? 0 : count1 < count2 ? -1 : 1;
}
};
private List<String> sortImports(JETTokenItem imports)
{
Set<SegmentSequence> importedNames = new TreeSet<SegmentSequence>(COMPARATOR);
for (JETValueElementItem jetValueElementItem : imports.getValueItem().getElements())
{
importedNames.add(SegmentSequence.create(".", jetValueElementItem.getText()));
}
List<String> result = new ArrayList<String>();
for (SegmentSequence name : importedNames)
{
result.add(name.toString());
}
return result;
}
protected void stripTrailingWhitespace(IDocument jetDocument, MultiTextEdit multiTextEdit)
{
try
{
int numberOfLines = jetDocument.getNumberOfLines();
for (int i = 0; i < numberOfLines; ++i)
{
int lineOffset = jetDocument.getLineOffset(i);
int lineLength = jetDocument.getLineLength(i);
String lineDelimiter = jetDocument.getLineDelimiter(i);
int lineDelimiterLength = lineDelimiter == null ? 0 : lineDelimiter.length();
int count = 0;
for (int j = lineOffset + lineLength - lineDelimiterLength - 1; j >= 0; --j)
{
char character = jetDocument.getChar(j);
if (character == ' ' || character == '\t')
{
++count;
}
else
{
break;
}
}
if (count > 0)
{
try
{
multiTextEdit.addChild(new ReplaceEdit(lineOffset + lineLength - lineDelimiterLength - count, count, ""));
}
catch (MalformedTreeException exception)
{
// These can and do happen because the directives are formatted to already eliminate trailing whitespace.
}
}
}
}
catch (BadLocationException e)
{
// Can't happen.
}
}
protected TrackedPosition getTrackedPosition(List<TrackedPosition> positions, int offset)
{
for (Position position : positions)
{
if (position.overlapsWith(offset, 0))
{
return (TrackedPosition)position;
}
}
return null;
}
protected void reformatScriptletBody(
IDocument jetDocument,
List<TrackedPosition> positions,
IDocument javaDocument,
MultiTextEdit multiTextEdit,
int start,
int stop,
String body)
{
// Trim any whitespace including the line feed at the end of the body.
int trim = -1;
int length = body.length();
for (int i = length; --i >= 0;)
{
if (Character.isWhitespace(body.charAt(i)))
{
trim = i;
}
else
{
break;
}
}
if (trim != -1)
{
multiTextEdit.addChild(new ReplaceEdit(start + trim, length - trim, ""));
}
// Compute the indentation for the scriptlet based on the indentation of the corresponding Java.
TrackedPosition jetPosition = getTrackedPosition(positions, start);
if (jetPosition != null)
{
TrackedPosition javaPosition = jetPosition.getOpposite();
int jetIndentation = computeIndentation(jetDocument, jetPosition.offset - 2);
if (jetIndentation != -1)
{
int javaIndentation = computeIndentation(javaDocument, javaPosition.offset);
if (javaIndentation >= 4)
{
// The body of the generate method is expected to be at an indentation level of 4 spaces.
int baseJavaIndentation = javaIndentation - 4;
int delta = baseJavaIndentation - jetIndentation;
if (delta > 0)
{
StringBuilder spaces = new StringBuilder();
for (int i = 0; i < delta; ++i)
{
spaces.append(' ');
}
multiTextEdit.addChild(new ReplaceEdit(start - 2, 0, spaces.toString()));
}
else if (delta < 0)
{
multiTextEdit.addChild(new ReplaceEdit(start + delta - 2, -delta, ""));
}
}
}
}
}
protected int computeIndentation(IDocument document, int offset)
{
int indent = 0;
for (int i = offset; --i >= 0;)
{
try
{
char character = document.getChar(i);
if (character == ' ')
{
++indent;
}
else if (character == '\n')
{
break;
}
else
{
return -1;
}
}
catch (BadLocationException exception)
{
}
}
return indent;
}
}
static class WorkingCopyCompilationMonitor extends JETCompileTemplateOperation.JETCompilationMonitor
{
@Override
public InputStream openInputStream(String locationURI) throws JETException
{
URI uri = URI.createURI(locationURI);
if (uri.isPlatformResource())
{
IPath fullPath = new Path(uri.toPlatformString(true));
ITextFileBuffer buffer = ITextFileBufferManager.DEFAULT.getTextFileBuffer(fullPath, LocationKind.IFILE);
if (buffer != null)
{
IDocument document = buffer.getDocument();
String contents = document.get();
try
{
return new ByteArrayInputStream(contents.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException exception)
{
// UTF-8 is always supported.
}
}
}
return super.openInputStream(locationURI);
}
}
static class LocalWorkingCopy extends WorkingCopyOwner
{
private String contents;
public LocalWorkingCopy(String contents)
{
this.contents = contents;
}
@Override
public IBuffer createBuffer(final ICompilationUnit workingCopy)
{
return new IBuffer()
{
public IOpenable getOwner()
{
return workingCopy;
}
public String getText(int offset, int length) throws IndexOutOfBoundsException
{
return contents.substring(offset, offset + length);
}
public int getLength()
{
return contents.length();
}
public String getContents()
{
return contents;
}
public char[] getCharacters()
{
return contents.toCharArray();
}
public char getChar(int position)
{
return contents.charAt(position);
}
public boolean isReadOnly()
{
return true;
}
public boolean isClosed()
{
return false;
}
public boolean hasUnsavedChanges()
{
return false;
}
public IResource getUnderlyingResource()
{
return null;
}
public void close()
{
}
public void save(IProgressMonitor progress, boolean force) throws JavaModelException
{
throw new UnsupportedOperationException();
}
public void setContents(String contents)
{
throw new UnsupportedOperationException();
}
public void setContents(char[] contents)
{
throw new UnsupportedOperationException();
}
public void replace(int position, int length, String text)
{
throw new UnsupportedOperationException();
}
public void replace(int position, int length, char[] text)
{
throw new UnsupportedOperationException();
}
public void append(String text)
{
throw new UnsupportedOperationException();
}
public void append(char[] text)
{
throw new UnsupportedOperationException();
}
public void addBufferChangedListener(IBufferChangedListener listener)
{
}
public void removeBufferChangedListener(IBufferChangedListener listener)
{
}
};
}
}
static final class StorageEditorInput extends PlatformObject implements IStorageEditorInput, IPathEditorInput, IURIEditorInput
{
private final URLStorage storage;
public StorageEditorInput(URI uri)
{
this(uri, null, null);
}
public StorageEditorInput(URI uri, String contents, String encoding)
{
storage = new URLStorage(uri, contents, encoding == null ? "UTF-8" : encoding);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getAdapter(Class adapter)
{
return storage.getAdapter(adapter);
}
public boolean exists()
{
return storage.exists();
}
public ImageDescriptor getImageDescriptor()
{
IEditorRegistry registry = PlatformUI.getWorkbench().getEditorRegistry();
return registry.getImageDescriptor(storage.uri.fileExtension());
}
public String getName()
{
return storage.uri.lastSegment();
}
public IPersistableElement getPersistable()
{
return null;
}
public String getToolTipText()
{
return storage.uri.toString();
}
public IEncodedStorage getStorage() throws CoreException
{
return storage;
}
public java.net.URI getURI()
{
try
{
URI resolvedURI = JETNature.resolve(storage.uri);
return new java.net.URI(resolvedURI.toString());
}
catch (URISyntaxException exception)
{
throw new RuntimeException(exception);
}
}
public IPath getPath()
{
IPath path = storage.getFullPath();
return path == null ? new Path("") : path;
}
public IFile getFile()
{
return (IFile)storage.getAdapter(IFile.class);
}
@Override
public String toString()
{
return storage.toString();
}
@Override
public int hashCode()
{
return storage.hashCode();
}
@Override
public boolean equals(Object that)
{
if (this == that)
{
return true;
}
else if (that == null || that.getClass() != StorageEditorInput.class)
{
return false;
}
else
{
StorageEditorInput other = (StorageEditorInput)that;
return storage == null ? other.storage == null : storage.equals(other.storage);
}
}
private static final class URLStorage extends PlatformObject implements IEncodedStorage
{
private final URI uri;
private final String contents;
private final String encoding;
public URLStorage(URI uri, String contents, String encoding)
{
this.uri = uri;
this.contents = contents;
this.encoding = encoding;
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getAdapter(Class adapter)
{
if (adapter == IFile.class)
{
IFile file = toFile(uri);
if (file != null)
{
return file;
}
}
return super.getAdapter(adapter);
}
public boolean exists()
{
try
{
if (contents == null)
{
getContents().close();
}
return true;
}
catch (Exception exception)
{
return false;
}
}
public InputStream getContents() throws CoreException
{
try
{
if (contents == null)
{
return new URL(uri.toString()).openStream();
}
else
{
return new ByteArrayInputStream(contents.getBytes(encoding == null ? "UTF-8" : encoding));
}
}
catch (Exception exception)
{
throw new CoreException(new Status(IStatus.ERROR, CodeGenPlugin.ID, exception.getLocalizedMessage(), exception));
}
}
public IPath getFullPath()
{
if (uri.isPlatformResource())
{
return new Path(uri.toPlatformString(true));
}
if (uri.isFile())
{
return new Path(uri.toFileString());
}
return null;
}
public String getName()
{
return uri.lastSegment();
}
public boolean isReadOnly()
{
return true;
}
public String getCharset() throws CoreException
{
return encoding;
}
@Override
public int hashCode()
{
return uri == null ? 0 : uri.hashCode();
}
@Override
public boolean equals(Object that)
{
if (this == that)
{
return true;
}
else if (that == null || that.getClass() != URLStorage.class)
{
return false;
}
else
{
URLStorage other = (URLStorage)that;
return uri == null ? other.uri == null : uri.equals(other.uri);
}
}
@Override
public String toString()
{
return String.valueOf(uri);
}
}
}
static class JavaEditorInput extends FileEditorInput
{
private boolean isConnected;
private boolean isWorkingCopy;
private ICompilationUnit workingCopy;
public JavaEditorInput(IFile file, String content)
{
super(file);
try
{
IPath path = file.getFullPath();
FileBuffers.getTextFileBufferManager().connect(path, LocationKind.IFILE, new NullProgressMonitor());
isConnected = true;
ITextFileBuffer textFileBuffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(path, LocationKind.IFILE);
if (textFileBuffer instanceof IStateValidationSupport)
{
((IStateValidationSupport)textFileBuffer).validationStateChanged(true, Status.OK_STATUS);
}
IDocument document = textFileBuffer.getDocument();
document.set(content);
}
catch (CoreException exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
public synchronized ITypeRoot getWorkingCopy(ITypeRoot inputJavaElement)
{
if (!isWorkingCopy && inputJavaElement instanceof ICompilationUnit)
{
try
{
ICompilationUnit workingCopy = (ICompilationUnit)inputJavaElement;
workingCopy.becomeWorkingCopy(new NullProgressMonitor());
this.workingCopy = workingCopy;
isWorkingCopy = true;
}
catch (JavaModelException exception)
{
isWorkingCopy = true;
CodeGenUIPlugin.getPlugin().log(exception);
}
}
return inputJavaElement;
}
public void releaseWorkingCopy()
{
if (workingCopy != null)
{
try
{
workingCopy.discardWorkingCopy();
}
catch (JavaModelException exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
}
public void release()
{
if (isConnected)
{
IPath path = getFile().getFullPath();
try
{
FileBuffers.getTextFileBufferManager().disconnect(path, LocationKind.IFILE, new NullProgressMonitor());
}
catch (CoreException exception)
{
CodeGenUIPlugin.getPlugin().log(exception);
}
}
}
}
@SuppressWarnings("restriction")
static final class JavaEditor extends org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor
{
static final Map<String, String> SELECTION_ACTIONS = new LinkedHashMap<String, String>();
static
{
SELECTION_ACTIONS.put(org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction.ENCLOSING, IJavaEditorActionDefinitionIds.SELECT_ENCLOSING);
SELECTION_ACTIONS.put(org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction.NEXT, IJavaEditorActionDefinitionIds.SELECT_NEXT);
SELECTION_ACTIONS.put(org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction.PREVIOUS, IJavaEditorActionDefinitionIds.SELECT_PREVIOUS);
SELECTION_ACTIONS.put(org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction.HISTORY, IJavaEditorActionDefinitionIds.SELECT_LAST);
}
private final JETEditor jetEditor;
private boolean navigating;
private IAction openDeclarationAction;
private DefaultCharacterPairMatcher bracketMatcher;
public JavaEditor(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
setDocumentProvider(new StatusFilteringForwardingDocumentProvider(getDocumentProvider()));
}
SourceViewer getJavaSourceViewer()
{
return (SourceViewer)getSourceViewer();
}
@Override
public IAction getAction(String actionID)
{
if ("OpenEditor".equals(actionID))
{
return getOpenDeclarationAction();
}
final IAction action = super.getAction(actionID);
String actionDefinitionID = SELECTION_ACTIONS.get(actionID);
if (actionDefinitionID != null)
{
return new Action(action.getText(), action.getStyle())
{
@Override
public void run()
{
try
{
navigating = true;
action.run();
jetEditor.selectionSynchronizer.sync(getJavaSourceViewer());
}
finally
{
navigating = false;
}
}
};
}
else if (EXTRACT_LOCAL_VARIABLE_ACTION_ID.equals(actionID))
{
return new JETExtractLocalVariableAction(jetEditor, action);
}
else
{
return action;
}
}
IJavaElement[] getSelectedElements()
{
ITypeRoot inputJavaElement = getInputJavaElement();
Point selectedRange = getJavaSourceViewer().getSelectedRange();
try
{
return inputJavaElement.codeSelect(selectedRange.x, selectedRange.y);
}
catch (JavaModelException e)
{
return null;
}
}
DefaultCharacterPairMatcher getJavaBracketMatcher()
{
if (bracketMatcher == null)
{
try
{
Field field = org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.class.getDeclaredField("fBracketMatcher");
field.setAccessible(true);
bracketMatcher = (DefaultCharacterPairMatcher)field.get(this);
}
catch (Exception exception)
{
}
}
return bracketMatcher;
}
IHyperlinkDetector[] getHyperlinkDetectors()
{
IHyperlinkDetector[] hyperlinkDetectors = getSourceViewerConfiguration().getHyperlinkDetectors(getSourceViewer());
return hyperlinkDetectors;
}
boolean isNavigating()
{
return navigating;
}
IAction getOpenDeclarationAction()
{
if (openDeclarationAction == null)
{
openDeclarationAction = new OpenAction(this)
{
@Override
public void run(Object[] elements)
{
IFileEditorInput editorInput = (IFileEditorInput)getEditorInput();
IPath editorInputPath = editorInput.getFile().getFullPath();
for (Object element : elements)
{
if (element instanceof IJavaElement)
{
IPath path = ((IJavaElement)element).getPath();
if (editorInputPath.equals(path))
{
try
{
navigating = true;
JavaUI.revealInEditor(JavaEditor.this, (IJavaElement)element);
ISourceViewer javaSourceViewer = JavaEditor.this.getJavaSourceViewer();
javaSourceViewer.getTextWidget().notifyListeners(SWT.Selection, new Event());
}
finally
{
navigating = false;
}
return;
}
}
}
super.run(elements);
}
};
}
return openDeclarationAction;
}
IAction getGotoMatchingBracketAction()
{
final IAction gotoMatchingBracketAction = getAction(org.eclipse.jdt.internal.ui.javaeditor.GotoMatchingBracketAction.GOTO_MATCHING_BRACKET);
gotoMatchingBracketAction.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
return new Action(gotoMatchingBracketAction.getText(), gotoMatchingBracketAction.getStyle())
{
@Override
public void run()
{
JETBracketMatcher jetBracketMatcher = jetEditor.getJetBracketMatcher();
ISourceViewer jetSourceViewer = jetEditor.getSourceViewer();
Point selectedRange = jetSourceViewer.getSelectedRange();
IRegion jetMatch = jetBracketMatcher.match(jetSourceViewer.getDocument(), selectedRange.x);
if (jetMatch == null)
{
try
{
navigating = true;
gotoMatchingBracketAction.run();
}
finally
{
navigating = false;
}
}
else
{
int offset = jetMatch.getOffset();
int length = jetMatch.getLength();
int targetOffset = (ICharacterPairMatcher.RIGHT == jetBracketMatcher.getAnchor()) ? offset + 1 : offset + length;
jetEditor.selectAndReveal(targetOffset, 0);
}
}
};
}
IContentAssistant getContentAssist()
{
try
{
Field field = SourceViewer.class.getDeclaredField("fContentAssistant");
field.setAccessible(true);
return (IContentAssistant)field.get(getSourceViewer());
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
IQuickAssistAssistant getQuickAssistAssistant()
{
try
{
Field field = SourceViewer.class.getDeclaredField("fQuickAssistAssistant");
field.setAccessible(true);
return (IQuickAssistAssistant)field.get(getSourceViewer());
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks)
{
JETCompilationUnit compilerResult = jetEditor.getCompilationUnit();
if (compilerResult != null)
{
IRegion javaWordRegion = org.eclipse.jdt.internal.ui.text.JavaWordFinder.findWord(textViewer.getDocument(), region.getOffset());
final int correspondingTemplateFileID = compilerResult.getCorrespondingTemplateFileID(region.getOffset());
if (correspondingTemplateFileID != -1 && correspondingTemplateFileID != jetEditor.getFileID())
{
JETHyperLink jetHyperLink = new JETHyperLink(
jetEditor,
javaWordRegion == null || javaWordRegion.getLength() == 0 ? new Region(region.getOffset(), 1) : javaWordRegion,
correspondingTemplateFileID,
toURI(jetEditor.getDocumentManager().getEditorInput(correspondingTemplateFileID)).toString())
{
@Override
public String getTypeLabel()
{
return "Open JET";
}
};
return new IHyperlink []{ jetHyperLink };
}
}
return null;
}
@Override
protected void markInNavigationHistory()
{
// Don't maintain history for the Java file itself.
}
@Override
protected ITypeRoot getInputJavaElement()
{
ITypeRoot inputJavaElement = super.getInputJavaElement();
IEditorInput editorInput = getEditorInput();
if (editorInput instanceof JavaEditorInput)
{
return ((JavaEditorInput)editorInput).getWorkingCopy(inputJavaElement);
}
else
{
return inputJavaElement;
}
}
@Override
public void dispose()
{
super.dispose();
IEditorInput editorInput = getEditorInput();
if (editorInput instanceof JavaEditorInput)
{
((JavaEditorInput)editorInput).releaseWorkingCopy();
}
}
void setInput(IFile javaFile, String compilationUnit)
{
IFile effectiveJavaFile = javaFile;
boolean javaFileExists = javaFile.exists();
if (!javaFileExists)
{
// Ensure that the file is contained by an actual existing project or folder.
IContainer parent = javaFile.getParent();
while (!parent.exists())
{
parent = parent.getParent();
}
if (parent.getType() == IResource.ROOT)
{
parent = jetEditor.getEditorInputFile().getParent();
}
effectiveJavaFile = parent.getFile(new Path(javaFile.getName()));
}
IEditorInput newInput = javaFileExists ? new FileEditorInput(effectiveJavaFile) : new JavaEditorInput(effectiveJavaFile, compilationUnit);
IEditorInput oldInput = getEditorInput();
if (!newInput.equals(oldInput))
{
setInput(newInput);
getJavaSourceViewer().setEditable(false);
if (oldInput instanceof JavaEditorInput)
{
((JavaEditorInput)oldInput).releaseWorkingCopy();
}
}
jetEditor.getJavaPosition().addToDocument(getJavaSourceViewer().getDocument());
if (newInput instanceof JavaEditorInput)
{
((JavaEditorInput)newInput).release();
}
}
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException
{
super.init(new DelegatingEditorSite(site), input);
IPerspectiveDescriptor perspective = getSite().getPage().getPerspective();
String id = EDITOR_SHOW_BREADCRUMB + "." + perspective.getId(); //$NON-NLS-1$
IPreferenceStore preferenceStore = getPreferenceStore();
PreferenceStore localPreferenceStore = new PreferenceStore();
localPreferenceStore.setValue(PreferenceConstants.EDITOR_FOLDING_ENABLED, false);
setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore []{ localPreferenceStore, preferenceStore }));
localPreferenceStore.setValue(id, true);
}
@Override
public void createPartControl(Composite parent)
{
super.createPartControl(parent);
new VisibleCaretHandler(getSourceViewer().getTextWidget(), jetEditor.getSourceViewer().getTextWidget());
// The Java editor does semantic highlighting on a background thread that updates the Java viewer at some arbitrary point in time later.
((ITextViewerExtension4)getSourceViewer()).addTextPresentationListener(new ITextPresentationListener()
{
private Color getBackground(JETJavaRange jetRange)
{
JETItem jetItem = jetRange.getJETItem();
if (jetItem instanceof JETScriptletItem)
{
return ColorManager.INSTANCE.getBackground(JETScriptletRule.TOKEN.getType());
}
else if (jetItem instanceof JETExpressionItem)
{
return ColorManager.INSTANCE.getBackground(JETExpressionRule.TOKEN.getType());
}
else if (jetItem instanceof JETLiteralItem)
{
return ColorManager.INSTANCE.getBackground(JETContentRule.TOKEN.getType());
}
else if (jetItem instanceof JETSubItem && jetItem.getParent() instanceof JETCommentItem)
{
return ColorManager.INSTANCE.getBackground(JETCommentRule.TOKEN.getType());
}
else
{
return ColorManager.INSTANCE.getBackground(JETDirectiveRule.TOKEN.getType());
}
}
public void applyTextPresentation(TextPresentation textPresentation)
{
// Start two parallel iterators on the JET ranges and the style ranges.
List<JETJavaRange> ranges = jetEditor.getRanges();
if (!ranges.isEmpty())
{
Iterator<StyleRange> i = textPresentation.getAllStyleRangeIterator();
if (i.hasNext())
{
// Accumulate altered style ranges.
List<StyleRange> newStyleRanges = new ArrayList<StyleRange>();
// Initialize the current starting point for each scanned JET range and style range.
Iterator<JETJavaRange> r = ranges.iterator();
JETJavaRange range = r.next();
StyleRange styleRange = i.next();
LOOP: while (true)
{
// Skip any empty ranges, e.g., the ones from an empty scriptlet.
int rangeJavaLength = range.getJavaLength();
while (rangeJavaLength == 0)
{
if (!r.hasNext())
{
newStyleRanges.add(styleRange);
break LOOP;
}
range = r.next();
rangeJavaLength = range.getJavaLength();
}
int javaOffset = styleRange.start;
int rangeJavaOffset = range.getJavaOffset();
// Consume ranges until we hit one that overlaps with the current style range.
while (rangeJavaOffset + rangeJavaLength <= javaOffset)
{
if (!r.hasNext())
{
newStyleRanges.add(styleRange);
break LOOP;
}
range = r.next();
rangeJavaOffset = range.getJavaOffset();
rangeJavaLength = range.getJavaLength();
}
// Consume style ranges until we hit one that overlaps with the current range.
while (javaOffset + styleRange.length <= rangeJavaOffset)
{
newStyleRanges.add(styleRange);
if (i.hasNext())
{
styleRange = i.next();
javaOffset = styleRange.start;
}
else
{
break LOOP;
}
}
// Trim off any unstyled prefix from the style range.
int delta = rangeJavaOffset - javaOffset;
if (delta > 0)
{
// The prefix has normal style so we clone the range and reduce the length.
StyleRange newStyleRange = (StyleRange)styleRange.clone();
newStyleRange.length = delta;
newStyleRanges.add(newStyleRange);
// If we've consumed the whole style range...
if (styleRange.length == delta)
{
if (i.hasNext())
{
// If there are style ranges left, continue the loop.
styleRange = i.next();
continue;
}
else
{
// Otherwise we're done.
break;
}
}
// Advance the style range.
javaOffset = styleRange.start += delta;
styleRange.length -= delta;
}
// Consume the styled part of the style range.
int lengthDelta = styleRange.length - rangeJavaLength;
if (lengthDelta > 0)
{
// The new style range completely consumes the range.
StyleRange newStyleRange = (StyleRange)styleRange.clone();
newStyleRange.length = rangeJavaLength;
newStyleRange.background = getBackground(range);
newStyleRanges.add(newStyleRange);
// Advance the style range by the consumed length.
styleRange.start += rangeJavaLength;
styleRange.length = lengthDelta;
// Advance the range if there are any left.
if (!r.hasNext())
{
// If not, consume the remaining portion of the style range and terminate.
newStyleRanges.add(styleRange);
break LOOP;
}
else
{
range = r.next();
}
}
else
{
// The style range is completely consumed by the range.
styleRange.background = getBackground(range);
newStyleRanges.add(styleRange);
// If we're out of style ranges, terminate.
if (!i.hasNext())
{
break;
}
else
{
// Otherwise, advance the range to the remaining portion and advanced to the next style range.
range = range.subrange(styleRange.length);
styleRange = i.next();
}
}
}
// Consume any remaining unaltered style ranges.
while (i.hasNext())
{
newStyleRanges.add(i.next());
}
textPresentation.clear();
for (StyleRange newStyleRange : newStyleRanges)
{
textPresentation.addStyleRange(newStyleRange);
}
}
}
if (jetEditor.isJavaEditorInSync())
{
jetEditor.invalidateVisibleTextPresentation(true);
}
}
});
try
{
// Disable the Java editor from also setting the last edit location.
Field textListenerField = AbstractTextEditor.class.getDeclaredField("fTextListener");
textListenerField.setAccessible(true);
Object textListener = textListenerField.get(this);
Field runnableField = textListener.getClass().getDeclaredField("fRunnable");
runnableField.setAccessible(true);
runnableField.set(textListener, new Runnable()
{
public void run()
{
}
});
}
catch (Exception exception)
{
// If that doesn't work, it's not tragic, just annoying.
}
((IPostSelectionProvider)getSelectionProvider()).addSelectionChangedListener(new JavadocUpdater(jetEditor));
}
private static final class JavadocUpdater implements ISelectionChangedListener
{
private final JETEditor jetEditor;
public JavadocUpdater(JETEditor jetEditor)
{
this.jetEditor = jetEditor;
}
public void selectionChanged(SelectionChangedEvent event)
{
JavaEditor javaEditor = jetEditor.getJavaEditor();
ISelectionProvider selectionProvider = javaEditor.getSelectionProvider();
ISelectionValidator selectionValidator = (ISelectionValidator)selectionProvider;
if (selectionValidator.isValid(event.getSelection()))
{
IWorkbenchPage page = jetEditor.getSite().getPage();
IViewPart javadocView = page.findView(JavaUI.ID_JAVADOC_VIEW);
if (javadocView != null)
{
IViewPart[] viewStack = page.getViewStack(javadocView);
if (viewStack != null && viewStack.length > 0 && viewStack[0] == javadocView)
{
((ISelectionListener)javadocView).selectionChanged(javaEditor, selectionProvider.getSelection());
}
}
}
}
}
private static final class StatusFilteringForwardingDocumentProvider extends ForwardingDocumentProvider
{
public StatusFilteringForwardingDocumentProvider(IDocumentProvider parentProvider)
{
super(IJavaPartitions.JAVA_PARTITIONING, new IDocumentSetupParticipant()
{
public void setup(IDocument document)
{
}
}, parentProvider);
}
@Override
public IStatus getStatus(Object element)
{
return Status.OK_STATUS;
}
}
private static class DelegatingEditorSite implements IEditorSite
{
private final IEditorSite editorSite;
private SubActionBars subActionBars;
public DelegatingEditorSite(IEditorSite editorSite)
{
this.editorSite = editorSite;
subActionBars = new SubActionBars(getEditorSite().getActionBars());
}
public IEditorSite getEditorSite()
{
return editorSite;
}
public IEditorActionBarContributor getActionBarContributor()
{
return getEditorSite().getActionBarContributor();
}
public String getId()
{
return JavaUI.ID_CU_EDITOR;
}
@SuppressWarnings("rawtypes")
public boolean hasService(Class api)
{
return false;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getService(Class api)
{
return null;
}
public String getPluginId()
{
return getEditorSite().getPluginId();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getAdapter(Class adapter)
{
return getEditorSite().getAdapter(adapter);
}
public IWorkbenchPage getPage()
{
return getEditorSite().getPage();
}
public ISelectionProvider getSelectionProvider()
{
return getEditorSite().getSelectionProvider();
}
public Shell getShell()
{
return getEditorSite().getShell();
}
public IActionBars getActionBars()
{
return subActionBars;
}
public IWorkbenchPart getPart()
{
return getEditorSite().getPart();
}
public IWorkbenchWindow getWorkbenchWindow()
{
return getEditorSite().getWorkbenchWindow();
}
public void setSelectionProvider(ISelectionProvider provider)
{
getEditorSite().setSelectionProvider(provider);
}
public String getRegisteredName()
{
return getEditorSite().getRegisteredName();
}
public void registerContextMenu(String menuId, MenuManager menuManager, ISelectionProvider selectionProvider)
{
}
public void registerContextMenu(MenuManager menuManager, ISelectionProvider selectionProvider, boolean includeEditorInput)
{
}
public void registerContextMenu(MenuManager menuManager, ISelectionProvider selectionProvider)
{
}
public void registerContextMenu(String menuId, MenuManager menuManager, ISelectionProvider selectionProvider, boolean includeEditorInput)
{
}
@SuppressWarnings("deprecation")
public org.eclipse.ui.IKeyBindingService getKeyBindingService()
{
return new DelegatingKeyBindingService();
}
@SuppressWarnings("deprecation")
private static class DelegatingKeyBindingService implements org.eclipse.ui.IKeyBindingService
{
public String[] getScopes()
{
return new String [0];
}
public void registerAction(IAction action)
{
}
public void setScopes(String[] scopes)
{
}
public void unregisterAction(IAction action)
{
}
}
}
}
static abstract class SneakyRunnable implements Runnable
{
@SuppressWarnings("unchecked")
private static <E extends Throwable> void sneakyThrow(Throwable throwable) throws E
{
throw (E)throwable;
}
public final void run()
{
try
{
execute();
}
catch (Throwable throwable)
{
SneakyRunnable.<RuntimeException> sneakyThrow(throwable);
}
}
protected abstract void execute() throws Throwable;
}
static IEditorPart open(IEditorSite site, String locationURI)
{
IFile file = toFile(URI.createURI(locationURI));
if (file != null && file.exists())
{
try
{
String editorID = site.getWorkbenchWindow().getWorkbench().getEditorRegistry().getDefaultEditor(file.getName()).getId();
return site.getPage().openEditor(new FileEditorInput(file), editorID);
}
catch (PartInitException exception)
{
CodeGenUIPlugin.write(exception);
}
}
return null;
}
static IFile toFile(URI uri)
{
return uri.isPlatformResource() ? ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true))) : null;
}
static URI toPlatformResourceURI(IEditorInput input)
{
return toURI(toFile(input));
}
static IFile toFile(IEditorInput input)
{
if (input instanceof StorageEditorInput)
{
return ((StorageEditorInput)input).getFile();
}
else
{
return input instanceof IAdaptable ? (IFile)((IAdaptable)input).getAdapter(IFile.class) : null;
}
}
static URI toURI(IResource resource)
{
return resource == null ? null : URI.createPlatformResourceURI(resource.getFullPath().toString(), true);
}
static IRegion toRegion(JETItem jetItem)
{
int start = jetItem.getStartOffset();
int stop = jetItem.getStopOffset();
return new Region(start, stop - start);
}
static IEditorInput toEditorInput(URI uri)
{
if (uri != null && uri.isPlatformResource())
{
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
if (file.isAccessible())
{
return new FileEditorInput(file);
}
}
return new StorageEditorInput(JETNature.resolve(uri));
}
static IFile toFile(IPath path)
{
return ResourcesPlugin.getWorkspace().getRoot().getFile(path);
}
static URI toURI(IEditorInput input)
{
if (input instanceof IFileEditorInput)
{
return toURI(((IFileEditorInput)input).getFile());
}
else if (input instanceof StorageEditorInput)
{
return URI.createURI(((StorageEditorInput)input).getURI().toString());
}
else if (input instanceof IURIEditorInput)
{
return URI.createURI(((IURIEditorInput)input).getURI().toString());
}
else
{
return null;
}
}
static boolean installOnDocument(IDocument document, Position position, String category, IPositionUpdater positionUpdater)
{
if (document != null && position != null)
{
if (!document.containsPositionCategory(category))
{
document.addPositionCategory(category);
document.addPositionUpdater(positionUpdater);
}
try
{
document.addPosition(category, position);
return true;
}
catch (Exception excetpion)
{
}
}
return false;
}
static boolean uninstallFromDocument(IDocument document, Position position, String category, IPositionUpdater positionUpdater)
{
if (document != null && position != null)
{
try
{
document.removePosition(category, position);
Position[] positions = document.getPositions(category);
if (positions == null || positions.length == 0)
{
document.removePositionCategory(category);
document.removePositionUpdater(positionUpdater);
}
return true;
}
catch (BadPositionCategoryException exception)
{
}
}
return false;
}
}