Import "views" plugins
[deliverable/tracecompass.git] / tmf / org.lttng.scope.tmf2.views.ui / src / org / lttng / scope / tmf2 / views / ui / jfx / JfxUtils.java
CommitLineData
c879c4db
AM
1/*
2 * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 */
9
10package org.lttng.scope.tmf2.views.ui.jfx;
11
12import static java.util.Objects.requireNonNull;
13
14import java.lang.invoke.MethodHandle;
15import java.lang.invoke.MethodHandles;
16import java.lang.reflect.Method;
17import java.util.List;
18
19import javafx.application.Platform;
20import javafx.beans.property.ReadOnlyDoubleProperty;
21import javafx.beans.property.SimpleDoubleProperty;
22import javafx.geometry.Rectangle2D;
23import javafx.scene.Node;
24import javafx.scene.control.Dialog;
25import javafx.scene.control.OverrunStyle;
26import javafx.scene.text.Font;
27import javafx.stage.Screen;
28import javafx.stage.Window;
29
30/**
31 * JavaFX-related utilities
32 *
33 * @author Alexandre Montplaisir
34 */
35public final class JfxUtils {
36
37 /**
38 * Double property with a non-modifiable value of 0. For things that should
39 * remain at 0.
40 */
41 public static final ReadOnlyDoubleProperty ZERO_PROPERTY = new SimpleDoubleProperty(0);
42
43
44 private static final MethodHandles.Lookup LOOKUP = requireNonNull(MethodHandles.lookup());
45 private static final MethodHandle COMPUTE_CLIPPED_TEXT_HANDLE;
46 static {
47 MethodHandle handle = null;
48 try {
49 Class<?> c = Class.forName("com.sun.javafx.scene.control.skin.Utils"); //$NON-NLS-1$
50 Method method = c.getDeclaredMethod("computeClippedText", //$NON-NLS-1$
51 Font.class, String.class, double.class, OverrunStyle.class, String.class);
52 method.setAccessible(true);
53 handle = LOOKUP.unreflect(method);
54 } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) {
55 /* Should not fail if we did everything correctly. */
56 }
57 COMPUTE_CLIPPED_TEXT_HANDLE = requireNonNull(handle);
58 }
59
60 /**
61 * Accessor for the
62 * com.sun.javafx.scene.control.skin.Utils.computeClippedText() method.
63 *
64 * This method implements the logic to clip Label strings. It can be useful
65 * for other types, like Text. Unfortunately it is not public, but this
66 * accessor allows calling it through reflection. It makes use of
67 * {@link MethodHandle#invokeExact}, which should be close to just as fast
68 * as a standard compiled method call.
69 *
70 * @param font
71 * The font of the text that will be used
72 * @param text
73 * The string to clip
74 * @param width
75 * The maximum width we want to limit the string to
76 * @param type
77 * The {@link OverrunStyle}
78 * @param ellipsisString
79 * The string to use as ellipsis
80 * @return The clipped string, or "ERROR" if an error happened.
81 * Unfortunately we lose the exception typing due to the reflection
82 * call, so we do not want to throw "Throwable" here.
83 */
84 public static String computeClippedText(Font font, String text, double width,
85 OverrunStyle type, String ellipsisString) {
86 try {
87 String str = (String) COMPUTE_CLIPPED_TEXT_HANDLE.invokeExact(font, text, width, type, ellipsisString);
88 return requireNonNull(str);
89 } catch (Throwable e) {
90 return "ERROR"; //$NON-NLS-1$
91 }
92 }
93
94 /**
95 * Run the given {@link Runnable} on the UI/main/application thread.
96 *
97 * If you know for sure you are *not* on the main thread, you should use
98 * {@link Platform#runLater} to queue the runnable for the main thread.
99 *
100 * If you are not sure, you can use this method. The difference with
101 * {@link Platform#runLater} is that if you are actually already on the UI
102 * thread, the runnable will be run immediately. Whereas calling runLater
103 * from the UI will just queue the runnable at the end of the queue.
104 *
105 * @param r
106 * The runnable to run on the main thread
107 */
108 public static void runOnMainThread(Runnable r) {
109 if (Platform.isFxApplicationThread()) {
110 r.run();
111 } else {
112 Platform.runLater(r);
113 }
114 }
115
116 /**
117 * Utility method to center a Dialog/Alert on the middle of the current
118 * screen. Used to workaround a "bug" with the current version of JavaFX (or
119 * the SWT/JavaFX embedding?) where alerts always show on the primary
120 * screen, not necessarily the current one.
121 *
122 * @param dialog
123 * The dialog to reposition. It must be already shown, or else
124 * this will do nothing.
125 * @param referenceNode
126 * The dialog should be moved to the same screen as this node's
127 * window.
128 */
129 public static void centerDialogOnScreen(Dialog<?> dialog, Node referenceNode) {
130 Window window = referenceNode.getScene().getWindow();
131 Rectangle2D windowRectangle = new Rectangle2D(window.getX(), window.getY(), window.getWidth(), window.getHeight());
132
133 List<Screen> screens = Screen.getScreensForRectangle(windowRectangle);
134 Screen screen = screens.stream()
135 .findFirst()
136 .orElse(Screen.getPrimary());
137
138 Rectangle2D screenBounds = screen.getBounds();
139 dialog.setX((screenBounds.getWidth() - dialog.getWidth()) / 2 + screenBounds.getMinX());
140// dialog.setY((screenBounds.getHeight() - dialog.getHeight()) / 2 + screenBounds.getMinY());
141 }
142}
This page took 0.029007 seconds and 5 git commands to generate.