| /******************************************************************************* |
| * Copyright (c) 2005, 2017 IBM Corporation 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.ui.editor; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.compare.rangedifferencer.IRangeComparator; |
| import org.eclipse.compare.rangedifferencer.RangeDifference; |
| import org.eclipse.compare.rangedifferencer.RangeDifferencer; |
| import org.eclipse.core.filebuffers.FileBuffers; |
| import org.eclipse.core.filebuffers.ITextFileBuffer; |
| import org.eclipse.core.filebuffers.ITextFileBufferManager; |
| import org.eclipse.core.filesystem.IFileStore; |
| 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.IStorage; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IExternalSourceModule; |
| import org.eclipse.dltk.core.IMember; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ISourceRange; |
| import org.eclipse.dltk.core.ISourceReference; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.internal.corext.util.Messages; |
| import org.eclipse.dltk.internal.ui.DelegatedOpen; |
| import org.eclipse.dltk.internal.ui.IDLTKStatusConstants; |
| import org.eclipse.dltk.internal.ui.text.LineComparator; |
| import org.eclipse.dltk.ui.DLTKUILanguageManager; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.IDLTKUILanguageToolkit; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.Region; |
| import org.eclipse.jface.text.TextSelection; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.ui.IEditorDescriptor; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IEditorSite; |
| import org.eclipse.ui.IFileEditorInput; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.actions.WorkspaceModifyOperation; |
| import org.eclipse.ui.ide.IDE; |
| import org.eclipse.ui.ide.IGotoMarker; |
| import org.eclipse.ui.part.FileEditorInput; |
| import org.eclipse.ui.texteditor.IDocumentProvider; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| import org.eclipse.ui.texteditor.TextEditorAction; |
| |
| public class EditorUtility { |
| /** |
| * Returns the DLTK project for a given editor input or <code>null</code> if |
| * no corresponding DLTK project exists. |
| * |
| * @param input |
| * the editor input |
| * @return the corresponding DLTK project |
| */ |
| public static IScriptProject getScriptProject(IEditorInput input) { |
| IScriptProject dProject = null; |
| if (input instanceof IFileEditorInput) { |
| IProject project = ((IFileEditorInput) input).getFile() |
| .getProject(); |
| if (project != null) { |
| dProject = DLTKCore.create(project); |
| if (!dProject.exists()) |
| dProject = null; |
| } |
| } else if (input instanceof ExternalStorageEditorInput) { |
| IModelElement element = input.getAdapter(IModelElement.class); |
| if (element != null) { |
| IScriptProject project = element.getScriptProject(); |
| if (project != null && project.exists()) { |
| return project; |
| } |
| } |
| } |
| return dProject; |
| } |
| |
| /** |
| * Returns the given editor's input as model element. |
| * |
| * @param editor |
| * the editor |
| * @param primaryOnly |
| * if <code>true</code> only primary working copies will be |
| * returned |
| * @return the given editor's input as model element or <code>null</code> if |
| * none |
| */ |
| public static ISourceModule getEditorInputModelElement(IEditorPart editor, |
| boolean primaryOnly) { |
| IEditorInput editorInput = editor.getEditorInput(); |
| if (editorInput == null) |
| return null; |
| ISourceModule je = DLTKUIPlugin.getEditorInputModelElement(editorInput); |
| if (je != null || primaryOnly) |
| return je; |
| return DLTKUIPlugin.getDefault().getWorkingCopyManager() |
| .getWorkingCopy(editorInput, primaryOnly); |
| } |
| |
| /** |
| * Opens a Script editor for an element such as <code>IModelElement</code>, |
| * <code>IFile</code>, or <code>IStorage</code>. The editor is activated by |
| * default. |
| * |
| * @return the IEditorPart or null if wrong element type or opening failed |
| */ |
| public static IEditorPart openInEditor(Object inputElement) |
| throws ModelException, PartInitException { |
| return openInEditor(inputElement, true); |
| } |
| |
| /** |
| * Opens a Script editor for an element (IModelElement, IFile, IStorage...) |
| * |
| * @return the IEditorPart or null if wrong element type or opening failed |
| */ |
| public static IEditorPart openInEditor(Object inputElement, |
| boolean activate) throws ModelException, PartInitException { |
| if (inputElement instanceof IFile) { |
| return openInEditor((IFile) inputElement, activate); |
| } else if (inputElement instanceof DelegatedOpen) { |
| return ((DelegatedOpen) inputElement).openInEditor(activate); |
| } |
| |
| IEditorInput input = getEditorInput(inputElement); |
| if (input != null) { |
| if (inputElement instanceof IModelElement) { |
| // first try to get it from the system. |
| String editorId = null; |
| IDLTKUILanguageToolkit toolkit = DLTKUILanguageManager |
| .getLanguageToolkit((IModelElement) inputElement); |
| if (toolkit != null) { |
| editorId = toolkit.getEditorId(inputElement); |
| } |
| if (editorId == null) { // Transitional code |
| editorId = getEditorID(input, inputElement); |
| } |
| |
| if (editorId != null) { |
| return openInEditor(input, editorId, activate); |
| } |
| } else |
| return openInEditor(input, getEditorID(input, inputElement), |
| activate); |
| } |
| if (inputElement instanceof IModelElement) { |
| IModelElement modelElement = (IModelElement) inputElement; |
| ISourceModule cu = (ISourceModule) (modelElement) |
| .getAncestor(IModelElement.SOURCE_MODULE); |
| if (cu != null) { |
| /* |
| * Support for non-primary or RSE working copy. Try to reveal it |
| * in the active editor. |
| */ |
| IWorkbenchPage page = DLTKUIPlugin.getActivePage(); |
| if (page != null) { |
| IEditorPart editor = page.getActiveEditor(); |
| if (editor != null) { |
| IModelElement editorCU = EditorUtility |
| .getEditorInputModelElement(editor, false); |
| if (editorCU == cu) { |
| EditorUtility.revealInEditor(editor, modelElement); |
| return editor; |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static String getEditorID(IEditorInput input, Object inputObject) { |
| IEditorDescriptor editorDescriptor; |
| try { |
| if (input instanceof IFileEditorInput) { |
| editorDescriptor = IDE.getEditorDescriptor( |
| ((IFileEditorInput) input).getFile(), true, false); |
| } else if (input instanceof ExternalStorageEditorInput) { |
| editorDescriptor = IDE.getEditorDescriptor(input.getName(), |
| true, false); |
| } else { |
| editorDescriptor = IDE.getEditorDescriptor(input.getName(), |
| true, false); |
| } |
| |
| } catch (PartInitException e) { |
| return null; |
| } |
| if (editorDescriptor != null) |
| return editorDescriptor.getId(); |
| return null; |
| } |
| |
| private static IEditorInput getEditorInput(IModelElement element) { |
| while (element != null) { |
| if (element instanceof IExternalSourceModule) { |
| ISourceModule unit = ((ISourceModule) element).getPrimary(); |
| if (unit instanceof IStorage) { |
| return new ExternalStorageEditorInput((IStorage) unit); |
| } |
| |
| } else if (element instanceof ISourceModule) { |
| ISourceModule unit = ((ISourceModule) element).getPrimary(); |
| IResource resource = unit.getResource(); |
| if (resource instanceof IFile && ((IFile) resource).exists()) |
| return new FileEditorInput((IFile) resource); |
| } |
| element = element.getParent(); |
| } |
| return null; |
| } |
| |
| public static IEditorInput getEditorInput(Object input) { |
| if (input instanceof IModelElement) |
| return getEditorInput((IModelElement) input); |
| if (input instanceof IFile) |
| return new FileEditorInput((IFile) input); |
| if (DLTKCore.DEBUG) { |
| System.err.println( |
| "Add archive entry and external source folder editor input.."); //$NON-NLS-1$ |
| } |
| if (input instanceof IStorage) { |
| return new ExternalStorageEditorInput((IStorage) input); |
| } |
| return null; |
| } |
| |
| /** |
| * Selects a Script Element in an editor |
| */ |
| public static void revealInEditor(IEditorPart part, IModelElement element) { |
| if (element == null) |
| return; |
| if (part instanceof IScriptEditor) { |
| ((IScriptEditor) part).setSelection(element); |
| return; |
| } |
| // Support for non-Script editor |
| try { |
| ISourceRange range = null; |
| if (element instanceof IExternalSourceModule) { |
| |
| } else if (element instanceof ISourceModule) { |
| range = null; |
| } |
| // else if (element instanceof IClassFile) |
| // range= null; |
| // else if (element instanceof ILocalVariable) |
| // range= ((ILocalVariable)element).getNameRange(); |
| else if (element instanceof IMember) |
| range = ((IMember) element).getNameRange(); |
| // else if (element instanceof ITypeParameter) |
| // range= ((ITypeParameter)element).getNameRange(); |
| else if (element instanceof ISourceReference) |
| range = ((ISourceReference) element).getSourceRange(); |
| if (range != null) |
| revealInEditor(part, range.getOffset(), range.getLength()); |
| } catch (ModelException e) { |
| // don't reveal |
| } |
| } |
| |
| /** |
| * Selects and reveals the given line in the given editor part. |
| * |
| * @param editorPart |
| * @param lineNumber |
| * @throws CoreException |
| */ |
| public static void revealInEditor(IEditorPart editorPart, int lineNumber) |
| throws CoreException { |
| if (editorPart instanceof ITextEditor && lineNumber >= 0) { |
| final ITextEditor textEditor = (ITextEditor) editorPart; |
| final IDocumentProvider provider = textEditor.getDocumentProvider(); |
| final IEditorInput input = editorPart.getEditorInput(); |
| provider.connect(input); |
| final IDocument document = provider.getDocument(input); |
| try { |
| final IRegion line = document.getLineInformation(lineNumber); |
| textEditor.selectAndReveal(line.getOffset(), line.getLength()); |
| } catch (BadLocationException e) { |
| |
| } |
| provider.disconnect(input); |
| } |
| } |
| |
| /** |
| * Selects and reveals the given region in the given editor part. |
| */ |
| public static void revealInEditor(IEditorPart part, IRegion region) { |
| if (part != null && region != null) |
| revealInEditor(part, region.getOffset(), region.getLength()); |
| } |
| |
| /** |
| * Selects and reveals the given offset and length in the given editor part. |
| */ |
| public static void revealInEditor(IEditorPart editor, final int offset, |
| final int length) { |
| if (editor instanceof ITextEditor) { |
| ((ITextEditor) editor).selectAndReveal(offset, length); |
| return; |
| } |
| // Support for non-text editor - try IGotoMarker interface |
| if (editor instanceof IGotoMarker) { |
| final IEditorInput input = editor.getEditorInput(); |
| if (input instanceof IFileEditorInput) { |
| final IGotoMarker gotoMarkerTarget = (IGotoMarker) editor; |
| WorkspaceModifyOperation op = new WorkspaceModifyOperation() { |
| @Override |
| protected void execute(IProgressMonitor monitor) |
| throws CoreException { |
| IMarker marker = null; |
| try { |
| marker = ((IFileEditorInput) input).getFile() |
| .createMarker(IMarker.TEXT); |
| marker.setAttribute(IMarker.CHAR_START, offset); |
| marker.setAttribute(IMarker.CHAR_END, |
| offset + length); |
| gotoMarkerTarget.gotoMarker(marker); |
| } finally { |
| if (marker != null) |
| marker.delete(); |
| } |
| } |
| }; |
| try { |
| op.run(null); |
| } catch (InvocationTargetException ex) { |
| // reveal failed |
| } catch (InterruptedException e) { |
| // Assert.isTrue(false, "this operation can not be |
| // canceled"); //$NON-NLS-1$ |
| } |
| } else if (input instanceof ExternalStorageEditorInput) { |
| System.err.println( |
| "TODO: Add external storage editor input reveal..."); //$NON-NLS-1$ |
| } |
| return; |
| } |
| /* |
| * Workaround: send out a text selection XXX: Needs to be improved, see |
| * https://bugs.eclipse.org/bugs/show_bug.cgi?id=32214 |
| */ |
| if (editor != null |
| && editor.getEditorSite().getSelectionProvider() != null) { |
| IEditorSite site = editor.getEditorSite(); |
| if (site == null) |
| return; |
| ISelectionProvider provider = editor.getEditorSite() |
| .getSelectionProvider(); |
| if (provider == null) |
| return; |
| provider.setSelection(new TextSelection(offset, length)); |
| } |
| } |
| |
| private static IEditorPart openInEditor(IFile file, boolean activate) |
| throws PartInitException { |
| if (file != null) { |
| IWorkbenchPage p = DLTKUIPlugin.getActivePage(); |
| if (p != null) { |
| IEditorPart editorPart = IDE.openEditor(p, file, activate); |
| initializeHighlightRange(editorPart); |
| return editorPart; |
| } |
| } |
| return null; |
| } |
| |
| private static IEditorPart openInEditor(IEditorInput input, String editorID, |
| boolean activate) throws PartInitException { |
| if (input != null) { |
| IWorkbenchPage p = DLTKUIPlugin.getActivePage(); |
| if (p != null) { |
| IEditorPart editorPart = p.openEditor(input, editorID, |
| activate); |
| initializeHighlightRange(editorPart); |
| return editorPart; |
| } |
| } |
| return null; |
| } |
| |
| private static void initializeHighlightRange(IEditorPart editorPart) { |
| if (editorPart instanceof ITextEditor) { |
| IAction toggleAction = editorPart.getEditorSite().getActionBars() |
| .getGlobalActionHandler( |
| ITextEditorActionDefinitionIds.TOGGLE_SHOW_SELECTED_ELEMENT_ONLY); |
| boolean enable = toggleAction != null; |
| // if (enable && editorPart instanceof Editor) |
| // enable= |
| // DLTKUIPlugin.getDefault().getPreferenceStore().getBoolean( |
| // PreferenceConstants.EDITOR_SHOW_SEGMENTS); |
| // else |
| if (DLTKCore.DEBUG) { |
| System.err.println( |
| "Add initializeHighlightRange support of preferences."); //$NON-NLS-1$ |
| } |
| enable = enable && toggleAction.isEnabled() |
| && toggleAction.isChecked(); |
| if (enable) { |
| if (toggleAction instanceof TextEditorAction) { |
| // Reset the action |
| ((TextEditorAction) toggleAction).setEditor(null); |
| // Restore the action |
| ((TextEditorAction) toggleAction) |
| .setEditor((ITextEditor) editorPart); |
| } else { |
| // Un-check |
| toggleAction.run(); |
| // Check |
| toggleAction.run(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Tests if a CU is currently shown in an editor |
| * |
| * @return the IEditorPart if shown, null if element is not open in an |
| * editor |
| */ |
| public static IEditorPart isOpenInEditor(Object inputElement) { |
| IEditorInput input = getEditorInput(inputElement); |
| |
| if (input != null) { |
| IWorkbenchPage p = DLTKUIPlugin.getActivePage(); |
| if (p != null) { |
| return p.findEditor(input); |
| } |
| } |
| |
| return null; |
| } |
| |
| public static IEditorPart[] getDirtyEditors() { |
| Set<IEditorInput> inputs = new HashSet<>(); |
| List<IEditorPart> result = new ArrayList<>(0); |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); |
| for (int i = 0; i < windows.length; i++) { |
| IWorkbenchPage[] pages = windows[i].getPages(); |
| for (int x = 0; x < pages.length; x++) { |
| IEditorPart[] editors = pages[x].getDirtyEditors(); |
| for (int z = 0; z < editors.length; z++) { |
| IEditorPart ep = editors[z]; |
| IEditorInput input = ep.getEditorInput(); |
| if (!inputs.contains(input)) { |
| inputs.add(input); |
| result.add(ep); |
| } |
| } |
| } |
| } |
| return result.toArray(new IEditorPart[result.size()]); |
| } |
| |
| /** |
| * If the current active editor edits ascriptelement return it, else return |
| * null |
| */ |
| public static IModelElement getActiveEditorModelInput() { |
| IWorkbenchPage page = DLTKUIPlugin.getActivePage(); |
| if (page != null) { |
| IEditorPart part = page.getActiveEditor(); |
| if (part != null) { |
| IEditorInput editorInput = part.getEditorInput(); |
| if (editorInput != null) { |
| return DLTKUIPlugin.getEditorInputModelElement(editorInput); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Appends to modifier string of the given SWT modifier bit to the given |
| * modifierString. |
| * |
| * @param modifierString |
| * the modifier string |
| * @param modifier |
| * an int with SWT modifier bit |
| * @return the concatenated modifier string |
| * |
| */ |
| private static String appendModifierString(String modifierString, |
| int modifier) { |
| if (modifierString == null) |
| modifierString = ""; //$NON-NLS-1$ |
| String newModifierString = Action.findModifierString(modifier); |
| if (modifierString.length() == 0) |
| return newModifierString; |
| return Messages.format( |
| DLTKEditorMessages.EditorUtility_concatModifierStrings, |
| new String[] { modifierString, newModifierString }); |
| } |
| |
| /** |
| * Returns the modifier string for the given SWT modifier modifier bits. |
| * |
| * @param stateMask |
| * the SWT modifier bits |
| * @return the modifier string |
| * |
| */ |
| public static String getModifierString(int stateMask) { |
| String modifierString = ""; //$NON-NLS-1$ |
| if ((stateMask & SWT.CTRL) == SWT.CTRL) |
| modifierString = appendModifierString(modifierString, SWT.CTRL); |
| if ((stateMask & SWT.ALT) == SWT.ALT) |
| modifierString = appendModifierString(modifierString, SWT.ALT); |
| if ((stateMask & SWT.SHIFT) == SWT.SHIFT) |
| modifierString = appendModifierString(modifierString, SWT.SHIFT); |
| if ((stateMask & SWT.COMMAND) == SWT.COMMAND) |
| modifierString = appendModifierString(modifierString, SWT.COMMAND); |
| |
| return modifierString; |
| } |
| |
| /** |
| * Maps the localized modifier name to a code in the same manner as |
| * #findModifier. |
| * |
| * @param modifierName |
| * the modifier name |
| * @return the SWT modifier bit, or <code>0</code> if no match was found |
| * |
| */ |
| public static int findLocalizedModifier(String modifierName) { |
| if (modifierName == null) |
| return 0; |
| |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.CTRL))) |
| return SWT.CTRL; |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.SHIFT))) |
| return SWT.SHIFT; |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.ALT))) |
| return SWT.ALT; |
| if (modifierName |
| .equalsIgnoreCase(Action.findModifierString(SWT.COMMAND))) |
| return SWT.COMMAND; |
| |
| return 0; |
| } |
| |
| /** |
| * Return the regions of all lines which have changed in the given buffer |
| * since the last save occurred. Each region in the result spans over the |
| * size of at least one line. If successive lines have changed a region |
| * spans over the size of all successive lines. The regions include line |
| * delimiters. |
| * |
| * @param buffer |
| * the buffer to compare contents from |
| * @param monitor |
| * to report progress to |
| * @return the regions of the changed lines |
| * @throws CoreException |
| * if something goes wrong |
| * @since 3.0 |
| */ |
| public static IRegion[] calculateChangedLineRegions( |
| final ITextFileBuffer buffer, final IProgressMonitor monitor) |
| throws CoreException { |
| final IRegion[][] result = new IRegion[1][]; |
| final IStatus[] errorStatus = new IStatus[] { Status.OK_STATUS }; |
| |
| try { |
| SafeRunner.run(new ISafeRunnable() { |
| |
| @Override |
| public void handleException(Throwable exception) { |
| DLTKUIPlugin.log(new Status(IStatus.ERROR, |
| DLTKUIPlugin.PLUGIN_ID, |
| IDLTKStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, |
| exception.getLocalizedMessage(), exception)); |
| String msg = DLTKEditorMessages.CompilationUnitDocumentProvider_error_calculatingChangedRegions; |
| errorStatus[0] = new Status(IStatus.ERROR, |
| DLTKUIPlugin.PLUGIN_ID, |
| IDLTKStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, |
| msg, exception); |
| result[0] = null; |
| } |
| |
| @Override |
| public void run() throws Exception { |
| monitor.beginTask( |
| DLTKEditorMessages.CompilationUnitDocumentProvider_calculatingChangedRegions_message, |
| 20); |
| IFileStore fileStore = buffer.getFileStore(); |
| |
| ITextFileBufferManager fileBufferManager = FileBuffers |
| .createTextFileBufferManager(); |
| fileBufferManager.connectFileStore(fileStore, |
| getSubProgressMonitor(monitor, 15)); |
| try { |
| IDocument currentDocument = buffer.getDocument(); |
| IDocument oldDocument = ((ITextFileBuffer) fileBufferManager |
| .getFileStoreFileBuffer(fileStore)) |
| .getDocument(); |
| |
| result[0] = getChangedLineRegions(oldDocument, |
| currentDocument); |
| } finally { |
| fileBufferManager.disconnectFileStore(fileStore, |
| getSubProgressMonitor(monitor, 5)); |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Return regions of all lines which differ comparing |
| * <code>oldDocument</code>s content with |
| * <code>currentDocument</code>s content. Successive lines are |
| * merged into one region. |
| * |
| * @param oldDocument |
| * a document containing the old content |
| * @param currentDocument |
| * a document containing the current content |
| * @return the changed regions |
| * @throws BadLocationException |
| * if fetching the line information fails |
| */ |
| private IRegion[] getChangedLineRegions(IDocument oldDocument, |
| IDocument currentDocument) throws BadLocationException { |
| /* |
| * Do not change the type of those local variables. We use |
| * Object here in order to prevent loading of the Compare |
| * plug-in at load time of this class. |
| */ |
| Object leftSide = new LineComparator(oldDocument); |
| Object rightSide = new LineComparator(currentDocument); |
| |
| RangeDifference[] differences = RangeDifferencer |
| .findDifferences((IRangeComparator) leftSide, |
| (IRangeComparator) rightSide); |
| |
| // It holds that: |
| // 1. Ranges are sorted: |
| // forAll r1,r2 element differences: indexOf(r1)<indexOf(r2) |
| // -> r1.rightStart()<r2.rightStart(); |
| // 2. Successive changed lines are merged into on |
| // RangeDifference |
| // forAll r1,r2 element differences: |
| // r1.rightStart()<r2.rightStart() -> |
| // r1.rightEnd()<r2.rightStart |
| |
| ArrayList<IRegion> regions = new ArrayList<>(); |
| for (int i = 0; i < differences.length; i++) { |
| RangeDifference curr = differences[i]; |
| if (curr.kind() == RangeDifference.CHANGE |
| && curr.rightLength() > 0) { |
| int startLine = curr.rightStart(); |
| int endLine = curr.rightEnd() - 1; |
| |
| IRegion startLineRegion = currentDocument |
| .getLineInformation(startLine); |
| if (startLine == endLine) { |
| regions.add(startLineRegion); |
| } else { |
| IRegion endLineRegion = currentDocument |
| .getLineInformation(endLine); |
| int startOffset = startLineRegion.getOffset(); |
| int endOffset = endLineRegion.getOffset() |
| + endLineRegion.getLength(); |
| regions.add(new Region(startOffset, |
| endOffset - startOffset)); |
| } |
| } |
| } |
| |
| return regions.toArray(new IRegion[regions.size()]); |
| } |
| }); |
| } finally { |
| if (!errorStatus[0].isOK()) |
| throw new CoreException(errorStatus[0]); |
| } |
| |
| return result[0]; |
| } |
| |
| /** |
| * Creates and returns a new sub-progress monitor for the given parent |
| * monitor. |
| * |
| * @param monitor |
| * the parent progress monitor |
| * @param ticks |
| * the number of work ticks allocated from the parent monitor |
| * @return the new sub-progress monitor |
| * @since 3.0 |
| */ |
| private static IProgressMonitor getSubProgressMonitor( |
| IProgressMonitor monitor, int ticks) { |
| if (monitor != null) |
| return new SubProgressMonitor(monitor, ticks, |
| SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); |
| return new NullProgressMonitor(); |
| } |
| } |