/******************************************************************************* * Copyright (c) 2000, 2007 Dakshinamurthy Karra and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Dakshinamurthy Karra - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.ui.preferences; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.window.Window; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.IUndoManager; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.templates.ContextTypeRegistry; import org.eclipse.jface.text.templates.Template; import org.eclipse.jface.text.templates.TemplateContextType; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.templates.TemplatesPage; import org.eclipse.ui.views.templates.ITemplatesPage; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContext; import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType; import org.eclipse.jdt.internal.corext.template.java.JavaContextType; import org.eclipse.jdt.internal.corext.template.java.JavaDocContextType; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jdt.ui.text.IJavaPartitions; import org.eclipse.jdt.ui.text.JavaTextTools; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer; import org.eclipse.jdt.internal.ui.text.SimpleJavaSourceViewerConfiguration; import org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateProposal; import org.eclipse.jdt.internal.ui.text.template.preferences.TemplateVariableProcessor; /** * A TemplatesPage implementation for JavaEditor * * @since 3.4 */ public class JavaTemplatesPage extends TemplatesPage implements ITemplatesPage { private static final ContextTypeRegistry TEMPLATE_CONTEXT_REGISTRY= JavaPlugin.getDefault().getTemplateContextRegistry(); private TemplateVariableProcessor fTemplateProcessor; private final JavaEditor fEditor; private IDocument fDocument; private String fJavaDocId; private String fJavaId; private String fCurrentId; private int fCachedOffset; private boolean fCachedResult; private Point fCachedPosition; /** * @param javaEditor */ public JavaTemplatesPage(JavaEditor javaEditor) { super(JavaPlugin.getDefault().getTemplateStore(), JavaPlugin.getDefault().getPreferenceStore(), TEMPLATE_CONTEXT_REGISTRY); fEditor= javaEditor; fJavaDocId= new JavaDocContextType().getId(); fJavaId= new JavaContextType().getId(); fTemplateProcessor= new TemplateVariableProcessor(); fDocument= fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput()); cursorPositionChanged(); setupEditorDropTarget(fEditor.getSite(), fEditor.getViewer().getTextWidget()); } public void dispose() { super.dispose(); } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#editTemplate(org.eclipse.jface.text.templates.Template, boolean, boolean) */ protected Template editTemplate(Template template, boolean edit, boolean isNameModifiable) { EditTemplateDialog dialog= new EditTemplateDialog(getShell(), template, edit, isNameModifiable, TEMPLATE_CONTEXT_REGISTRY); if (dialog.open() == Window.OK) { return dialog.getTemplate(); } return null; } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#createViewer(org.eclipse.swt.widgets.Composite) */ protected SourceViewer createViewer(Composite parent) { IDocument document= new Document(); JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools(); tools.setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING); IPreferenceStore store= JavaPlugin.getDefault().getCombinedPreferenceStore(); SourceViewer viewer= new JavaSourceViewer(parent, null, null, false, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL, store); SimpleJavaSourceViewerConfiguration configuration= new SimpleJavaSourceViewerConfiguration(tools.getColorManager(), store, null, IJavaPartitions.JAVA_PARTITIONING, false); viewer.configure(configuration); viewer.setEditable(false); viewer.setDocument(document); Font font= JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT); viewer.getTextWidget().setFont(font); new JavaSourcePreviewerUpdater(viewer, configuration, store); Control control= viewer.getControl(); GridData data= new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.FILL_VERTICAL); control.setLayoutData(data); return viewer; } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#updateViewerInput(org.eclipse.jface.text.templates.Template) */ protected void updateViewerInput(Template template) { SourceViewer viewer= getViewer(); String contextId= template.getContextTypeId(); TemplateContextType type= TEMPLATE_CONTEXT_REGISTRY.getContextType(contextId); fTemplateProcessor.setContextType(type); IDocument doc= viewer.getDocument(); String start= null; if ("javadoc".equals(contextId)) { //$NON-NLS-1$ start= "/**" + doc.getLegalLineDelimiters()[0]; //$NON-NLS-1$ } else start= ""; //$NON-NLS-1$ doc.set(start + template.getPattern()); int startLen= start.length(); viewer.setDocument(doc, startLen, doc.getLength() - startLen); } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#getPreferencePageId() */ protected String getPreferencePageId() { return "org.eclipse.jdt.ui.preferences.JavaTemplatePreferencePage"; //$NON-NLS-1$ } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#insertTemplate(org.eclipse.jface.text.templates.Template) */ public void insertTemplate(Template template) { if (!fEditor.isEditorInputModifiable()) return; TemplateContextType type= TEMPLATE_CONTEXT_REGISTRY.getContextType(template.getContextTypeId()); ISourceViewer contextViewer= fEditor.getViewer(); ITextSelection textSelection= (ITextSelection) contextViewer.getSelectionProvider().getSelection(); if ( !isValidTemplate(template, textSelection.getOffset(), textSelection.getLength())) return; IUndoManager undoManager= ((JavaSourceViewer) fEditor.getViewer()).getUndoManager(); undoManager.beginCompoundChange(); /* * The Editor checks whether a completion for a word exists before it allows for the template to be * applied. We pickup the current text at the selection position and replace it with the first char * of the template name for this to succeed. * We don't need to go through this, if the editors simply support applyTemplate(Template). */ String savedText; try { savedText= fDocument.get(textSelection.getOffset(), textSelection.getLength()); if (savedText.length() == 0) { String prefix= getIdentifierPart(textSelection.getOffset()); if (prefix.length() > 0 && !template.getName().startsWith(prefix.toString())) { return; } if (prefix.length() > 0) { contextViewer.setSelectedRange(textSelection.getOffset() - prefix.length(), prefix.length()); textSelection= (ITextSelection) contextViewer.getSelectionProvider().getSelection(); } } fDocument.replace(textSelection.getOffset(), textSelection.getLength(), template.getName().substring(0, 1)); } catch (BadLocationException e) { undoManager.endCompoundChange(); e.printStackTrace(); return; } Position position= new Position(textSelection.getOffset() + 1, 0); Region region= new Region(textSelection.getOffset() + 1, 0); contextViewer.getSelectionProvider().setSelection(new TextSelection(textSelection.getOffset(), 1)); ICompilationUnit compilationUnit= JavaCore.createCompilationUnitFrom(((FileEditorInput) fEditor.getEditorInput()).getFile()); CompilationUnitContext context= ((CompilationUnitContextType) type).createContext(fDocument, position, compilationUnit); context.setVariable("selection", savedText); //$NON-NLS-1$ if (context.getKey().length() == 0) { try { fDocument.replace(textSelection.getOffset(), 1, savedText); } catch (BadLocationException e) { e.printStackTrace(); undoManager.endCompoundChange(); return; } } TemplateProposal proposal= new TemplateProposal(template, context, region, null); fEditor.getSite().getPage().activate(fEditor); proposal.apply(fEditor.getViewer(), ' ', 0, region.getOffset()); undoManager.endCompoundChange(); } /** * Invoked by the editor whenever the caret position is updated */ public void cursorPositionChanged() { Point selectedRange= fEditor.getViewer().getSelectedRange(); int cursor= selectedRange.x + selectedRange.y; String partition; try { partition= TextUtilities.getContentType(fDocument, IJavaPartitions.JAVA_PARTITIONING, cursor, true); } catch (BadLocationException e) { return; } String id= fJavaId; if (partition.equals(IJavaPartitions.JAVA_DOC)) id= fJavaDocId; if (!id.equals(fCurrentId)) { fCurrentId= id; contextTypeChanged(new String[] { id }); } } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#isValidTempalteForPosition(org.eclipse.jface.text.templates.Template, int, int) */ protected boolean isValidTemplateForPosition(Template template, int x, int y) { StyledText textWidget= fEditor.getViewer().getTextWidget(); try { Point point= new Point(x,y); if (point.equals(fCachedPosition)) return fCachedResult; fCachedPosition = point ; int offset= getOffset(textWidget, textWidget.toControl(x, y)); if (fCachedOffset == offset) return fCachedResult; fCachedOffset= offset; if (isValidTemplate(template, offset, 0)) return fCachedResult= true; } catch (BadLocationException e) { } return fCachedResult= false; } /** * Get the document relative offset from the textwidget relative point * * @param textWidget * @param point * @return offset * @throws BadLocationException */ private int getOffset(StyledText textWidget, Point point) throws BadLocationException { ITextViewerExtension5 ext= (ITextViewerExtension5) fEditor.getViewer(); try { return ext.widgetOffset2ModelOffset(textWidget.getOffsetAtLocation(point)); } catch (IllegalArgumentException e) { int docLineIndex= ext.widgetLine2ModelLine(textWidget.getLineIndex(point.y)); String lineDelimiter= fDocument.getLineDelimiter(docLineIndex); int delimLength= lineDelimiter == null ? 0 : lineDelimiter.length(); return fDocument.getLineOffset(docLineIndex) + fDocument.getLineLength(docLineIndex) - delimLength; } } /** * Check whether the template is valid for the given offset * * @param template * @param offset * @param length * @return true if the template is valid */ private boolean isValidTemplate(Template template, int offset, int length) { try { if (!getContextId(offset).equals(template.getContextTypeId())) return false ; if (length > 0) // length > 0 iff no selection in editor or DnD operation return true ; String identifierPart= getIdentifierPart(offset); return ((identifierPart.length() > 0 && template.getName().startsWith(identifierPart.toString())) || (offset == fDocument.getLineInformationOfOffset(offset).getOffset()) || (Character.isWhitespace(fDocument.getChar(offset - 1)))); } catch (BadLocationException e) { } return false; } /** * Get the context id for at the given offset * * @param offset * @return the context id * @throws BadLocationException */ private String getContextId(int offset) throws BadLocationException { String partition= TextUtilities.getContentType(fDocument, IJavaPartitions.JAVA_PARTITIONING, offset, true); String id= fJavaId; if (partition.equals(IJavaPartitions.JAVA_DOC)) id= fJavaDocId; return id; } /** * Get the java identifier terminated at the given offset * * @param offset * @return the identifier part * @throws BadLocationException */ private String getIdentifierPart(int offset) throws BadLocationException { int end= offset; int start= end; while (--start >= 0) { if (!Character.isJavaIdentifierPart(fDocument.getChar(start))) break; } start++; return fDocument.get(start, end - start); } /* (non-Javadoc) * @see org.eclipse.ui.texteditor.templates.TemplatesPage#isEditorModifiable() */ protected boolean isEditorModifiable() { return fEditor.isEditorInputModifiable(); } }