/* * Copyright (c) 2011, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.internal.text.editor; import com.google.dart.tools.ui.PreferenceConstants; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.dnd.ByteArrayTransfer; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; import org.eclipse.ui.texteditor.TextEditorAction; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ResourceBundle; /** * Action for cut/copy and paste with support for adding imports on paste. */ public final class ClipboardOperationAction extends TextEditorAction { public static class ClipboardData { private static String[] readArray(DataInputStream dataIn) throws IOException { int count = dataIn.readInt(); String[] array = new String[count]; for (int i = 0; i < count; i++) { array[i] = dataIn.readUTF(); } return array; } private static void writeArray(DataOutputStream dataOut, String[] array) throws IOException { dataOut.writeInt(array.length); for (int i = 0; i < array.length; i++) { dataOut.writeUTF(array[i]); } } private String fOriginHandle; private String[] fTypeImports; private String[] fStaticImports; public ClipboardData(byte[] bytes) throws IOException { DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(bytes)); try { fOriginHandle = dataIn.readUTF(); fTypeImports = readArray(dataIn); fStaticImports = readArray(dataIn); } finally { dataIn.close(); } } public String[] getStaticImports() { return fStaticImports; } public String[] getTypeImports() { return fTypeImports; } public byte[] serialize() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); DataOutputStream dataOut = new DataOutputStream(out); try { dataOut.writeUTF(fOriginHandle); writeArray(dataOut, fTypeImports); writeArray(dataOut, fStaticImports); } finally { dataOut.close(); out.close(); } return out.toByteArray(); } } private static class ClipboardTransfer extends ByteArrayTransfer { private static final String TYPE_NAME = "source-with-imports-transfer-format" + System.currentTimeMillis(); //$NON-NLS-1$ private static final int TYPEID = registerType(TYPE_NAME); /* * (non-Javadoc) * * @see org.eclipse.swt.dnd.Transfer#getTypeIds() */ @Override protected int[] getTypeIds() { return new int[] {TYPEID}; } /* * (non-Javadoc) * * @see org.eclipse.swt.dnd.Transfer#getTypeNames() */ @Override protected String[] getTypeNames() { return new String[] {TYPE_NAME}; } /* * (non-Javadoc) * * @see org.eclipse.swt.dnd.Transfer#javaToNative(java.lang.Object, * org.eclipse.swt.dnd.TransferData) */ @Override protected void javaToNative(Object data, TransferData transferData) { if (data instanceof ClipboardData) { try { super.javaToNative(((ClipboardData) data).serialize(), transferData); } catch (IOException e) { // it's best to send nothing if there were problems } } } /* * (non-Javadoc) Method declared on Transfer. */ @Override protected Object nativeToJava(TransferData transferData) { byte[] bytes = (byte[]) super.nativeToJava(transferData); if (bytes != null) { try { return new ClipboardData(bytes); } catch (IOException e) { } } return null; } } private static final ClipboardTransfer fgTransferInstance = new ClipboardTransfer(); /** The text operation code */ private int fOperationCode = -1; /** The text operation target */ private ITextOperationTarget fOperationTarget; /** * Creates the action. */ @SuppressWarnings("deprecation") public ClipboardOperationAction(ResourceBundle bundle, String prefix, ITextEditor editor, int operationCode) { super(bundle, prefix, editor); fOperationCode = operationCode; if (operationCode == ITextOperationTarget.CUT) { setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION); setActionDefinitionId(IWorkbenchActionDefinitionIds.CUT); } else if (operationCode == ITextOperationTarget.COPY) { setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION); setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY); } else if (operationCode == ITextOperationTarget.PASTE) { setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION); setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE); } else { Assert.isTrue(false, "Invalid operation code"); //$NON-NLS-1$ } update(); } /* * (non-Javadoc) * * @see org.eclipse.jface.action.IAction#run() */ @Override public void run() { if (fOperationCode == -1 || fOperationTarget == null) { return; } ITextEditor editor = getTextEditor(); if (editor == null) { return; } if (!isReadOnlyOperation() && !validateEditorInputState()) { return; } BusyIndicator.showWhile(getDisplay(), new Runnable() { @Override public void run() { internalDoOperation(); } }); } /* * (non-Javadoc) * * @see org.eclipse.ui.texteditor.TextEditorAction#setEditor(org.eclipse.ui.texteditor * .ITextEditor) */ @Override public void setEditor(ITextEditor editor) { super.setEditor(editor); fOperationTarget = null; } /* * (non-Javadoc) * * @see org.eclipse.ui.texteditor.IUpdate#update() */ @Override public void update() { super.update(); if (!isReadOnlyOperation() && !canModifyEditor()) { setEnabled(false); return; } ITextEditor editor = getTextEditor(); if (fOperationTarget == null && editor != null && fOperationCode != -1) { fOperationTarget = (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class); } boolean isEnabled = (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode)); setEnabled(isEnabled); } protected final void internalDoOperation() { if (PreferenceConstants.getPreferenceStore().getBoolean( PreferenceConstants.EDITOR_IMPORTS_ON_PASTE)) { if (fOperationCode == ITextOperationTarget.PASTE) { doPasteWithImportsOperation(); } else { doCutCopyWithImportsOperation(); } } else { fOperationTarget.doOperation(fOperationCode); } } private void doCutCopyWithImportsOperation() { fOperationTarget.doOperation(fOperationCode); } private void doPasteWithImportsOperation() { Clipboard clipboard = new Clipboard(getDisplay()); ClipboardData importsData = (ClipboardData) clipboard.getContents(fgTransferInstance); if (importsData == null || importsData.fOriginHandle == null) { fOperationTarget.doOperation(fOperationCode); } } private Display getDisplay() { Shell shell = getShell(); if (shell != null) { return shell.getDisplay(); } return null; } private Shell getShell() { ITextEditor editor = getTextEditor(); if (editor != null) { IWorkbenchPartSite site = editor.getSite(); Shell shell = site.getShell(); if (shell != null && !shell.isDisposed()) { return shell; } } return null; } private boolean isReadOnlyOperation() { return fOperationCode == ITextOperationTarget.COPY; } }