Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.embed.swt; 027 028import java.lang.reflect.Field; 029import java.nio.IntBuffer; 030 031import java.security.AccessController; 032import java.security.PrivilegedAction; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.Map; 036import java.util.Set; 037 038import com.sun.glass.ui.Application; 039import com.sun.javafx.cursor.CursorFrame; 040import com.sun.javafx.cursor.CursorType; 041 042import javafx.application.Platform; 043import javafx.scene.Scene; 044import javafx.scene.input.TransferMode; 045 046import com.sun.javafx.application.PlatformImpl; 047import com.sun.javafx.embed.AbstractEvents; 048import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface; 049import com.sun.javafx.embed.EmbeddedSceneDragStartListenerInterface; 050import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface; 051import com.sun.javafx.embed.EmbeddedSceneInterface; 052import com.sun.javafx.embed.EmbeddedStageInterface; 053import com.sun.javafx.embed.HostInterface; 054import com.sun.javafx.stage.EmbeddedWindow; 055 056import org.eclipse.swt.dnd.DND; 057import org.eclipse.swt.dnd.DragSource; 058import org.eclipse.swt.dnd.DragSourceListener; 059import org.eclipse.swt.dnd.DropTarget; 060import org.eclipse.swt.dnd.DropTargetEvent; 061import org.eclipse.swt.dnd.DropTargetListener; 062import org.eclipse.swt.dnd.FileTransfer; 063import org.eclipse.swt.dnd.HTMLTransfer; 064import org.eclipse.swt.dnd.ImageTransfer; 065import org.eclipse.swt.dnd.RTFTransfer; 066import org.eclipse.swt.dnd.TextTransfer; 067import org.eclipse.swt.dnd.Transfer; 068import org.eclipse.swt.dnd.TransferData; 069import org.eclipse.swt.dnd.URLTransfer; 070import org.eclipse.swt.events.ControlEvent; 071import org.eclipse.swt.events.DisposeEvent; 072import org.eclipse.swt.events.DisposeListener; 073import org.eclipse.swt.events.FocusEvent; 074import org.eclipse.swt.events.KeyEvent; 075import org.eclipse.swt.events.KeyListener; 076import org.eclipse.swt.events.MenuDetectEvent; 077import org.eclipse.swt.events.MenuDetectListener; 078import org.eclipse.swt.events.MouseEvent; 079import org.eclipse.swt.events.MouseListener; 080import org.eclipse.swt.events.MouseMoveListener; 081import org.eclipse.swt.events.PaintEvent; 082import org.eclipse.swt.events.PaintListener; 083 084import org.eclipse.swt.widgets.Canvas; 085import org.eclipse.swt.widgets.Composite; 086import org.eclipse.swt.widgets.Display; 087 088import org.eclipse.swt.graphics.Image; 089import org.eclipse.swt.graphics.ImageData; 090import org.eclipse.swt.graphics.PaletteData; 091import org.eclipse.swt.graphics.Point; 092import org.eclipse.swt.graphics.Rectangle; 093 094import org.eclipse.swt.SWT; 095import org.eclipse.swt.events.ControlListener; 096import org.eclipse.swt.events.FocusListener; 097import org.eclipse.swt.events.MouseTrackListener; 098import org.eclipse.swt.events.MouseWheelListener; 099 100/** 101 * {@code FXCanvas} is a component to embed JavaFX content into 102 * SWT applications. The content to be displayed is specified 103 * with the {@link #setScene} method that accepts an instance of 104 * JavaFX {@code Scene}. After the scene is assigned, it gets 105 * repainted automatically. All the input and focus events are 106 * forwarded to the scene transparently to the developer. 107 * <p> 108 * Here is a typical pattern how {@code FXCanvas} can used: 109 * <pre> 110 * public class Test { 111 * private static Scene createScene() { 112 * Group group = new Group(); 113 * Scene scene = new Scene(group); 114 * Button button = new Button("JFX Button"); 115 * group.getChildren().add(button); 116 * return scene; 117 * } 118 * 119 * public static void main(String[] args) { 120 * Display display = new Display(); 121 * Shell shell = new Shell(display); 122 * shell.setLayout(new FillLayout()); 123 * FXCanvas canvas = new FXCanvas(shell, SWT.NONE); 124 * Scene scene = createScene(); 125 * canvas.setScene(scene); 126 * shell.open(); 127 * while (!shell.isDisposed()) { 128 * if (!display.readAndDispatch()) display.sleep(); 129 * } 130 * display.dispose(); 131 * } 132 * } 133 * </pre> 134 * 135 * 136 */ 137public class FXCanvas extends Canvas { 138 139 private HostContainer hostContainer; 140 private volatile EmbeddedWindow stage; 141 private volatile Scene scene; 142 private EmbeddedStageInterface stagePeer; 143 private EmbeddedSceneInterface scenePeer; 144 145 private int pWidth = 0; 146 private int pHeight = 0; 147 148 private volatile int pPreferredWidth = -1; 149 private volatile int pPreferredHeight = -1; 150 151 private IntBuffer pixelsBuf = null; 152 153 static Transfer [] StandardTransfers = new Transfer [] { 154 TextTransfer.getInstance(), 155 RTFTransfer.getInstance(), 156 HTMLTransfer.getInstance(), 157 URLTransfer.getInstance(), 158 ImageTransfer.getInstance(), 159 FileTransfer.getInstance(), 160 }; 161 static Transfer [] CustomTransfers = new Transfer [0]; 162 163 static Transfer [] getAllTransfers () { 164 Transfer [] transfers = new Transfer[StandardTransfers.length + CustomTransfers.length]; 165 System.arraycopy(StandardTransfers, 0, transfers, 0, StandardTransfers.length); 166 System.arraycopy(CustomTransfers, 0, transfers, StandardTransfers.length, CustomTransfers.length); 167 return transfers; 168 } 169 170 static Transfer getCustomTransfer(String mime) { 171 for (int i=0; i<CustomTransfers.length; i++) { 172 if (((CustomTransfer)CustomTransfers[i]).getMime().equals(mime)) { 173 return CustomTransfers[i]; 174 } 175 } 176 Transfer transfer = new CustomTransfer (mime, mime); 177 Transfer [] newCustom = new Transfer [CustomTransfers.length + 1]; 178 System.arraycopy(CustomTransfers, 0, newCustom, 0, CustomTransfers.length); 179 newCustom[CustomTransfers.length] = transfer; 180 CustomTransfers = newCustom; 181 return transfer; 182 } 183 184 /** 185 * @inheritDoc 186 */ 187 public FXCanvas(Composite parent, int style) { 188 super(parent, style | SWT.NO_BACKGROUND); 189 initFx(); 190 hostContainer = new HostContainer(); 191 registerEventListeners(); 192 } 193 194 private static void initFx() { 195 AccessController.doPrivileged(new PrivilegedAction<Void>() { 196 public Void run() { 197 System.setProperty("javafx.embed.isEventThread", "true"); 198 return null; 199 } 200 }); 201 Map map = Application.getDeviceDetails(); 202 if (map == null) { 203 Application.setDeviceDetails(map = new HashMap()); 204 } 205 if (map.get("javafx.embed.eventProc") == null) { 206 long eventProc = 0; 207 try { 208 Field field = Display.class.getDeclaredField("eventProc"); 209 field.setAccessible(true); 210 if (field.getType() == int.class) { 211 eventProc = field.getLong(Display.getDefault()); 212 } else { 213 if (field.getType() == long.class) { 214 eventProc = field.getLong(Display.getDefault()); 215 } 216 } 217 } catch (Throwable th) { 218 //Fail silently 219 } 220 map.put("javafx.embed.eventProc", eventProc); 221 } 222 // Note that calling PlatformImpl.startup more than once is OK 223 PlatformImpl.startup(new Runnable() { 224 @Override 225 public void run() { 226 } 227 }); 228 } 229 230 /** 231 * {@inheritDoc} 232 */ 233 public Point computeSize (int wHint, int hHint, boolean changed) { 234 checkWidget(); 235 if (wHint == -1 && hHint == -1) { 236 if (pPreferredWidth != -1 && pPreferredHeight != -1) { 237 return new Point (pPreferredWidth, pPreferredHeight); 238 } 239 } 240 return super.computeSize(wHint, hHint, changed); 241 } 242 243 /** 244 * Returns the JavaFX scene attached to this {@code FXCanvas}. 245 * 246 * @return the {@code Scene} attached to this {@code FXCanvas} 247 */ 248 public Scene getScene() { 249 checkWidget(); 250 return scene; 251 } 252 253 /** 254 * Attaches a {@code Scene} object to display in this {@code 255 * FXCanvas}. This method must called either on the JavaFX 256 * JavaFX application thread (which is the same as the SWT 257 * event dispatch thread). 258 * 259 * @param newScene a scene to display in this {@code FXCanvas} 260 * 261 * @see javafx.application.Platform#isFxApplicationThread() 262 */ 263 public void setScene(final Scene newScene) { 264 checkWidget(); 265 266 if ((stage == null) && (newScene != null)) { 267 stage = new EmbeddedWindow(hostContainer); 268 stage.show(); 269 } 270 scene = newScene; 271 if (stage != null) { 272 stage.setScene(newScene); 273 } 274 if ((stage != null) && (newScene == null)) { 275 stage.hide(); 276 stage = null; 277 } 278 } 279 280 // Note that removing the listeners is unnecessary 281 private void registerEventListeners() { 282 addDisposeListener(new DisposeListener() { 283 @Override 284 public void widgetDisposed(DisposeEvent de) { 285 FXCanvas.this.widgetDisposed(de); 286 } 287 }); 288 289 addPaintListener(new PaintListener() { 290 @Override 291 public void paintControl(PaintEvent pe) { 292 FXCanvas.this.paintControl(pe); 293 } 294 }); 295 296 addMouseListener(new MouseListener() { 297 @Override 298 public void mouseDoubleClick(MouseEvent me) { 299 // Clicks and double-clicks are handled in FX 300 } 301 @Override 302 public void mouseDown(MouseEvent me) { 303 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_PRESSED); 304 } 305 @Override 306 public void mouseUp(MouseEvent me) { 307 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_RELEASED); 308 } 309 }); 310 311 addMouseMoveListener(new MouseMoveListener() { 312 @Override 313 public void mouseMove(MouseEvent me) { 314 if ((me.stateMask & SWT.BUTTON_MASK) != 0) { 315 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_DRAGGED); 316 } else { 317 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_MOVED); 318 } 319 } 320 }); 321 322 addMouseWheelListener(new MouseWheelListener() { 323 @Override 324 public void mouseScrolled(MouseEvent me) { 325 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_WHEEL); 326 } 327 }); 328 329 addMouseTrackListener(new MouseTrackListener() { 330 @Override 331 public void mouseEnter(MouseEvent me) { 332 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_ENTERED); 333 } 334 @Override 335 public void mouseExit(MouseEvent me) { 336 FXCanvas.this.sendMouseEventToFX(me, AbstractEvents.MOUSEEVENT_EXITED); 337 } 338 @Override 339 public void mouseHover(MouseEvent me) { 340 // No mouse hovering in FX 341 } 342 }); 343 344 addControlListener(new ControlListener() { 345 @Override 346 public void controlMoved(ControlEvent ce) { 347 FXCanvas.this.sendMoveEventToFX(); 348 } 349 @Override 350 public void controlResized(ControlEvent ce) { 351 FXCanvas.this.sendResizeEventToFX(); 352 } 353 }); 354 355 addFocusListener(new FocusListener() { 356 @Override 357 public void focusGained(FocusEvent fe) { 358 FXCanvas.this.sendFocusEventToFX(fe, true); 359 } 360 @Override 361 public void focusLost(FocusEvent fe) { 362 FXCanvas.this.sendFocusEventToFX(fe, false); 363 } 364 }); 365 366 addKeyListener(new KeyListener() { 367 @Override 368 public void keyPressed(KeyEvent e) { 369 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyDown); 370 371 } 372 @Override 373 public void keyReleased(KeyEvent e) { 374 FXCanvas.this.sendKeyEventToFX(e, SWT.KeyUp); 375 } 376 }); 377 378 addMenuDetectListener(new MenuDetectListener() { 379 @Override 380 public void menuDetected(MenuDetectEvent e) { 381 FXCanvas.this.sendMenuEventToFX(e); 382 } 383 }); 384 } 385 386 private void widgetDisposed(DisposeEvent de) { 387 if (stage != null) { 388 stage.hide(); 389 } 390 } 391 392 int lastWidth, lastHeight; 393 IntBuffer lastPixelsBuf = null; 394 private void paintControl(PaintEvent pe) { 395 if ((scenePeer == null) || (pixelsBuf == null)) { 396 return; 397 } 398 399 // if we can't get the pixels, draw the bits that were there before 400 IntBuffer buffer = pixelsBuf; 401 int width = pWidth, height = pHeight; 402 if (scenePeer.getPixels(pixelsBuf, pWidth, pHeight)) { 403 width = lastWidth = pWidth; 404 height = lastHeight = pHeight; 405 buffer = lastPixelsBuf = pixelsBuf; 406 } else { 407 if (lastPixelsBuf == null) return; 408 width = lastWidth; 409 height = lastHeight; 410 buffer = lastPixelsBuf; 411 } 412 413 // Consider optimizing this 414 ImageData imageData = null; 415 if ("win32".equals(SWT.getPlatform())) { 416 PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 417 int scanline = width * 4; 418 byte[] dstData = new byte[scanline * height]; 419 int[] srcData = buffer.array(); 420 int dp = 0, sp = 0; 421 for (int y = 0; y < height; y++) { 422 for (int x = 0; x < width; x++) { 423 int p = srcData[sp++]; 424 dstData[dp++] = (byte) (p & 0xFF); //dst:blue 425 dstData[dp++] = (byte)((p >> 8) & 0xFF); //dst:green 426 dstData[dp++] = (byte)((p >> 16) & 0xFF); //dst:green 427 dstData[dp++] = (byte)0x00; //alpha 428 } 429 } 430 /*ImageData*/ imageData = new ImageData(width, height, 32, palette, 4, dstData); 431 } else { 432 PaletteData palette = new PaletteData(0x00ff0000, 0x0000ff00, 0x000000ff); 433 /*ImageData*/ imageData = new ImageData(width, height, 32, palette); 434 imageData.setPixels(0, 0,width * height, buffer.array(), 0); 435 } 436 437 Image image = new Image(Display.getDefault(), imageData); 438 pe.gc.drawImage(image, 0, 0); 439 image.dispose(); 440 } 441 442 private void sendMoveEventToFX() { 443 if ((stagePeer == null) /*|| !isShowing()*/) { 444 return; 445 } 446 Rectangle rect = getClientArea(); 447 Point los = toDisplay(rect.x, rect.y); 448 stagePeer.setLocation(los.x, los.y); 449 } 450 451 private void sendMouseEventToFX(MouseEvent me, int embedMouseType) { 452 if (scenePeer == null) { 453 return; 454 } 455 456 Point los = toDisplay(me.x, me.y); 457 boolean primaryBtnDown = (me.stateMask & SWT.BUTTON1) != 0; 458 boolean middleBtnDown = (me.stateMask & SWT.BUTTON2) != 0; 459 boolean secondaryBtnDown = (me.stateMask & SWT.BUTTON3) != 0; 460 boolean shift = (me.stateMask & SWT.SHIFT) != 0; 461 boolean control = (me.stateMask & SWT.CONTROL) != 0; 462 boolean alt = (me.stateMask & SWT.ALT) != 0; 463 boolean meta = (me.stateMask & SWT.COMMAND) != 0; 464 switch (embedMouseType) { 465 case AbstractEvents.MOUSEEVENT_PRESSED: 466 primaryBtnDown |= me.button == 1; 467 middleBtnDown |= me.button == 2; 468 secondaryBtnDown |= me.button == 3; 469 break; 470 case AbstractEvents.MOUSEEVENT_RELEASED: 471 primaryBtnDown &= me.button != 1; 472 middleBtnDown &= me.button != 2; 473 secondaryBtnDown &= me.button != 3; 474 break; 475 default: 476 break; 477 } 478 scenePeer.mouseEvent( 479 embedMouseType, 480 SWTEvents.mouseButtonToEmbedMouseButton(me.button, me.stateMask), 481 primaryBtnDown, middleBtnDown, secondaryBtnDown, 482 me.count, 483 me.x, me.y, 484 los.x, los.y, 485 shift, control, alt, meta, 486 SWTEvents.getWheelRotation(me, embedMouseType), false); // TODO: popup trigger 487 } 488 489 private void sendKeyEventToFX(final KeyEvent e, int type) { 490 if (scenePeer == null /*|| !isFxEnabled()*/) { 491 return; 492 } 493 int stateMask = e.stateMask; 494 if (type == SWT.KeyDown) { 495 if (e.keyCode == SWT.SHIFT) stateMask |= SWT.SHIFT; 496 if (e.keyCode == SWT.CONTROL) stateMask |= SWT.CONTROL; 497 if (e.keyCode == SWT.ALT) stateMask |= SWT.ALT; 498 if (e.keyCode == SWT.COMMAND) stateMask |= SWT.COMMAND; 499 } else { 500 if (e.keyCode == SWT.SHIFT) stateMask &= ~SWT.SHIFT; 501 if (e.keyCode == SWT.CONTROL) stateMask &= ~SWT.CONTROL; 502 if (e.keyCode == SWT.ALT) stateMask &= ~SWT.ALT; 503 if (e.keyCode == SWT.COMMAND) stateMask &= ~SWT.COMMAND; 504 } 505 int keyCode = SWTEvents.keyCodeToEmbedKeyCode(e.keyCode); 506 scenePeer.keyEvent( 507 SWTEvents.keyIDToEmbedKeyType(type), 508 keyCode, new char[0], 509 SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask)); 510 if (e.character != '\0' && type == SWT.KeyDown) { 511 char[] chars = new char[] { e.character }; 512 scenePeer.keyEvent( 513 AbstractEvents.KEYEVENT_TYPED, 514 e.keyCode, chars, 515 SWTEvents.keyModifiersToEmbedKeyModifiers(stateMask)); 516 } 517 } 518 519 private void sendMenuEventToFX(MenuDetectEvent me) { 520 if (scenePeer == null /*|| !isFxEnabled()*/) { 521 return; 522 } 523 Point pt = toControl(me.x, me.y); 524 scenePeer.menuEvent(pt.x, pt.y, me.x, me.y, false); 525 } 526 527 private void sendResizeEventToFX() { 528 529 // force the panel to draw right away (avoid black rectangle) 530 redraw(); 531 update(); 532 533 pWidth = getClientArea().width; 534 pHeight = getClientArea().height; 535 536 if ((pWidth <= 0) || (pHeight <= 0)) { 537 pixelsBuf = lastPixelsBuf = null; 538 } else { 539 pixelsBuf = IntBuffer.allocate(pWidth * pHeight); 540 } 541 542 if (scenePeer == null) { 543 return; 544 } 545 546 stagePeer.setSize(pWidth, pHeight); 547 scenePeer.setSize(pWidth, pHeight); 548 } 549 550 private void sendFocusEventToFX(FocusEvent fe, boolean focused) { 551 if ((stage == null) || (stagePeer == null)) { 552 return; 553 } 554 int focusCause = (focused ? 555 AbstractEvents.FOCUSEVENT_ACTIVATED : 556 AbstractEvents.FOCUSEVENT_DEACTIVATED); 557 stagePeer.setFocused(focused, focusCause); 558 } 559 560 private class HostContainer implements HostInterface { 561 562 @Override 563 public void setEmbeddedStage(EmbeddedStageInterface embeddedStage) { 564 stagePeer = embeddedStage; 565 if (stagePeer == null) { 566 return; 567 } 568 if (pWidth > 0 && pHeight > 0) { 569 stagePeer.setSize(pWidth, pHeight); 570 } 571 if (FXCanvas.this.isFocusControl()) { 572 stagePeer.setFocused(true, AbstractEvents.FOCUSEVENT_ACTIVATED); 573 } 574 sendMoveEventToFX(); 575 sendResizeEventToFX(); 576 } 577 578 TransferMode getTransferMode(int bits) { 579 switch (bits) { 580 case DND.DROP_COPY: 581 return TransferMode.COPY; 582 case DND.DROP_MOVE: 583 case DND.DROP_TARGET_MOVE: 584 return TransferMode.MOVE; 585 case DND.DROP_LINK: 586 return TransferMode.LINK; 587 default: 588 return null; 589 } 590 } 591 592 Set<TransferMode> getTransferModes(int bits) { 593 Set<TransferMode> set = new HashSet<TransferMode>(); 594 if ((bits & DND.DROP_COPY) != 0) set.add(TransferMode.COPY); 595 if ((bits & DND.DROP_MOVE) != 0) set.add(TransferMode.MOVE); 596 if ((bits & DND.DROP_TARGET_MOVE) != 0) set.add(TransferMode.MOVE); 597 if ((bits & DND.DROP_LINK) != 0) set.add(TransferMode.LINK); 598 return set; 599 } 600 601 // Consider using dragAction 602 private DragSource createDragSource(final EmbeddedSceneDragSourceInterface fxDragSource, TransferMode dragAction) { 603 Transfer [] transfers = getTransferTypes(fxDragSource.getMimeTypes()); 604 if (transfers.length == 0) return null; 605 int dragOperation = getDragActions(fxDragSource.getSupportedActions()); 606 final DragSource dragSource = new DragSource(FXCanvas.this, dragOperation); 607 dragSource.setTransfer(transfers); 608 dragSource.addDragListener(new DragSourceListener() { 609 public void dragFinished(org.eclipse.swt.dnd.DragSourceEvent event) { 610 dragSource.dispose(); 611 fxDragSource.dragDropEnd(getTransferMode(event.detail)); 612 } 613 public void dragSetData(org.eclipse.swt.dnd.DragSourceEvent event) { 614 Transfer [] transfers = dragSource.getTransfer(); 615 for (int i=0; i<transfers.length; i++) { 616 if (transfers[i].isSupportedType(event.dataType)) { 617 String mime = getMime(transfers[i]); 618 if (mime != null) { 619 event.doit = true; 620 event.data = fxDragSource.getData(mime); 621 return; 622 } 623 } 624 event.doit = false; 625 } 626 } 627 public void dragStart(org.eclipse.swt.dnd.DragSourceEvent event) { 628 } 629 }); 630 return dragSource; 631 } 632 633 int getDragAction(TransferMode tm) { 634 if (tm == null) return DND.DROP_NONE; 635 switch (tm) { 636 case COPY: return DND.DROP_COPY; 637 case MOVE: return DND.DROP_MOVE; 638 case LINK: return DND.DROP_LINK; 639 default: 640 throw new IllegalArgumentException("Invalid transfer mode"); 641 } 642 } 643 644 int getDragActions(Set<TransferMode> set) { 645 int result = 0; 646 for (TransferMode mode : set) { 647 result |= getDragAction(mode); 648 } 649 return result; 650 } 651 652 Transfer getTransferType(String mime) { 653 if (mime.equals("text/plain")) return TextTransfer.getInstance(); 654 if (mime.equals("text/rtf")) return RTFTransfer.getInstance(); 655 if (mime.equals("text/html")) return HTMLTransfer.getInstance(); 656 if (mime.equals("text/uri-list")) return URLTransfer.getInstance(); 657 if (mime.equals("application/x-java-rawimage")) return ImageTransfer.getInstance(); 658 if (mime.equals("application/x-java-file-list") || mime.equals("java.file-list")) { 659 return FileTransfer.getInstance(); 660 } 661 return getCustomTransfer(mime); 662 } 663 664 Transfer [] getTransferTypes(String [] mimeTypes) { 665 int count= 0; 666 Transfer [] transfers = new Transfer [mimeTypes.length]; 667 for (int i=0; i<mimeTypes.length; i++) { 668 Transfer transfer = getTransferType(mimeTypes[i]); 669 if (transfer != null) transfers [count++] = transfer; 670 } 671 if (count != mimeTypes.length) { 672 Transfer [] newTransfers = new Transfer[count]; 673 System.arraycopy(transfers, 0, newTransfers, 0, count); 674 transfers = newTransfers; 675 } 676 return transfers; 677 } 678 679 String getMime(Transfer transfer) { 680 if (transfer.equals(TextTransfer.getInstance())) return "text/plain"; 681 if (transfer.equals(RTFTransfer.getInstance())) return "text/rtf"; ; 682 if (transfer.equals( HTMLTransfer.getInstance())) return "text/html"; 683 if (transfer.equals(URLTransfer.getInstance())) return "text/uri-list"; 684 if (transfer.equals( ImageTransfer.getInstance())) return "application/x-java-rawimage"; 685 if (transfer.equals(FileTransfer.getInstance())) return "application/x-java-file-list"; 686 if (transfer instanceof CustomTransfer) return ((CustomTransfer)transfer).getMime(); 687 return null; 688 } 689 690 String [] getMimes(Transfer [] transfers, TransferData data) { 691 int count= 0; 692 String [] result = new String [transfers.length]; 693 for (int i=0; i<transfers.length; i++) { 694 if (transfers[i].isSupportedType(data)) { 695 result [count++] = getMime (transfers [i]); 696 } 697 } 698 if (count != result.length) { 699 String [] newResult = new String[count]; 700 System.arraycopy(result, 0, newResult, 0, count); 701 result = newResult; 702 } 703 return result; 704 } 705 706 DropTarget createDropTarget(EmbeddedSceneInterface embeddedScene) { 707 final DropTarget dropTarget = new DropTarget(FXCanvas.this, DND.DROP_COPY | DND.DROP_LINK | DND.DROP_MOVE); 708 final EmbeddedSceneDropTargetInterface fxDropTarget = embeddedScene.createDropTarget(); 709 dropTarget.setTransfer(getAllTransfers()); 710 dropTarget.addDropListener(new DropTargetListener() { 711 Object data; 712 TransferData [] transferData; 713 TransferData currentTransferData; 714 boolean ignoreLeave; 715 int detail = DND.DROP_NONE, operations = DND.DROP_NONE; 716 EmbeddedSceneDragSourceInterface fxDragSource = new EmbeddedSceneDragSourceInterface() { 717 public Set<TransferMode> getSupportedActions() { 718 return getTransferModes(operations); 719 } 720 public Object getData(String mimeType) { 721 // NOTE: get the data for the requested mime type, not the default data 722 return data; 723 } 724 public String[] getMimeTypes() { 725 if (currentTransferData == null) return new String [0]; 726 return getMimes(getAllTransfers(), currentTransferData); 727 } 728 public boolean isMimeTypeAvailable(String mimeType) { 729 String [] mimes = getMimeTypes(); 730 for (int i=0; i<mimes.length; i++) { 731 if (mimes[i].equals(mimeType)) return true; 732 } 733 return false; 734 } 735 public void dragDropEnd(TransferMode performedAction) { 736 data = null; 737 transferData = null; 738 currentTransferData = null; 739 } 740 }; 741 public void dragEnter(DropTargetEvent event) { 742 dropTarget.setTransfer(getAllTransfers()); 743 detail = event.detail; 744 operations = event.operations; 745 dragOver (event, true, detail); 746 } 747 public void dragLeave(DropTargetEvent event) { 748 detail = operations = DND.DROP_NONE; 749 data = null; 750 transferData = null; 751 currentTransferData = null; 752 getDisplay().asyncExec(new Runnable () { 753 public void run () { 754 if (ignoreLeave) return; 755 fxDropTarget.handleDragLeave(); 756 } 757 }); 758 } 759 public void dragOperationChanged(DropTargetEvent event) { 760 detail = event.detail; 761 operations = event.operations; 762 dragOver(event, false, detail); 763 } 764 public void dragOver(DropTargetEvent event) { 765 operations = event.operations; 766 dragOver (event, false, detail); 767 } 768 public void dragOver(DropTargetEvent event, boolean enter, int detail) { 769 transferData = event.dataTypes; 770 currentTransferData = event.currentDataType; 771 Point pt = toControl(event.x, event.y); 772 if (detail == DND.DROP_NONE) detail = DND.DROP_COPY; 773 TransferMode acceptedMode, recommendedMode = getTransferMode(detail); 774 if (enter) { 775 acceptedMode = fxDropTarget.handleDragEnter(pt.x, pt.y, event.x, event.y, recommendedMode, fxDragSource); 776 } else { 777 acceptedMode = fxDropTarget.handleDragOver(pt.x, pt.y, event.x, event.y, recommendedMode); 778 } 779 event.detail = getDragAction(acceptedMode); 780 } 781 public void drop(DropTargetEvent event) { 782 detail = event.detail; 783 operations = event.operations; 784 data = event.data; 785 transferData = event.dataTypes; 786 currentTransferData = event.currentDataType; 787 Point pt = toControl(event.x, event.y); 788 TransferMode recommendedDropAction = getTransferMode(event.detail); 789 TransferMode acceptedMode = fxDropTarget.handleDragDrop(pt.x, pt.y, event.x, event.y, recommendedDropAction); 790 event.detail = getDragAction(acceptedMode); 791 data = null; 792 transferData = null; 793 currentTransferData = null; 794 } 795 public void dropAccept(DropTargetEvent event) { 796 ignoreLeave = true; 797 } 798 }); 799 return dropTarget; 800 } 801 802 DropTarget dropTarget; 803 @Override 804 public void setEmbeddedScene(EmbeddedSceneInterface embeddedScene) { 805 scenePeer = embeddedScene; 806 if (scenePeer == null) { 807 return; 808 } 809 if (pWidth > 0 && pHeight > 0) { 810 scenePeer.setSize(pWidth, pHeight); 811 } 812 scenePeer.setDragStartListener(new EmbeddedSceneDragStartListenerInterface() { 813 @Override 814 public void dragStarted(final EmbeddedSceneDragSourceInterface fxDragSource, final TransferMode dragAction) { 815 Platform.runLater(new Runnable () { 816 public void run () { 817 DragSource dragSource = createDragSource(fxDragSource, dragAction); 818 if (dragSource == null) { 819 fxDragSource.dragDropEnd(null); 820 } else { 821 if (dropTarget != null) dropTarget.setTransfer(getAllTransfers()); 822 FXCanvas.this.notifyListeners(SWT.DragDetect, null); 823 } 824 } 825 }); 826 } 827 }); 828 if (dropTarget != null) dropTarget.dispose(); 829 dropTarget = createDropTarget(embeddedScene); 830 } 831 832 @Override 833 public boolean requestFocus() { 834 Display.getDefault().asyncExec(new Runnable() { 835 @Override 836 public void run() { 837 if (isDisposed()) return; 838 FXCanvas.this.forceFocus(); 839 } 840 }); 841 return true; 842 } 843 844 @Override 845 public boolean traverseFocusOut(boolean bln) { 846 // RT-18085: not implemented 847 return true; 848 } 849 850 Object lock = new Object(); 851 boolean queued = false; 852 public void repaint() { 853 synchronized (lock) { 854 if (queued) return; 855 queued = true; 856 Display.getDefault().asyncExec(new Runnable() { 857 @Override 858 public void run() { 859 try { 860 if (isDisposed()) return; 861 FXCanvas.this.redraw(); 862 FXCanvas.this.sendMoveEventToFX(); 863 } finally { 864 synchronized (lock) { 865 queued = false; 866 } 867 } 868 } 869 }); 870 } 871 } 872 873 @Override 874 public void setPreferredSize(int width, int height) { 875 FXCanvas.this.pPreferredWidth = width; 876 FXCanvas.this.pPreferredHeight = height; 877 //FXCanvas.this.getShell().layout(new Control []{FXCanvas.this}, SWT.DEFER); 878 } 879 880 @Override 881 public void setEnabled(boolean bln) { 882 FXCanvas.this.setEnabled(bln); 883 } 884 885 @Override 886 public void setCursor(CursorFrame cursorFrame) { 887 FXCanvas.this.setCursor(getPlatformCursor(cursorFrame)); 888 } 889 890 private org.eclipse.swt.graphics.Cursor getPlatformCursor(final CursorFrame cursorFrame) { 891 /* 892 * On the Mac, setting the cursor during drag and drop clears the move 893 * and link indicators. The fix is to set the default cursor for the 894 * control (which is null) when the FX explicitly requests the default 895 * cursor. This will preserve the drag and drop indicators. 896 */ 897 if (cursorFrame.getCursorType() == CursorType.DEFAULT) { 898 return null; 899 } 900 final org.eclipse.swt.graphics.Cursor cachedPlatformCursor = 901 cursorFrame.getPlatformCursor(org.eclipse.swt.graphics.Cursor.class); 902 if (cachedPlatformCursor != null) { 903 // platform cursor already cached 904 return cachedPlatformCursor; 905 } 906 907 // platform cursor not cached yet 908 final org.eclipse.swt.graphics.Cursor platformCursor = 909 SWTCursors.embedCursorToCursor(cursorFrame); 910 cursorFrame.setPlatforCursor(org.eclipse.swt.graphics.Cursor.class, platformCursor); 911 912 return platformCursor; 913 } 914 915 @Override 916 public boolean grabFocus() { 917 // RT-27949: not implemented 918 return true; 919 } 920 921 @Override 922 public void ungrabFocus() { 923 // RT-27949: not implemented 924 } 925 } 926}