1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * StubToolkit.java 28 */ 29 30 package com.sun.javafx.pgstub; 31 32 import com.sun.glass.ui.CommonDialogs.FileChooserResult; 33 import com.sun.javafx.application.PlatformImpl; 34 import com.sun.javafx.embed.HostInterface; 35 import com.sun.javafx.geom.Path2D; 36 import com.sun.javafx.geom.Shape; 37 import com.sun.javafx.geom.transform.BaseTransform; 38 import com.sun.javafx.menu.MenuBase; 39 import com.sun.javafx.perf.PerformanceTracker; 40 import com.sun.javafx.runtime.async.AsyncOperation; 41 import com.sun.javafx.runtime.async.AsyncOperationListener; 42 import com.sun.javafx.scene.text.HitInfo; 43 import com.sun.javafx.scene.text.TextLayoutFactory; 44 import com.sun.javafx.tk.*; 45 import com.sun.prism.BasicStroke; 46 import com.sun.scenario.DelayedRunnable; 47 import com.sun.scenario.animation.AbstractMasterTimer; 48 import com.sun.scenario.effect.FilterContext; 49 import com.sun.scenario.effect.Filterable; 50 import javafx.application.ConditionalFeature; 51 import javafx.geometry.Dimension2D; 52 import javafx.scene.image.Image; 53 import javafx.scene.input.*; 54 import javafx.scene.paint.Color; 55 import javafx.scene.paint.ImagePattern; 56 import javafx.scene.paint.LinearGradient; 57 import javafx.scene.paint.RadialGradient; 58 import javafx.scene.shape.*; 59 import javafx.stage.FileChooser.ExtensionFilter; 60 import javafx.stage.Modality; 61 import javafx.stage.StageStyle; 62 import javafx.stage.Window; 63 import javafx.util.Pair; 64 65 import java.io.File; 66 import java.io.InputStream; 67 import java.security.AccessControlContext; 68 import java.util.*; 69 import java.util.concurrent.Future; 70 71 /** 72 * A Toolkit implementation for use with Testing. 73 * 74 * @author Richard 75 */ 76 public class StubToolkit extends Toolkit { 77 78 private Map<Object, Object> contextMap = new HashMap<Object, Object>(); 79 80 private StubMasterTimer masterTimer = new StubMasterTimer(); 81 82 private PerformanceTracker performanceTracker = new StubPerformanceTracker(); 83 84 private final StubImageLoaderFactory imageLoaderFactory = 85 new StubImageLoaderFactory(); 86 87 private CursorSizeConverter cursorSizeConverter = 88 CursorSizeConverter.NO_CURSOR_SUPPORT; 89 90 private int maximumCursorColors = 2; 91 92 private TKScreenConfigurationListener screenConfigurationListener; 93 94 private static final ScreenConfiguration[] DEFAULT_SCREEN_CONFIG = { 95 new ScreenConfiguration(0, 0, 1920, 1200, 0, 0, 1920, 1172, 96) 96 }; 97 98 private ScreenConfiguration[] screenConfigurations = DEFAULT_SCREEN_CONFIG; 99 100 static { 101 try { 102 // ugly hack to initialize "runLater" method in Platform.java 103 PlatformImpl.startup(() -> {}); 104 } catch (Exception ex) {} 105 106 // allow tests to access PG scenegraph 107 // so that they can run with assertion enabled 108 javafx.scene.Scene.impl_setAllowPGAccess(true); 109 } 110 private boolean pulseRequested; 111 112 /* 113 * overrides of Toolkit's abstract functions 114 */ 115 116 @Override 117 public boolean init() { 118 return true; 119 } 120 121 @Override 122 public TKStage createTKStage(Window peerWindow, boolean securityDialog, StageStyle stageStyle, boolean primary, Modality modality, TKStage owner, boolean rtl, AccessControlContext acc) { 123 124 return new StubStage(); 125 } 126 127 @Override 128 public TKStage createTKPopupStage(Window peerWindow, StageStyle popupStyle, TKStage owner, AccessControlContext acc) { 129 return new StubPopupStage(); 130 } 131 132 @Override 133 public TKStage createTKEmbeddedStage(HostInterface host, AccessControlContext acc) { 134 return new StubStage(); 135 } 136 137 @Override 138 public AppletWindow createAppletWindow(long parent, String serverName) { 139 // unsupported 140 return null; 141 } 142 143 @Override 144 public void closeAppletWindow() { 145 // unsupported 146 } 147 148 private final TKSystemMenu systemMenu = new StubSystemMenu(); 149 @Override 150 public TKSystemMenu getSystemMenu() { 151 return systemMenu; 152 } 153 154 @Override 155 public void startup(Runnable runnable) { 156 runnable.run(); 157 } 158 159 @Override 160 public void checkFxUserThread() { 161 // Do nothing 162 } 163 164 @Override 165 public boolean isFxUserThread() { 166 // Always on the FX app thread 167 return true; 168 } 169 170 @Override 171 public void defer(Runnable runnable) { 172 runnable.run(); 173 } 174 175 @Override 176 public void exit() { 177 System.exit(0); 178 } 179 180 @Override 181 public Future addRenderJob(RenderJob rj) { 182 return rj; 183 } 184 185 @Override 186 public Map<Object, Object> getContextMap() { 187 return contextMap; 188 } 189 190 @Override public int getRefreshRate() { 191 return -1; 192 } 193 194 private DelayedRunnable animationRunnable; 195 196 @Override 197 public void setAnimationRunnable(DelayedRunnable animationRunnable) { 198 this.animationRunnable = animationRunnable; 199 } 200 201 @Override 202 public PerformanceTracker getPerformanceTracker() { 203 return performanceTracker; 204 } 205 206 @Override public PerformanceTracker createPerformanceTracker() { 207 return new StubPerformanceTracker(); 208 } 209 210 @Override 211 protected Object createColorPaint(Color paint) { 212 return new com.sun.prism.paint.Color((float) paint.getRed(), 213 (float) paint.getGreen(), 214 (float) paint.getBlue(), 215 (float) paint.getOpacity()); 216 } 217 218 @Override 219 protected Object createLinearGradientPaint(LinearGradient paint) { 220 // Non functioning but compiles 221 return new com.sun.prism.paint.Color(1, 1, 1, 1); 222 } 223 224 @Override 225 protected Object createRadialGradientPaint(RadialGradient paint) { 226 // Non functioning but compiles 227 return new com.sun.prism.paint.Color(1, 1, 1, 1); 228 } 229 230 @Override 231 protected Object createImagePatternPaint(ImagePattern paint) { 232 // Non functioning but compiles 233 return new com.sun.prism.paint.Color(1, 1, 1, 1); 234 } 235 236 static BasicStroke tmpStroke = new BasicStroke(); 237 void initStroke(StrokeType pgtype, double strokewidth, 238 StrokeLineCap pgcap, 239 StrokeLineJoin pgjoin, float miterLimit) 240 { 241 int type; 242 if (pgtype == StrokeType.CENTERED) { 243 type = BasicStroke.TYPE_CENTERED; 244 } else if (pgtype == StrokeType.INSIDE) { 245 type = BasicStroke.TYPE_INNER; 246 } else { 247 type = BasicStroke.TYPE_OUTER; 248 } 249 250 int cap; 251 if (pgcap == StrokeLineCap.BUTT) { 252 cap = BasicStroke.CAP_BUTT; 253 } else if (pgcap == StrokeLineCap.SQUARE) { 254 cap = BasicStroke.CAP_SQUARE; 255 } else { 256 cap = BasicStroke.CAP_ROUND; 257 } 258 259 int join; 260 if (pgjoin == StrokeLineJoin.BEVEL) { 261 join = BasicStroke.JOIN_BEVEL; 262 } else if (pgjoin == StrokeLineJoin.MITER) { 263 join = BasicStroke.JOIN_MITER; 264 } else { 265 join = BasicStroke.JOIN_ROUND; 266 } 267 268 tmpStroke.set(type, (float) strokewidth, cap, join, miterLimit); 269 } 270 271 @Override 272 public void accumulateStrokeBounds(Shape shape, float bbox[], 273 StrokeType pgtype, 274 double strokewidth, 275 StrokeLineCap pgcap, 276 StrokeLineJoin pgjoin, 277 float miterLimit, 278 BaseTransform tx) 279 { 280 281 initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit); 282 // TODO: The accumulation could be done directly without creating a Shape 283 Shape.accumulate(bbox, tmpStroke.createStrokedShape(shape), tx); 284 } 285 286 @Override 287 public boolean strokeContains(Shape shape, double x, double y, 288 StrokeType pgtype, 289 double strokewidth, 290 StrokeLineCap pgcap, 291 StrokeLineJoin pgjoin, 292 float miterLimit) 293 { 294 initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit); 295 // TODO: The contains testing could be done directly without creating a Shape 296 return tmpStroke.createStrokedShape(shape).contains((float) x, (float) y); 297 } 298 299 @Override 300 public Shape createStrokedShape(Shape shape, 301 StrokeType pgtype, 302 double strokewidth, 303 StrokeLineCap pgcap, 304 StrokeLineJoin pgjoin, 305 float miterLimit, 306 float[] dashArray, 307 float dashOffset) { 308 initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit); 309 return tmpStroke.createStrokedShape(shape); 310 } 311 312 public CursorSizeConverter getCursorSizeConverter() { 313 return cursorSizeConverter; 314 } 315 316 public void setCursorSizeConverter( 317 CursorSizeConverter cursorSizeConverter) { 318 this.cursorSizeConverter = cursorSizeConverter; 319 } 320 321 @Override 322 public Dimension2D getBestCursorSize(int preferredWidth, int preferredHeight) { 323 return cursorSizeConverter.getBestCursorSize(preferredWidth, 324 preferredHeight); 325 } 326 327 @Override 328 public int getMaximumCursorColors() { 329 return maximumCursorColors; 330 } 331 332 public void setMaximumCursorColors(int maximumCursorColors) { 333 this.maximumCursorColors = maximumCursorColors; 334 } 335 336 @Override 337 public AbstractMasterTimer getMasterTimer() { 338 return masterTimer; 339 } 340 341 @Override 342 public FontLoader getFontLoader() { 343 return new StubFontLoader(); 344 } 345 346 @Override 347 public TextLayoutFactory getTextLayoutFactory() { 348 return new StubTextLayoutFactory(); 349 } 350 351 @Override public boolean isSupported(ConditionalFeature feature) { 352 if (feature == ConditionalFeature.SCENE3D) { 353 return true; 354 } else if (feature == ConditionalFeature.TRANSPARENT_WINDOW) { 355 return true; 356 } 357 return false; 358 } 359 360 /* 361 * additional testing functions 362 */ 363 public void fireTestPulse() { 364 firePulse(); 365 } 366 367 public boolean isPulseRequested() { 368 return pulseRequested; 369 } 370 371 public void clearPulseRequested() { 372 pulseRequested = false; 373 } 374 375 // do nothing -- bringing in FrameJob and MasterTimer also bring in 376 // Settings and crap which isn't setup for the testing stuff because 377 // we don't run through a RuntimeProvider or do normal startup 378 // public @Override public void triggerNextPulse():Void { } 379 @Override public void requestNextPulse() { 380 pulseRequested = true; 381 } 382 383 private TKClipboard clipboard = new TKClipboard() { 384 private Map<DataFormat, Object> map = new HashMap<DataFormat, Object>(); 385 private Image image; 386 private double offsetX; 387 private double offsetY; 388 389 @Override 390 public void setSecurityContext(AccessControlContext ctx) { 391 } 392 393 @Override public Set<DataFormat> getContentTypes() { 394 return map.keySet(); 395 } 396 397 @Override public boolean putContent(Pair<DataFormat, Object>... content) { 398 boolean good; 399 for (Pair<DataFormat,Object> pair : content) { 400 good = map.put(pair.getKey(), pair.getValue()) == pair.getValue(); 401 if (!good) return false; 402 } 403 return true; 404 } 405 406 @Override public Object getContent(DataFormat dataFormat) { 407 return map.get(dataFormat); 408 } 409 410 @Override public boolean hasContent(DataFormat dataFormat) { 411 return map.containsKey(dataFormat); 412 } 413 414 @Override public Set<TransferMode> getTransferModes() { 415 Set<TransferMode> modes = new HashSet<TransferMode>(); 416 modes.add(TransferMode.COPY); 417 return modes; 418 } 419 420 @Override 421 public void setDragView(Image image) { 422 this.image = image; 423 } 424 425 @Override 426 public void setDragViewOffsetX(double offsetX) { 427 this.offsetX = offsetX; 428 } 429 430 @Override 431 public void setDragViewOffsetY(double offsetY) { 432 this.offsetY = offsetY; 433 } 434 435 @Override 436 public Image getDragView() { 437 return image; 438 } 439 440 @Override 441 public double getDragViewOffsetX() { 442 return offsetX; 443 } 444 445 @Override 446 public double getDragViewOffsetY() { 447 return offsetY; 448 } 449 }; 450 451 452 @Override 453 public TKClipboard getSystemClipboard() { 454 return clipboard; 455 } 456 457 @Override public TKClipboard getNamedClipboard(String name) { 458 return null; 459 } 460 461 public static TKClipboard createDragboard() { 462 StubToolkit tk = (StubToolkit)Toolkit.getToolkit(); 463 if (tk.dndDelegate != null) { 464 return tk.dndDelegate.createDragboard(); 465 } 466 return null; 467 } 468 469 @Override 470 public void enableDrop(TKScene s, TKDropTargetListener l) { 471 if (dndDelegate != null) { 472 dndDelegate.enableDrop(l); 473 } 474 } 475 476 private ScreenConfigurationAccessor accessor = new ScreenConfigurationAccessor() { 477 @Override 478 public int getMinX(Object obj) { 479 return ((ScreenConfiguration) obj).getMinX(); 480 } 481 482 @Override 483 public int getMinY(Object obj) { 484 return ((ScreenConfiguration) obj).getMinY(); 485 } 486 487 @Override 488 public int getWidth(Object obj) { 489 return ((ScreenConfiguration) obj).getWidth(); 490 } 491 492 @Override 493 public int getHeight(Object obj) { 494 return ((ScreenConfiguration) obj).getHeight(); 495 } 496 497 @Override 498 public int getVisualMinX(Object obj) { 499 return ((ScreenConfiguration) obj).getVisualMinX(); 500 } 501 502 @Override 503 public int getVisualMinY(Object obj) { 504 return ((ScreenConfiguration) obj).getVisualMinY(); 505 } 506 507 @Override 508 public int getVisualWidth(Object obj) { 509 return ((ScreenConfiguration) obj).getVisualWidth(); 510 } 511 512 @Override 513 public int getVisualHeight(Object obj) { 514 return ((ScreenConfiguration) obj).getVisualHeight(); 515 } 516 517 @Override 518 public float getDPI(Object obj) { 519 return ((ScreenConfiguration) obj).getDPI(); 520 } 521 522 @Override 523 public float getUIScale(Object obj) { 524 return ((ScreenConfiguration) obj).getScale(); 525 } 526 527 @Override 528 public float getRenderScale(Object obj) { 529 return ((ScreenConfiguration) obj).getScale(); 530 } 531 }; 532 533 @Override 534 public ScreenConfigurationAccessor setScreenConfigurationListener( 535 TKScreenConfigurationListener listener) { 536 screenConfigurationListener = listener; 537 return accessor; 538 } 539 540 @Override 541 public ScreenConfiguration getPrimaryScreen() { 542 return screenConfigurations[0]; 543 } 544 545 public void setScreens(ScreenConfiguration... screenConfigurations) { 546 this.screenConfigurations = screenConfigurations.clone(); 547 if (screenConfigurationListener != null) { 548 screenConfigurationListener.screenConfigurationChanged(); 549 } 550 } 551 552 public void resetScreens() { 553 setScreens(DEFAULT_SCREEN_CONFIG); 554 } 555 556 @Override 557 public List<ScreenConfiguration> getScreens() { 558 return Arrays.asList(screenConfigurations); 559 } 560 561 @Override 562 public ScreenConfigurationAccessor getScreenConfigurationAccessor() { 563 return accessor; 564 } 565 566 @Override public void registerDragGestureListener(TKScene s, Set<TransferMode> tm, TKDragGestureListener l) { 567 if (dndDelegate != null) { 568 dndDelegate.registerListener(l); 569 } 570 } 571 572 @Override public void startDrag(TKScene scene, Set<TransferMode> tm, TKDragSourceListener l, Dragboard dragboard) { 573 if (dndDelegate != null) { 574 dndDelegate.startDrag(scene, tm, l, dragboard); 575 } 576 } 577 578 @Override 579 public ImageLoader loadImage(String url, int width, int height, 580 boolean preserveRatio, boolean smooth) { 581 return imageLoaderFactory.createImageLoader(url, width, height, 582 preserveRatio, smooth); 583 } 584 585 @Override 586 public ImageLoader loadImage(InputStream stream, int width, int height, 587 boolean preserveRatio, boolean smooth) { 588 return imageLoaderFactory.createImageLoader(stream, width, height, 589 preserveRatio, smooth); 590 } 591 592 @Override 593 public AsyncOperation loadImageAsync( 594 AsyncOperationListener listener, String url, int width, int height, 595 boolean preserveRatio, boolean smooth) { 596 return imageLoaderFactory.createAsyncImageLoader( 597 listener, url, width, height, preserveRatio, smooth); 598 } 599 600 @Override 601 public ImageLoader loadPlatformImage(Object platformImage) { 602 return imageLoaderFactory.createImageLoader(platformImage, 603 0, 0, false, false); 604 } 605 606 @Override 607 public PlatformImage createPlatformImage(int w, int h) { 608 PlatformImage image = new StubWritablePlatformImage(w, h); 609 imageLoaderFactory.registerImage(image, new StubPlatformImageInfo(w, h)); 610 return image; 611 } 612 613 @Override 614 public void waitFor(Task t) { 615 throw new UnsupportedOperationException(); 616 } 617 618 @Override 619 public int getKeyCodeForChar(String character) { 620 if (charToKeyCodeMap != null) { 621 final KeyCode keyCode = charToKeyCodeMap.get(character); 622 if (keyCode != null) { 623 return keyCode.impl_getCode(); 624 } 625 } 626 627 return 0; 628 } 629 630 @Override 631 public PathElement[] convertShapeToFXPath(Object shape) { 632 // Had to be mocked up for TextField tests (for the caret!) 633 // Since the "shape" could be anything, I'm just returning 634 // something here, doesn't matter what. 635 return new PathElement[0]; 636 } 637 638 @Override 639 public HitInfo convertHitInfoToFX(Object hit) { 640 return (HitInfo) hit; 641 } 642 643 @Override 644 public Filterable toFilterable(Image img) { 645 return StubFilterable.create((StubPlatformImage)img.impl_getPlatformImage()); 646 } 647 648 @Override 649 public FilterContext getFilterContext(Object config) { 650 throw new UnsupportedOperationException(); 651 } 652 653 @Override 654 public boolean isForwardTraversalKey(KeyEvent e) { 655 throw new UnsupportedOperationException(); 656 } 657 658 @Override 659 public boolean isBackwardTraversalKey(KeyEvent e) { 660 throw new UnsupportedOperationException(); 661 } 662 663 @Override 664 public Object createSVGPathObject(SVGPath svgpath) { 665 int windingRule = (svgpath.getFillRule() == FillRule.NON_ZERO) ? 666 Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD; 667 668 return new SVGPathImpl(svgpath.getContent(), windingRule); 669 } 670 671 @Override 672 public Path2D createSVGPath2D(SVGPath svgpath) { 673 int windingRule = (svgpath.getFillRule() == FillRule.NON_ZERO) ? 674 Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD; 675 676 return new SVGPathImpl(svgpath.getContent(), windingRule); 677 } 678 679 @Override 680 public boolean imageContains(Object image, float x, float y) { 681 return ((StubPlatformImage) image).getImageInfo() 682 .contains((int) x, (int) y); 683 } 684 685 public void setCurrentTime(long millis) { 686 masterTimer.setCurrentTime(millis); 687 } 688 689 public void handleAnimation() { 690 if (animationRunnable != null) { 691 try { 692 animationRunnable.run(); 693 } catch (Throwable t) { 694 t.printStackTrace(); 695 } 696 } 697 } 698 699 public StubImageLoaderFactory getImageLoaderFactory() { 700 return imageLoaderFactory; 701 } 702 703 public void setAnimationTime(final long millis) { 704 setCurrentTime(millis); 705 handleAnimation(); 706 fireTestPulse(); 707 } 708 709 @Override 710 public void installInputMethodRequests(TKScene scene, InputMethodRequests requests) { 711 // just do nothing here. 712 } 713 714 private Map<String, KeyCode> charToKeyCodeMap; 715 716 public void setCharToKeyCodeMap(Map<String, KeyCode> charToKeyCodeMap) { 717 this.charToKeyCodeMap = charToKeyCodeMap; 718 } 719 720 @Override 721 public Object renderToImage(ImageRenderingContext context) { 722 throw new UnsupportedOperationException(); 723 } 724 725 @Override public Object enterNestedEventLoop(Object key) { 726 throw new UnsupportedOperationException("Not supported yet."); 727 } 728 729 @Override public void exitNestedEventLoop(Object key, Object rval) { 730 throw new UnsupportedOperationException("Not supported yet."); 731 } 732 733 @Override 734 public boolean isNestedLoopRunning() { 735 return false; 736 } 737 738 private KeyCode platformShortcutKey = KeyCode.SHORTCUT; 739 740 public void setPlatformShortcutKey(final KeyCode platformShortcutKey) { 741 this.platformShortcutKey = platformShortcutKey; 742 } 743 744 public KeyCode getPlatformShortcutKey() { 745 return platformShortcutKey; 746 } 747 748 private DndDelegate dndDelegate; 749 public void setDndDelegate(DndDelegate dndDelegate) { 750 this.dndDelegate = dndDelegate; 751 } 752 753 754 public interface DndDelegate { 755 void startDrag(TKScene scene, Set<TransferMode> tm, 756 TKDragSourceListener l, Dragboard dragboard); 757 758 TKClipboard createDragboard(); 759 760 DragEvent convertDragEventToFx(Object event, Dragboard dragboard); 761 762 void registerListener(TKDragGestureListener l); 763 764 void enableDrop(TKDropTargetListener l); 765 } 766 767 public interface CommonDialogsSupport { 768 FileChooserResult showFileChooser(TKStage ownerWindow, 769 String title, 770 File initialDirectory, 771 String initialFileName, 772 FileChooserType fileChooserType, 773 List<ExtensionFilter> extensionFilters, 774 ExtensionFilter selectedFilter); 775 776 File showDirectoryChooser(TKStage ownerWindow, 777 String title, 778 File initialDirectory); 779 } 780 781 private CommonDialogsSupport commonDialogsSupport; 782 public void setCommonDialogsSupport( 783 final CommonDialogsSupport commonDialogsSupport) { 784 this.commonDialogsSupport = commonDialogsSupport; 785 } 786 787 @Override 788 public FileChooserResult showFileChooser(TKStage ownerWindow, 789 String title, 790 File initialDirectory, 791 String initialFileName, 792 FileChooserType fileChooserType, 793 List<ExtensionFilter> extensionFilters, 794 ExtensionFilter selectedFilter) { 795 return commonDialogsSupport.showFileChooser( 796 ownerWindow, 797 title, 798 initialDirectory, 799 initialFileName, 800 fileChooserType, 801 extensionFilters, 802 selectedFilter); 803 } 804 805 806 @Override 807 public File showDirectoryChooser(TKStage ownerWindow, 808 String title, 809 File initialDirectory) { 810 return commonDialogsSupport.showDirectoryChooser( 811 ownerWindow, 812 title, 813 initialDirectory); 814 } 815 816 @Override 817 public long getMultiClickTime() { 818 return 500L; 819 } 820 821 @Override 822 public int getMultiClickMaxX() { 823 return 5; 824 } 825 826 @Override 827 public int getMultiClickMaxY() { 828 return 5; 829 } 830 831 public static final class ScreenConfiguration { 832 private final int minX; 833 private final int minY; 834 private final int width; 835 private final int height; 836 private final int visualMinX; 837 private final int visualMinY; 838 private final int visualWidth; 839 private final int visualHeight; 840 private final float dpi; 841 private final float scale; 842 843 public ScreenConfiguration(final int minX, final int minY, 844 final int width, final int height, 845 final int visualMinX, 846 final int visualMinY, 847 final int visualWidth, 848 final int visualHeight, 849 final float dpi) { 850 this.minX = minX; 851 this.minY = minY; 852 this.width = width; 853 this.height = height; 854 this.visualMinX = visualMinX; 855 this.visualMinY = visualMinY; 856 this.visualWidth = visualWidth; 857 this.visualHeight = visualHeight; 858 this.dpi = dpi; 859 this.scale = 1; // TODO: add a constructor that takes scale 860 } 861 862 public int getMinX() { 863 return minX; 864 } 865 866 public int getMinY() { 867 return minY; 868 } 869 870 public int getWidth() { 871 return width; 872 } 873 874 public int getHeight() { 875 return height; 876 } 877 878 public int getVisualMinX() { 879 return visualMinX; 880 } 881 882 public int getVisualMinY() { 883 return visualMinY; 884 } 885 886 public int getVisualWidth() { 887 return visualWidth; 888 } 889 890 public int getVisualHeight() { 891 return visualHeight; 892 } 893 894 public float getDPI() { 895 return dpi; 896 } 897 898 public float getScale() { 899 return scale; 900 } 901 } 902 903 public static class StubSystemMenu implements TKSystemMenu { 904 905 private List<MenuBase> menus = null; 906 907 @Override 908 public boolean isSupported() { 909 // Although not all platforms have a system menu, the only real 910 // interaction with the system menu is this TKSystemMenu instance 911 // so we'll return true on all platforms. 912 return true; 913 // final String os = System.getProperty("os.name"); 914 // return (os != null && os.startsWith("Mac")); 915 } 916 917 @Override 918 public void setMenus(List<MenuBase> menus) { 919 this.menus = menus; 920 } 921 922 // make menus accessible to unit tests 923 public List<MenuBase> getMenus() { 924 return menus; 925 } 926 927 } 928 }