1 11 package org.eclipse.jdt.internal.ui.javaeditor; 12 13 import java.io.ByteArrayInputStream ; 14 import java.io.ByteArrayOutputStream ; 15 import java.io.DataInputStream ; 16 import java.io.DataOutputStream ; 17 import java.io.IOException ; 18 import java.util.ArrayList ; 19 import java.util.HashSet ; 20 import java.util.List ; 21 import java.util.ResourceBundle ; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 26 import org.eclipse.swt.SWTError; 27 import org.eclipse.swt.custom.BusyIndicator; 28 import org.eclipse.swt.dnd.ByteArrayTransfer; 29 import org.eclipse.swt.dnd.Clipboard; 30 import org.eclipse.swt.dnd.DND; 31 import org.eclipse.swt.dnd.RTFTransfer; 32 import org.eclipse.swt.dnd.TextTransfer; 33 import org.eclipse.swt.dnd.Transfer; 34 import org.eclipse.swt.dnd.TransferData; 35 import org.eclipse.swt.widgets.Display; 36 import org.eclipse.swt.widgets.Shell; 37 38 import org.eclipse.jface.viewers.ISelection; 39 40 import org.eclipse.jface.text.IRewriteTarget; 41 import org.eclipse.jface.text.ITextOperationTarget; 42 import org.eclipse.jface.text.ITextSelection; 43 import org.eclipse.jface.text.Region; 44 45 import org.eclipse.ui.IWorkbenchPartSite; 46 import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; 47 import org.eclipse.ui.texteditor.ITextEditor; 48 import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; 49 import org.eclipse.ui.texteditor.TextEditorAction; 50 51 import org.eclipse.jdt.core.ICompilationUnit; 52 import org.eclipse.jdt.core.IJavaElement; 53 import org.eclipse.jdt.core.Signature; 54 import org.eclipse.jdt.core.dom.ASTNode; 55 import org.eclipse.jdt.core.dom.CompilationUnit; 56 import org.eclipse.jdt.core.dom.IBinding; 57 import org.eclipse.jdt.core.dom.ITypeBinding; 58 import org.eclipse.jdt.core.dom.Name; 59 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 60 61 import org.eclipse.jdt.internal.corext.codemanipulation.ImportReferencesCollector; 62 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 63 import org.eclipse.jdt.internal.corext.dom.Bindings; 64 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 65 66 import org.eclipse.jdt.ui.PreferenceConstants; 67 68 import org.eclipse.jdt.internal.ui.JavaPlugin; 69 70 71 74 public final class ClipboardOperationAction extends TextEditorAction { 75 76 public static class ClipboardData { 77 private String fOriginHandle; 78 private String [] fTypeImports; 79 private String [] fStaticImports; 80 81 public ClipboardData(IJavaElement origin, String [] typeImports, String [] staticImports) { 82 Assert.isNotNull(origin); 83 Assert.isNotNull(typeImports); 84 Assert.isNotNull(staticImports); 85 86 fTypeImports= typeImports; 87 fStaticImports= staticImports; 88 fOriginHandle= origin.getHandleIdentifier(); 89 } 90 91 public ClipboardData(byte[] bytes) throws IOException { 92 DataInputStream dataIn = new DataInputStream (new ByteArrayInputStream (bytes)); 93 try { 94 fOriginHandle= dataIn.readUTF(); 95 fTypeImports= readArray(dataIn); 96 fStaticImports= readArray(dataIn); 97 } finally { 98 dataIn.close(); 99 } 100 } 101 102 private static String [] readArray(DataInputStream dataIn) throws IOException { 103 int count= dataIn.readInt(); 104 105 String [] array= new String [count]; 106 for (int i = 0; i < count; i++) { 107 array[i]= dataIn.readUTF(); 108 } 109 return array; 110 } 111 112 private static void writeArray(DataOutputStream dataOut, String [] array) throws IOException { 113 dataOut.writeInt(array.length); 114 for (int i = 0; i < array.length; i++) { 115 dataOut.writeUTF(array[i]); 116 } 117 } 118 119 public String [] getTypeImports() { 120 return fTypeImports; 121 } 122 123 public String [] getStaticImports() { 124 return fStaticImports; 125 } 126 127 public boolean isFromSame(IJavaElement elem) { 128 return fOriginHandle.equals(elem.getHandleIdentifier()); 129 } 130 131 public byte[] serialize() throws IOException { 132 ByteArrayOutputStream out = new ByteArrayOutputStream (); 133 DataOutputStream dataOut = new DataOutputStream (out); 134 try { 135 dataOut.writeUTF(fOriginHandle); 136 writeArray(dataOut, fTypeImports); 137 writeArray(dataOut, fStaticImports); 138 } finally { 139 dataOut.close(); 140 out.close(); 141 } 142 143 return out.toByteArray(); 144 } 145 } 146 147 148 private static class ClipboardTransfer extends ByteArrayTransfer { 149 150 private static final String TYPE_NAME = "source-with-imports-transfer-format" + System.currentTimeMillis(); 152 private static final int TYPEID = registerType(TYPE_NAME); 153 154 157 protected int[] getTypeIds() { 158 return new int[] { TYPEID }; 159 } 160 161 164 protected String [] getTypeNames() { 165 return new String [] { TYPE_NAME }; 166 } 167 168 171 protected void javaToNative(Object data, TransferData transferData) { 172 if (data instanceof ClipboardData) { 173 try { 174 super.javaToNative(((ClipboardData) data).serialize(), transferData); 175 } catch (IOException e) { 176 } 178 } 179 } 180 181 184 protected Object nativeToJava(TransferData transferData) { 185 byte[] bytes = (byte[]) super.nativeToJava(transferData); 186 if (bytes != null) { 187 try { 188 return new ClipboardData(bytes); 189 } catch (IOException e) { 190 } 191 } 192 return null; 193 } 194 195 } 196 197 private static final ClipboardTransfer fgTransferInstance = new ClipboardTransfer(); 198 199 200 private int fOperationCode= -1; 201 202 private ITextOperationTarget fOperationTarget; 203 204 205 208 public ClipboardOperationAction(ResourceBundle bundle, String prefix, ITextEditor editor, int operationCode) { 209 super(bundle, prefix, editor); 210 fOperationCode= operationCode; 211 212 if (operationCode == ITextOperationTarget.CUT) { 213 setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION); 214 setActionDefinitionId(IWorkbenchActionDefinitionIds.CUT); 215 } else if (operationCode == ITextOperationTarget.COPY) { 216 setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION); 217 setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY); 218 } else if (operationCode == ITextOperationTarget.PASTE) { 219 setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION); 220 setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE); 221 } else { 222 Assert.isTrue(false, "Invalid operation code"); } 224 update(); 225 } 226 227 private boolean isReadOnlyOperation() { 228 return fOperationCode == ITextOperationTarget.COPY; 229 } 230 231 232 235 public void run() { 236 if (fOperationCode == -1 || fOperationTarget == null) 237 return; 238 239 ITextEditor editor= getTextEditor(); 240 if (editor == null) 241 return; 242 243 if (!isReadOnlyOperation() && !validateEditorInputState()) 244 return; 245 246 BusyIndicator.showWhile(getDisplay(), new Runnable () { 247 public void run() { 248 internalDoOperation(); 249 } 250 }); 251 } 252 253 private Shell getShell() { 254 ITextEditor editor= getTextEditor(); 255 if (editor != null) { 256 IWorkbenchPartSite site= editor.getSite(); 257 Shell shell= site.getShell(); 258 if (shell != null && !shell.isDisposed()) { 259 return shell; 260 } 261 } 262 return null; 263 } 264 265 private Display getDisplay() { 266 Shell shell= getShell(); 267 if (shell != null) { 268 return shell.getDisplay(); 269 } 270 return null; 271 } 272 273 274 protected final void internalDoOperation() { 275 if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_IMPORTS_ON_PASTE)) { 276 if (fOperationCode == ITextOperationTarget.PASTE) { 277 doPasteWithImportsOperation(); 278 } else { 279 doCutCopyWithImportsOperation(); 280 } 281 } else { 282 fOperationTarget.doOperation(fOperationCode); 283 } 284 } 285 286 289 public void update() { 290 super.update(); 291 292 if (!isReadOnlyOperation() && !canModifyEditor()) { 293 setEnabled(false); 294 return; 295 } 296 297 ITextEditor editor= getTextEditor(); 298 if (fOperationTarget == null && editor!= null && fOperationCode != -1) 299 fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class); 300 301 boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode)); 302 setEnabled(isEnabled); 303 } 304 305 308 public void setEditor(ITextEditor editor) { 309 super.setEditor(editor); 310 fOperationTarget= null; 311 } 312 313 314 private void doCutCopyWithImportsOperation() { 315 ITextEditor editor= getTextEditor(); 316 IJavaElement inputElement= (IJavaElement) editor.getEditorInput().getAdapter(IJavaElement.class); 317 ISelection selection= editor.getSelectionProvider().getSelection(); 318 319 Object clipboardData= null; 320 if (inputElement != null && selection instanceof ITextSelection && !selection.isEmpty()) { 321 ITextSelection textSelection= (ITextSelection) selection; 322 if (isNonTrivialSelection(textSelection)) { 323 clipboardData= getClipboardData(inputElement, textSelection.getOffset(), textSelection.getLength()); 324 } 325 } 326 327 fOperationTarget.doOperation(fOperationCode); 328 329 if (clipboardData != null) { 330 Clipboard clipboard= new Clipboard(getDisplay()); 331 try { 332 336 Object textData= clipboard.getContents(TextTransfer.getInstance()); 337 Object rtfData= clipboard.getContents(RTFTransfer.getInstance()); 338 339 ArrayList datas= new ArrayList (3); 340 ArrayList transfers= new ArrayList (3); 341 if (textData != null) { 342 datas.add(textData); 343 transfers.add(TextTransfer.getInstance()); 344 } 345 if (rtfData != null) { 346 datas.add(rtfData); 347 transfers.add(RTFTransfer.getInstance()); 348 } 349 350 354 if (datas.isEmpty()) 355 return; 356 357 datas.add(clipboardData); 358 transfers.add(fgTransferInstance); 359 360 Transfer[] dataTypes= (Transfer[]) transfers.toArray(new Transfer[transfers.size()]); 361 Object [] data= datas.toArray(); 362 setClipboardContents(clipboard, data, dataTypes); 363 } finally { 364 clipboard.dispose(); 365 } 366 } 367 } 368 369 private void setClipboardContents(Clipboard clipboard, Object [] datas, Transfer[] transfers) { 370 try { 371 clipboard.setContents(datas, transfers); 372 } catch (SWTError e) { 373 if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { 374 throw e; 375 } 376 } 378 } 379 380 private boolean isNonTrivialSelection(ITextSelection selection) { 381 if (selection.getLength() < 30) { 382 String text= selection.getText(); 383 if (text != null) { 384 for (int i= 0; i < text.length(); i++) { 385 if (!Character.isJavaIdentifierPart(text.charAt(i))) { 386 return true; 387 } 388 } 389 } 390 return false; 391 } 392 return true; 393 } 394 395 396 private ClipboardData getClipboardData(IJavaElement inputElement, int offset, int length) { 397 CompilationUnit astRoot= JavaPlugin.getDefault().getASTProvider().getAST(inputElement, ASTProvider.WAIT_ACTIVE_ONLY, null); 398 if (astRoot == null) { 399 return null; 400 } 401 402 List list= astRoot.imports(); 404 if (!list.isEmpty()) { 405 if (offset < ((ASTNode) list.get(list.size() - 1)).getStartPosition()) { 406 return null; 407 } 408 } else if (astRoot.getPackage() != null) { 409 if (offset < ((ASTNode) astRoot.getPackage()).getStartPosition()) { 410 return null; 411 } 412 } 413 414 ArrayList typeImportsRefs= new ArrayList (); 415 ArrayList staticImportsRefs= new ArrayList (); 416 417 ImportReferencesCollector.collect(astRoot, inputElement.getJavaProject(), new Region(offset, length), typeImportsRefs, staticImportsRefs); 418 419 if (typeImportsRefs.isEmpty() && staticImportsRefs.isEmpty()) { 420 return null; 421 } 422 423 HashSet namesToImport= new HashSet (typeImportsRefs.size()); 424 for (int i= 0; i < typeImportsRefs.size(); i++) { 425 Name curr= (Name) typeImportsRefs.get(i); 426 IBinding binding= curr.resolveBinding(); 427 if (binding != null && binding.getKind() == IBinding.TYPE) { 428 ITypeBinding typeBinding= (ITypeBinding) binding; 429 if (typeBinding.isArray()) { 430 typeBinding= typeBinding.getElementType(); 431 } 432 if (typeBinding.isTypeVariable() || typeBinding.isCapture() || typeBinding.isWildcardType()) { continue; 434 } 435 436 if (typeBinding.isMember() || typeBinding.isTopLevel()) { 437 String name= Bindings.getRawQualifiedName(typeBinding); 438 if (name.length() > 0) { 439 namesToImport.add(name); 440 } 441 } 442 } 443 } 444 445 HashSet staticsToImport= new HashSet (staticImportsRefs.size()); 446 for (int i= 0; i < staticImportsRefs.size(); i++) { 447 Name curr= (Name) staticImportsRefs.get(i); 448 IBinding binding= curr.resolveBinding(); 449 if (binding != null) { 450 StringBuffer buf= new StringBuffer (Bindings.getImportName(binding)); 451 if (binding.getKind() == IBinding.METHOD) { 452 buf.append("()"); } 454 staticsToImport.add(buf.toString()); 455 } 456 } 457 458 459 if (namesToImport.isEmpty() && staticsToImport.isEmpty()) { 460 return null; 461 } 462 463 String [] typeImports= (String []) namesToImport.toArray(new String [namesToImport.size()]); 464 String [] staticImports= (String []) staticsToImport.toArray(new String [staticsToImport.size()]); 465 return new ClipboardData(inputElement, typeImports, staticImports); 466 } 467 468 469 private void doPasteWithImportsOperation() { 470 ITextEditor editor= getTextEditor(); 471 IJavaElement inputElement= (IJavaElement) editor.getEditorInput().getAdapter(IJavaElement.class); 472 473 Clipboard clipboard= new Clipboard(getDisplay()); 474 ClipboardData importsData= (ClipboardData) clipboard.getContents(fgTransferInstance); 475 if (importsData != null && inputElement instanceof ICompilationUnit && !importsData.isFromSame(inputElement)) { 476 IRewriteTarget target= editor != null ? (IRewriteTarget) editor.getAdapter(IRewriteTarget.class) : null; 478 if (target != null) { 479 target.beginCompoundChange(); 480 } 481 try { 482 fOperationTarget.doOperation(fOperationCode); 483 addImports((ICompilationUnit) inputElement, importsData); 484 } catch (CoreException e) { 485 JavaPlugin.log(e); 486 } finally { 487 if (target != null) { 488 target.endCompoundChange(); 489 } 490 } 491 } else { 492 fOperationTarget.doOperation(fOperationCode); 493 } 494 } 495 496 497 private void addImports(ICompilationUnit unit, ClipboardData data) throws CoreException { 498 ImportRewrite rewrite= StubUtility.createImportRewrite(unit, true); 499 String [] imports= data.getTypeImports(); 500 for (int i= 0; i < imports.length; i++) { 501 rewrite.addImport(imports[i]); 502 } 503 String [] staticImports= data.getStaticImports(); 504 for (int i= 0; i < staticImports.length; i++) { 505 String name= Signature.getSimpleName(staticImports[i]); 506 boolean isField= !name.endsWith("()"); if (!isField) { 508 name= name.substring(0, name.length() - 2); 509 } 510 String qualifier= Signature.getQualifier(staticImports[i]); 511 rewrite.addStaticImport(qualifier, name, isField); 512 } 513 514 JavaModelUtil.applyEdit(unit, rewrite.rewriteImports(null), false, null); 515 } 516 517 518 } 519 | Popular Tags |