| /** |
| * 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; |
| } |
| } |