diff --git a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardCompare.java b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardCompare.java new file mode 100644 index 00000000000..c433acd757f --- /dev/null +++ b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardCompare.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.CompareEditorInput; +import org.eclipse.compare.CompareUI; +import org.eclipse.compare.IStreamContentAccessor; +import org.eclipse.compare.ITypedElement; +import org.eclipse.compare.structuremergeviewer.DiffNode; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.texteditor.ITextEditor; + +public class ClipboardCompare extends BaseCompareAction implements IObjectActionDelegate { + + private String clipboard = "Clipboard"; //$NON-NLS-1$ + private String compareFailed = "Comparision Failed"; //$NON-NLS-1$ + + private IWorkbenchPart activePart; + + @Override + protected void run(ISelection selection) { + IFile[] files = Utilities.getFiles(selection); + Shell parentShell = CompareUIPlugin.getShell(); + for (IFile file : files) { + try { + processComparison(file, parentShell); + } catch (Exception e) { + MessageDialog.openError(parentShell, compareFailed, e.getMessage()); + } + } + } + @Override + protected boolean isEnabled(ISelection selection) { + return Utilities.getFiles(selection).length == 1 && getClipboard() != null; + } + + /** + * Process comparison with selection or entire editor contents with contents in + * clipboard + * + * @param file Editor file + * @param parentShell The shell containing this window's controls + * @throws IOException, CoreException + */ + private void processComparison(IFile file, Shell parentShell) throws IOException, CoreException { + String cb = getClipboard().toString(); + String fileName = file.getName(); + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IEditorPart editor = page.getActiveEditor(); + if (activePart instanceof IViewPart) { + String fileContents = new String(file.getContents().readAllBytes(), file.getCharset()); + showComparison(fileContents, fileName, cb, parentShell); + return; + } + final String selectionContents; + if (editor instanceof ITextEditor txtEditor) { + ISelection selection = txtEditor.getSelectionProvider().getSelection(); + if (selection instanceof ITextSelection textSelection) { + selectionContents = textSelection.getText(); + if (selectionContents.isEmpty()) { + String fileContents = new String(file.getContents().readAllBytes(), file.getCharset()); + showComparison(fileContents, fileName, cb, parentShell); + } else { + showComparison(selectionContents, fileName, cb, parentShell); + } + return; + } + } + if (editor instanceof CompareEditor existingCompare) { // if selection is from compare editor itself + ISelection selection = existingCompare.getSite().getSelectionProvider().getSelection(); + if (selection instanceof ITextSelection textSelection) { + String selectedText = textSelection.getText(); + String fileContents = new String(file.getContents().readAllBytes(), file.getCharset()); + showComparison(fileContents, fileName, selectedText, parentShell); + } + } + } + + /** + * Shows comparison result + * + * @param source Either selection from current editor or entire + * editor if no selection + * @param fileName Editor file name + * @param clipboardContents Contents in clipboard + * @param parentShell The shell containing this window's controls + */ + private void showComparison(String source, String fileName, String clipboardContents, Shell parentShell) { + class ClipboardTypedElement implements ITypedElement, IStreamContentAccessor { + private final String name; + private final String content; + + public ClipboardTypedElement(String name, String content) { + this.name = name; + this.content = content; + } + + @Override + public String getName() { + return name; + } + + @Override + public Image getImage() { + return null; + } + + @Override + public String getType() { + return null; + } + + @Override + public InputStream getContents() throws CoreException { + return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); + } + + } + if (source == null) { + MessageDialog.openInformation(parentShell, compareFailed, "Failed to process selected file"); //$NON-NLS-1$ + return; + } + CompareConfiguration config = new CompareConfiguration(); + config.setLeftLabel(fileName); + config.setRightLabel(clipboard); + config.setLeftEditable(true); + config.setRightEditable(true); + CompareEditorInput compareInput = new CompareEditorInput(config) { + @Override + protected Object prepareInput(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + return new DiffNode(new ClipboardTypedElement(fileName, source), + new ClipboardTypedElement(clipboard, clipboardContents)); + + } + }; + CompareUI.openCompareEditor(compareInput); + } + + /** + * Returns Clipboard Object or null if there is nothing in clipboard + * + * @returns Clipboard Object or null + */ + private Object getClipboard() { + Clipboard clip = new Clipboard(Display.getDefault()); + return clip.getContents(TextTransfer.getInstance()); + } + + @Override + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + this.activePart = targetPart; + } + +} diff --git a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardReplace.java b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardReplace.java new file mode 100644 index 00000000000..638547796a4 --- /dev/null +++ b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ClipboardReplace.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.texteditor.ITextEditor; + +public class ClipboardReplace extends BaseCompareAction { + + @Override + protected void run(ISelection selection) { + IFile[] files = Utilities.getFiles(selection); + for (IFile file : files) { + try { + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IEditorPart editor = page.getActiveEditor(); + IEditorInput input = editor.getEditorInput(); + if (input instanceof IFileEditorInput ed) { + IFile file2 = ed.getFile(); + String fileName2 = file2.getName(); + if (!file.getName().equals(fileName2)) { + ByteArrayInputStream source = new ByteArrayInputStream( + getClipboard().toString().getBytes(StandardCharsets.UTF_8)); + file.setContents(source, IResource.FORCE, null); + return; + } + } + if (editor instanceof ITextEditor txtEditor) { + ISelection selection2 = txtEditor.getSelectionProvider().getSelection(); + if (selection2 instanceof ITextSelection textSelection) { + int offset = textSelection.getOffset(); + int len = textSelection.getLength(); + if (len > 0) { + IDocument doc = ((ITextEditor) editor).getDocumentProvider() + .getDocument(editor.getEditorInput()); + doc.replace(offset, len, getClipboard().toString()); + return; + } + ByteArrayInputStream source = new ByteArrayInputStream( + getClipboard().toString().getBytes(StandardCharsets.UTF_8)); + file.setContents(source, IResource.FORCE, null); + } + } + + } catch (Exception e) { + Shell parentShell = CompareUIPlugin.getShell(); + MessageDialog.openError(parentShell, "Replace Failed", e.getMessage()); //$NON-NLS-1$ + } + } + } + @Override + protected boolean isEnabled(ISelection selection) { + return Utilities.getFiles(selection).length == 1 && getClipboard() != null; + } + + /** + * Returns Clipboard Object or null if there is nothing in clipboard + * + * @returns Clipboard Object or null + */ + private Object getClipboard() { + Clipboard clip = new Clipboard(Display.getDefault()); + return clip.getContents(TextTransfer.getInstance()); + } + +} diff --git a/team/bundles/org.eclipse.compare/plugin.properties b/team/bundles/org.eclipse.compare/plugin.properties index 493df3f9a36..823ffdd18c0 100644 --- a/team/bundles/org.eclipse.compare/plugin.properties +++ b/team/bundles/org.eclipse.compare/plugin.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2016 IBM Corporation and others. +# Copyright (c) 2000, 2025 IBM Corporation and others. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -98,6 +98,12 @@ CompareWithOtherResource.tooltip= Open the 'Compare With' Dialog CompareWithHistoryAction.label= &Local History... CompareWithHistoryAction.tooltip= Compare the Selected Resource with Local History +CompareWithClipboardAction.label= Clipboard +CompareWithClipboardAction.tooltip= Compare the selection or entire contents in editor with contents in clipboard + +ReplaceWithClipboardAction.label= Clipboard +ReplaceWithClipboardAction.tooltip= Replace the selection or entire contents in editor with contents in clipboard + ReplaceWithMenu.label= Rep&lace With ReplaceFromHistoryAction.label= &Local History... diff --git a/team/bundles/org.eclipse.compare/plugin.xml b/team/bundles/org.eclipse.compare/plugin.xml index 525290ad943..ca52ac4c299 100644 --- a/team/bundles/org.eclipse.compare/plugin.xml +++ b/team/bundles/org.eclipse.compare/plugin.xml @@ -296,6 +296,14 @@ enablesFor="1" id="replaceWithPreviousFromHistory"> + + + +