/******************************************************************************* * Copyright (c) 2009 Andrey Loskutov. * 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 * Contributor: Andrey Loskutov - initial API and implementation *******************************************************************************/ package de.loskutov.anyedit.ui.editor; import static de.loskutov.anyedit.util.EclipseUtils.getAdapter; import java.io.File; import java.lang.reflect.Method; import java.net.URI; import org.eclipse.compare.ITypedElement; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentRewriteSession; import org.eclipse.jface.text.DocumentRewriteSessionType; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.IRewriteTarget; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.ISaveablePart; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.editors.text.IStorageDocumentProvider; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.part.IPage; import org.eclipse.ui.part.MultiPageEditorPart; import org.eclipse.ui.part.PageBookView; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.ITextEditorExtension; import org.eclipse.ui.texteditor.ITextEditorExtension2; import de.loskutov.anyedit.AnyEditToolsPlugin; import de.loskutov.anyedit.util.EclipseUtils; import de.loskutov.anyedit.util.TextUtil; /** * @author Andrey */ public class AbstractEditor implements ITextEditorExtension2 { private IWorkbenchPart wPart; private boolean multipage; /** * Proxy for different editor types */ public AbstractEditor(final @Nullable IWorkbenchPart editorPart) { this(); wPart = editorPart; if(editorPart instanceof FormEditor){ FormEditor fe = (FormEditor)editorPart; wPart = fe.getActiveEditor(); multipage = true; } else if(editorPart instanceof MultiPageEditorPart){ MultiPageEditorPart me = (MultiPageEditorPart)editorPart; // followed is because "getActiveEditor" method is protected in // MultiPageEditorPart class. try { Method method = MultiPageEditorPart.class.getDeclaredMethod( "getActiveEditor", null); method.setAccessible(true); wPart = (IEditorPart) method.invoke(me, null); multipage = true; } catch (Exception e) { AnyEditToolsPlugin.logError("Can't get current page", e); } } else if(editorPart!= null && !(editorPart instanceof ITextEditor) && !(editorPart instanceof IViewPart)) { /* * added to support different multipage editors which are not extending * MultiPageEditorPart, like adobe Flex family editors */ try { Method[] declaredMethods = editorPart.getClass().getDeclaredMethods(); for (int i = 0; i < declaredMethods.length; i++) { Method method = declaredMethods[i]; String methodName = method.getName(); if(("getActiveEditor".equals(methodName) // lines below are for Flex 3, above for Flex 2 || "getCodeEditor".equals(methodName) || "getTextEditor".equals(methodName)) && method.getParameterTypes().length == 0){ method.setAccessible(true); IEditorPart ePart = (IEditorPart) method.invoke(editorPart, null); if(ePart == null) { continue; } wPart = ePart; multipage = true; break; } } } catch (Exception e) { AnyEditToolsPlugin.logError("Can't get current page", e); } } } private AbstractEditor() { super(); } public AbstractEditor recreate(){ AbstractEditor ae = new AbstractEditor(); ae.wPart = wPart; ae.multipage = multipage; return ae; } public boolean isMultiPage(){ return multipage; } /** * @return may return null */ @Nullable public IDocumentProvider getDocumentProvider() { if (wPart == null) { return null; } if (wPart instanceof ITextEditor) { return ((ITextEditor) wPart).getDocumentProvider(); } IDocumentProvider docProvider = getAdapter(wPart, IDocumentProvider.class); return docProvider; } /** * @return may return null */ @Nullable public IEditorInput getInput() { if (!(wPart instanceof IEditorPart)) { return null; } return ((IEditorPart) wPart).getEditorInput(); } /** * @return may return null */ @Nullable public IFile getIFile(){ if(wPart == null){ return null; } IEditorInput input = getInput(); if(input != null){ IFile adapter = EclipseUtils.getIFile(input, true); if(adapter != null){ return adapter; } } IFile adapter = EclipseUtils.getIFile(wPart, true); return adapter; } @Nullable public File getFile(){ if(wPart == null){ return null; } IEditorInput input = getInput(); if(input != null){ File adapter = EclipseUtils.getFile(input, true); if(adapter != null){ return adapter; } } File adapter = EclipseUtils.getFile(wPart, true); if(adapter != null){ return adapter; } ISelectionProvider sp = getSelectionProvider(); if(sp != null){ ISelection selection = sp.getSelection(); if(selection != null){ adapter = EclipseUtils.getFile(selection, true); } } return adapter; } /** * @see ITypedElement#getType() */ @Nullable public String getContentType(){ URI uri = getURI(); String path; if(uri != null) { path = uri.toString(); } else { File file = getFile(); if(file == null) { return null; } path = file.getAbsolutePath(); } int dot = path.lastIndexOf('.') + 1; if(dot >= 0){ return path.substring(dot); } return path; } @NonNull public String getTitle(){ if(wPart == null){ return ""; } String title = wPart.getTitle(); return title != null? title : ""; } /** * @return may return null */ @Nullable private URI getURI(){ return EclipseUtils.getURI(getInput()); } @NonNull public String computeEncoding() { IFile file = getIFile(); if(file != null) { try { String charset = file.getCharset(); if(charset != null) { return charset; } } catch (CoreException e) { // ignore; } } IDocumentProvider provider = getDocumentProvider(); if(provider instanceof IStorageDocumentProvider) { IStorageDocumentProvider docProvider = (IStorageDocumentProvider) provider; String encoding = docProvider.getEncoding(getInput()); if(encoding != null) { return encoding; } } return TextUtil.SYSTEM_CHARSET; } @Nullable public ISelectionProvider getSelectionProvider() { if (wPart == null) { return null; } if (wPart instanceof ITextEditor) { return ((ITextEditor) wPart).getSelectionProvider(); } // PDEMultiPageEditor doesn't implement ITextEditor interface ISelectionProvider adapter = getAdapter(wPart, ISelectionProvider.class); if(adapter != null){ return adapter; } ISelectionProvider sp = wPart.getSite().getSelectionProvider(); if(sp != null){ return sp; } TextViewer viewer = getAdapter(wPart, TextViewer.class); if(viewer != null){ return viewer.getSelectionProvider(); } return null; } @Nullable public IDocument getDocument() { IEditorInput input = getInput(); if(input != null) { IDocumentProvider provider = getDocumentProvider(); if (provider != null) { return provider.getDocument(input); } } if (wPart instanceof PageBookView) { IPage page = ((PageBookView) wPart).getCurrentPage(); ITextViewer viewer = EditorPropertyTester.getViewer(page); if( viewer != null ) { return viewer.getDocument(); } } if (wPart instanceof IViewPart) { ISelectionProvider sp = ((IViewPart) wPart).getViewSite().getSelectionProvider(); if(sp instanceof ITextViewer){ return ((ITextViewer) sp).getDocument(); } } if(wPart != null){ TextViewer viewer = getAdapter(wPart, TextViewer.class); if(viewer != null){ return viewer.getDocument(); } } return null; } @Nullable public ITextSelection getSelection(){ ISelectionProvider selectionProvider = getSelectionProvider(); if (selectionProvider == null) { return null; } ISelection selection = selectionProvider.getSelection(); if (selection instanceof ITextSelection) { return (ITextSelection) selection; } return null; } @Nullable public String getSelectedText(){ ITextSelection selection = getSelection(); if(selection == null){ return null; } String selectedText = selection.getText(); if(selectedText != null && selectedText.length() > 0) { return selectedText; } return null; } public void selectAndReveal(int lineNumber){ if (!(wPart instanceof ITextEditor)) { return; } IDocument document = getDocument(); if(document != null){ try { // line count internally starts with 0, and not with 1 like in GUI IRegion lineInfo = document.getLineInformation(lineNumber - 1); if(lineInfo != null){ ((ITextEditor)wPart).selectAndReveal(lineInfo.getOffset(), lineInfo.getLength()); } } catch (BadLocationException e) { //ignored because line number may not really exist in document, we guess this... } } } public boolean isDirty(){ if (!(wPart instanceof ISaveablePart)) { return false; } return ((ISaveablePart) wPart).isDirty(); } @Nullable private <T> T getAdapterFromPart(Class<T> clazz){ if (wPart == null) { return null; } return getAdapter(wPart, clazz); } public void doSave(IProgressMonitor moni){ if (!(wPart instanceof ISaveablePart)) { return; } ((ISaveablePart) wPart).doSave(moni); } @Override public boolean isEditorInputModifiable() { if (wPart == null) { return false; } if (wPart instanceof ITextEditorExtension2) { return ((ITextEditorExtension2)wPart).isEditorInputModifiable(); } if (wPart instanceof ITextEditorExtension) { return !((ITextEditorExtension) wPart).isEditorInputReadOnly(); } if (wPart instanceof ITextEditor) { return ((ITextEditor)wPart).isEditable(); } return true; } @Override public boolean validateEditorInputState() { if (wPart == null) { return false; } if (wPart instanceof ITextEditorExtension2) { return ((ITextEditorExtension2)wPart).validateEditorInputState(); } return true; } /** * Sets the sequential rewrite mode of the viewer's document. */ public void stopSequentialRewriteMode(DocumentRewriteSession session) { IDocument document = getDocument(); if (document instanceof IDocumentExtension4) { IDocumentExtension4 extension= (IDocumentExtension4) document; extension.stopRewriteSession(session); } else if (document instanceof IDocumentExtension) { IDocumentExtension extension= (IDocumentExtension)document; extension.stopSequentialRewrite(); } IRewriteTarget target = getAdapterFromPart(IRewriteTarget.class); if (target != null) { target.endCompoundChange(); target.setRedraw(true); } } /** * Starts the sequential rewrite mode of the viewer's document. * @param normalized <code>true</code> if the rewrite is performed * from the start to the end of the document */ @Nullable public DocumentRewriteSession startSequentialRewriteMode(boolean normalized) { // de/activate listeners etc, prepare multiple replace IRewriteTarget target = getAdapterFromPart(IRewriteTarget.class); if (target != null) { target.setRedraw(false); target.beginCompoundChange(); } DocumentRewriteSession rewriteSession = null; IDocument document = getDocument(); if (document instanceof IDocumentExtension4) { IDocumentExtension4 extension= (IDocumentExtension4) document; if (normalized) { rewriteSession = extension .startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL); } else { rewriteSession = extension .startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL); } } else if (document instanceof IDocumentExtension) { IDocumentExtension extension = (IDocumentExtension) document; extension.startSequentialRewrite(normalized); } return rewriteSession; } /** * clean reference to wrapped "real" editor object */ public void dispose(){ wPart = null; } public boolean isDisposed(){ return wPart == null; } @Override public int hashCode() { IDocumentProvider provider = getDocumentProvider(); IEditorInput input = getInput(); int code = 0; if(provider != null){ code += provider.hashCode(); } if(input != null){ code += input.hashCode(); } if(wPart != null){ code += wPart.hashCode(); } return code; } @Override public boolean equals(Object obj) { if(obj == this){ return true; } if(!(obj instanceof AbstractEditor)){ return false; } AbstractEditor other = (AbstractEditor) obj; if(this.wPart != other.wPart){ return false; } // now check for multi page stuff if(!isMultiPage()){ return true; } return this.hashCode() == other.hashCode(); } @Nullable public IWorkbenchPart getPart() { return wPart; } @Nullable public String getText() { IDocument doc = getDocument(); return doc != null? doc.get() : null; } }