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 test.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.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 Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), t); 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 boolean canStartNestedEventLoop() { 726 return false; 727 } 728 729 @Override public Object enterNestedEventLoop(Object key) { 730 throw new UnsupportedOperationException("Not supported yet."); 731 } 732 733 @Override public void exitNestedEventLoop(Object key, Object rval) { 734 throw new UnsupportedOperationException("Not supported yet."); 735 } 736 737 @Override 738 public boolean isNestedLoopRunning() { 739 return false; 740 } 741 742 private KeyCode platformShortcutKey = KeyCode.SHORTCUT; 743 744 public void setPlatformShortcutKey(final KeyCode platformShortcutKey) { 745 this.platformShortcutKey = platformShortcutKey; 746 } 747 748 public KeyCode getPlatformShortcutKey() { 749 return platformShortcutKey; 750 } 751 752 private DndDelegate dndDelegate; 753 public void setDndDelegate(DndDelegate dndDelegate) { 754 this.dndDelegate = dndDelegate; 755 } 756 757 758 public interface DndDelegate { 759 void startDrag(TKScene scene, Set<TransferMode> tm, 760 TKDragSourceListener l, Dragboard dragboard); 761 762 TKClipboard createDragboard(); 763 764 DragEvent convertDragEventToFx(Object event, Dragboard dragboard); 765 766 void registerListener(TKDragGestureListener l); 767 768 void enableDrop(TKDropTargetListener l); 769 } 770 771 public interface CommonDialogsSupport { 772 FileChooserResult showFileChooser(TKStage ownerWindow, 773 String title, 774 File initialDirectory, 775 String initialFileName, 776 FileChooserType fileChooserType, 777 List<ExtensionFilter> extensionFilters, 778 ExtensionFilter selectedFilter); 779 780 File showDirectoryChooser(TKStage ownerWindow, 781 String title, 782 File initialDirectory); 783 } 784 785 private CommonDialogsSupport commonDialogsSupport; 786 public void setCommonDialogsSupport( 787 final CommonDialogsSupport commonDialogsSupport) { 788 this.commonDialogsSupport = commonDialogsSupport; 789 } 790 791 @Override 792 public FileChooserResult showFileChooser(TKStage ownerWindow, 793 String title, 794 File initialDirectory, 795 String initialFileName, 796 FileChooserType fileChooserType, 797 List<ExtensionFilter> extensionFilters, 798 ExtensionFilter selectedFilter) { 799 return commonDialogsSupport.showFileChooser( 800 ownerWindow, 801 title, 802 initialDirectory, 803 initialFileName, 804 fileChooserType, 805 extensionFilters, 806 selectedFilter); 807 } 808 809 810 @Override 811 public File showDirectoryChooser(TKStage ownerWindow, 812 String title, 813 File initialDirectory) { 814 return commonDialogsSupport.showDirectoryChooser( 815 ownerWindow, 816 title, 817 initialDirectory); 818 } 819 820 @Override 821 public long getMultiClickTime() { 822 return 500L; 823 } 824 825 @Override 826 public int getMultiClickMaxX() { 827 return 5; 828 } 829 830 @Override 831 public int getMultiClickMaxY() { 832 return 5; 833 } 834 835 public static final class ScreenConfiguration { 836 private final int minX; 837 private final int minY; 838 private final int width; 839 private final int height; 840 private final int visualMinX; 841 private final int visualMinY; 842 private final int visualWidth; 843 private final int visualHeight; 844 private final float dpi; 845 private final float scale; 846 847 public ScreenConfiguration(final int minX, final int minY, 848 final int width, final int height, 849 final int visualMinX, 850 final int visualMinY, 851 final int visualWidth, 852 final int visualHeight, 853 final float dpi) { 854 this.minX = minX; 855 this.minY = minY; 856 this.width = width; 857 this.height = height; 858 this.visualMinX = visualMinX; 859 this.visualMinY = visualMinY; 860 this.visualWidth = visualWidth; 861 this.visualHeight = visualHeight; 862 this.dpi = dpi; 863 this.scale = 1; // TODO: add a constructor that takes scale 864 } 865 866 public int getMinX() { 867 return minX; 868 } 869 870 public int getMinY() { 871 return minY; 872 } 873 874 public int getWidth() { 875 return width; 876 } 877 878 public int getHeight() { 879 return height; 880 } 881 882 public int getVisualMinX() { 883 return visualMinX; 884 } 885 886 public int getVisualMinY() { 887 return visualMinY; 888 } 889 890 public int getVisualWidth() { 891 return visualWidth; 892 } 893 894 public int getVisualHeight() { 895 return visualHeight; 896 } 897 898 public float getDPI() { 899 return dpi; 900 } 901 902 public float getScale() { 903 return scale; 904 } 905 } 906 907 public static class StubSystemMenu implements TKSystemMenu { 908 909 private List<MenuBase> menus = null; 910 911 @Override 912 public boolean isSupported() { 913 // Although not all platforms have a system menu, the only real 914 // interaction with the system menu is this TKSystemMenu instance 915 // so we'll return true on all platforms. 916 return true; 917 // final String os = System.getProperty("os.name"); 918 // return (os != null && os.startsWith("Mac")); 919 } 920 921 @Override 922 public void setMenus(List<MenuBase> menus) { 923 this.menus = menus; 924 } 925 926 // make menus accessible to unit tests 927 public List<MenuBase> getMenus() { 928 return menus; 929 } 930 931 } 932 }