X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=inline;f=bundles%2Forg.simantics.utils.ui%2Fsrc%2Forg%2Fsimantics%2Futils%2Fui%2FSWTAWTComponent.java;h=9a7b7aee736721cd12b23b7fa9a1f3ffb395a82c;hb=fad226f0141b3739cc7c68e47e0b0c4a4c545e8c;hp=a57067565a25e184a07bf8356b05c85608afc630;hpb=75785e1454fbc60973848c72e2ed698d2cda5ce7;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTAWTComponent.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTAWTComponent.java index a57067565..9a7b7aee7 100644 --- a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTAWTComponent.java +++ b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTAWTComponent.java @@ -1,597 +1,614 @@ -/******************************************************************************* - * Copyright (c) 2007, 2013 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - * Semantum Oy - workaround for Simantics issue #3518 - *******************************************************************************/ -package org.simantics.utils.ui; - -import java.awt.AWTEvent; -import java.awt.Component; -import java.awt.Container; -import java.awt.EventQueue; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.Toolkit; -import java.awt.event.AWTEventListener; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -import javax.swing.JApplet; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.plaf.FontUIResource; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.swt.SWT; -import org.eclipse.swt.awt.SWT_AWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.simantics.utils.threads.AWTThread; -import org.simantics.utils.threads.ThreadUtils; -import org.simantics.utils.threads.logger.ITask; -import org.simantics.utils.threads.logger.ThreadLogger; -import org.simantics.utils.ui.awt.AwtEnvironment; -import org.simantics.utils.ui.awt.AwtFocusHandler; -import org.simantics.utils.ui.awt.CleanResizeListener; -import org.simantics.utils.ui.awt.EmbeddedChildFocusTraversalPolicy; -import org.simantics.utils.ui.awt.SwtFocusHandler; -import org.simantics.utils.ui.internal.Activator; - - -/** - *
- * embeddedComposite = new SWTAWTComposite(parent, SWT.NONE) { - * protected JComponent createSwingComponent() { - * scrollPane = new JScrollPane(); - * table = new JTable(); - * scrollPane.setViewportView(table); - * return scrollPane; - * } - * }; - * // For asynchronous AWT UI population of the swing components: - * embeddedComposite.populate(); - * // and optionally you can wait until the AWT UI population - * // has finished: - * embeddedComposite.waitUntilPopulated(); - * - * // OR: - * - * // Do both things above in one call to block until the - * // AWT UI population is complete: - * embeddedComposite.syncPopulate(); - * - * // OR: - * - * // Set a callback for asynchronous completion in the AWT thread: - * embeddedComposite.populate(component -> { - // AWT components have been created for component - * }); - * - * // All methods assume all invocations are made from the SWT display thread. - *- *
- *
- * @author Tuukka Lehtonen
- */
-public abstract class SWTAWTComponent extends Composite {
-
- private static class AwtContext {
- private Frame frame;
- private Component swingComponent;
-
- AwtContext(Frame frame) {
- assert frame != null;
- this.frame = frame;
- }
-
- Frame getFrame() {
- return frame;
- }
-
- void setSwingComponent(Component swingComponent) {
- this.swingComponent = swingComponent;
- }
-
- Component getSwingComponent() {
- return swingComponent;
- }
-
- }
-
- private Font currentSystemFont;
- private AwtContext awtContext;
- private AwtFocusHandler awtHandler;
-
- private JApplet panel;
-
- private final AtomicBoolean populationStarted = new AtomicBoolean(false);
-
- private final AtomicBoolean populated = new AtomicBoolean(false);
-
- private final Semaphore populationSemaphore = new Semaphore(0);
-
- private Consumer
- * This method is called from the AWT event thread.
- *
- * If you are defining your own root pane container, make sure that there is at least one
- * heavyweight (AWT) component in the frame's containment hierarchy; otherwise, event
- * processing will not work correctly. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4982522
- * for more information.
- *
- * @param frame the frame to which the root pane container is added
- * @return a non-null Swing component
- */
- protected JApplet addRootPaneContainer(Frame frame) {
- assert EventQueue.isDispatchThread(); // On AWT event thread
- assert frame != null;
-
- // It is important to set up the proper top level components in the frame:
- // 1) For Swing to work properly, Sun documents that there must be an implementor of
- // javax.swing.RootPaneContainer at the top of the component hierarchy.
- // 2) For proper event handling there must be a heavyweight
- // an AWT frame must contain a heavyweight component (see
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4982522)
- // 3) The Swing implementation further narrows the options by expecting that the
- // top of the hierarchy be a JFrame, JDialog, JWindow, or JApplet. See javax.swing.PopupFactory.
- // All this drives the choice of JApplet for the top level Swing component. It is the
- // only single component that satisfies all the above. This does not imply that
- // we have a true applet; in particular, there is no notion of an applet lifecycle in this
- // context.
- JApplet applet = new JApplet();
-
- // In JRE 1.4, the JApplet makes itself a focus cycle root. This
- // interferes with the focus handling installed on the parent frame, so
- // change it back to a non-root here.
- // TODO: consider moving the focus policy from the Frame down to the JApplet
- applet.setFocusCycleRoot(false);
-
- frame.add(applet);
-
- return applet;
- }
-
- /**
- * Override this to customize what kind of AWT/Swing UI is created by this
- * {@link SWTAWTComponent}.
- *
- * @return the AWT/Swing component created by this SWTAWT bridging control
- * @thread AWT
- */
- protected abstract Component createSwingComponent();
-
- private void setComponentFont() {
- assert currentSystemFont != null;
- assert EventQueue.isDispatchThread(); // On AWT event thread
-
- Component swingComponent = (awtContext != null) ? awtContext.getSwingComponent() : null;
- if ((swingComponent != null) && !currentSystemFont.getDevice().isDisposed()) {
- FontData fontData = currentSystemFont.getFontData()[0];
-
- // AWT font sizes assume a 72 dpi resolution, always. The true screen resolution must be
- // used to convert the platform font size into an AWT point size that matches when displayed.
- int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
- int awtFontSize = (int)Math.round((double)fontData.getHeight() * resolution / 72.0);
-
- // The style constants for SWT and AWT map exactly, and since they are int constants, they should
- // never change. So, the SWT style is passed through as the AWT style.
- java.awt.Font awtFont = new java.awt.Font(fontData.getName(), fontData.getStyle(), awtFontSize);
-
- // Update the look and feel defaults to use new font.
- updateLookAndFeel(awtFont);
-
- // Allow subclasses to react to font change if necessary.
- updateAwtFont(awtFont);
-
- // Allow components to update their UI based on new font
- // TODO: should the update method be called on the root pane instead?
- Container contentPane = SwingUtilities.getRootPane(swingComponent).getContentPane();
- SwingUtilities.updateComponentTreeUI(contentPane);
- }
- }
-
- private void updateLookAndFeel(java.awt.Font awtFont) {
- assert awtFont != null;
- assert EventQueue.isDispatchThread(); // On AWT event thread
-
- // The FontUIResource class marks the font as replaceable by the look and feel
- // implementation if font settings are later changed.
- FontUIResource fontResource = new FontUIResource(awtFont);
-
- // Assign the new font to the relevant L&F font properties. These are
- // the properties that are initially assigned to the system font
- // under the Windows look and feel.
- // TODO: It's possible that other platforms will need other assignments.
- // TODO: This does not handle fonts other than the "system" font.
- // Other fonts may change, and the Swing L&F may not be adjusting.
-
- UIManager.put("Button.font", fontResource); //$NON-NLS-1$
- UIManager.put("CheckBox.font", fontResource); //$NON-NLS-1$
- UIManager.put("ComboBox.font", fontResource); //$NON-NLS-1$
- UIManager.put("EditorPane.font", fontResource); //$NON-NLS-1$
- UIManager.put("Label.font", fontResource); //$NON-NLS-1$
- UIManager.put("List.font", fontResource); //$NON-NLS-1$
- UIManager.put("Panel.font", fontResource); //$NON-NLS-1$
- UIManager.put("ProgressBar.font", fontResource); //$NON-NLS-1$
- UIManager.put("RadioButton.font", fontResource); //$NON-NLS-1$
- UIManager.put("ScrollPane.font", fontResource); //$NON-NLS-1$
- UIManager.put("TabbedPane.font", fontResource); //$NON-NLS-1$
- UIManager.put("Table.font", fontResource); //$NON-NLS-1$
- UIManager.put("TableHeader.font", fontResource); //$NON-NLS-1$
- UIManager.put("TextField.font", fontResource); //$NON-NLS-1$
- UIManager.put("TextPane.font", fontResource); //$NON-NLS-1$
- UIManager.put("TitledBorder.font", fontResource); //$NON-NLS-1$
- UIManager.put("ToggleButton.font", fontResource); //$NON-NLS-1$
- UIManager.put("TreeFont.font", fontResource); //$NON-NLS-1$
- UIManager.put("ViewportFont.font", fontResource); //$NON-NLS-1$
- }
-
- /**
- * Performs custom updates to newly set fonts. This method is called whenever a change
- * to the system font through the system settings (i.e. control panel) is detected.
- *
- * This method is called from the AWT event thread.
- *
- * In most cases it is not necessary to override this method. Normally, the implementation
- * of this class will automatically propogate font changes to the embedded Swing components
- * through Swing's Look and Feel support. However, if additional
- * special processing is necessary, it can be done inside this method.
- *
- * @param newFont New AWT font
- */
- protected void updateAwtFont(java.awt.Font newFont) {
- }
-
- private void handleSettingsChange() {
- Font newFont = getDisplay().getSystemFont();
- if (!newFont.equals(currentSystemFont)) {
- currentSystemFont = newFont;
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- setComponentFont();
- }
- });
- }
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - workaround for Simantics issue #3518
+ *******************************************************************************/
+package org.simantics.utils.ui;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+import javax.swing.JApplet;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.FontUIResource;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
+import org.simantics.utils.ui.internal.Activator;
+import org.simantics.utils.ui.internal.awt.AwtEnvironment;
+import org.simantics.utils.ui.internal.awt.AwtFocusHandler;
+import org.simantics.utils.ui.internal.awt.CleanResizeListener;
+import org.simantics.utils.ui.internal.awt.EmbeddedChildFocusTraversalPolicy;
+import org.simantics.utils.ui.internal.awt.SwtFocusHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ *
+ *
+ * @author Tuukka Lehtonen
+ */
+public abstract class SWTAWTComponent extends Composite {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SWTAWTComponent.class);
+
+ private static class AwtContext {
+ private Frame frame;
+ private Component swingComponent;
+
+ AwtContext(Frame frame) {
+ assert frame != null;
+ this.frame = frame;
+ }
+
+ Frame getFrame() {
+ return frame;
+ }
+
+ void setSwingComponent(Component swingComponent) {
+ this.swingComponent = swingComponent;
+ }
+
+ Component getSwingComponent() {
+ return swingComponent;
+ }
+
+ }
+
+ private Font currentSystemFont;
+ private AwtContext awtContext;
+ private AwtFocusHandler awtHandler;
+
+ private JApplet panel;
+
+ private final AtomicBoolean populationStarted = new AtomicBoolean(false);
+
+ private final AtomicBoolean populated = new AtomicBoolean(false);
+
+ private final Semaphore populationSemaphore = new Semaphore(0);
+
+ private Consumer
+ * This method is called from the AWT event thread.
+ *
+ * If you are defining your own root pane container, make sure that there is at least one
+ * heavyweight (AWT) component in the frame's containment hierarchy; otherwise, event
+ * processing will not work correctly. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4982522
+ * for more information.
+ *
+ * @param frame the frame to which the root pane container is added
+ * @return a non-null Swing component
+ */
+ protected JApplet addRootPaneContainer(Frame frame) {
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+ assert frame != null;
+
+ // It is important to set up the proper top level components in the frame:
+ // 1) For Swing to work properly, Sun documents that there must be an implementor of
+ // javax.swing.RootPaneContainer at the top of the component hierarchy.
+ // 2) For proper event handling there must be a heavyweight
+ // an AWT frame must contain a heavyweight component (see
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4982522)
+ // 3) The Swing implementation further narrows the options by expecting that the
+ // top of the hierarchy be a JFrame, JDialog, JWindow, or JApplet. See javax.swing.PopupFactory.
+ // All this drives the choice of JApplet for the top level Swing component. It is the
+ // only single component that satisfies all the above. This does not imply that
+ // we have a true applet; in particular, there is no notion of an applet lifecycle in this
+ // context.
+ JApplet applet = new JApplet();
+
+ // In JRE 1.4, the JApplet makes itself a focus cycle root. This
+ // interferes with the focus handling installed on the parent frame, so
+ // change it back to a non-root here.
+ // TODO: consider moving the focus policy from the Frame down to the JApplet
+ applet.setFocusCycleRoot(false);
+
+ frame.add(applet);
+
+ return applet;
+ }
+
+ /**
+ * Override this to customize what kind of AWT/Swing UI is created by this
+ * {@link SWTAWTComponent}.
+ *
+ * @return the AWT/Swing component created by this SWTAWT bridging control
+ * @thread AWT
+ */
+ protected abstract Component createSwingComponent();
+
+ private void setComponentFont() {
+ assert currentSystemFont != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ Component swingComponent = (awtContext != null) ? awtContext.getSwingComponent() : null;
+ if ((swingComponent != null) && !currentSystemFont.getDevice().isDisposed()) {
+ FontData fontData = currentSystemFont.getFontData()[0];
+
+ // AWT font sizes assume a 72 dpi resolution, always. The true screen resolution must be
+ // used to convert the platform font size into an AWT point size that matches when displayed.
+ int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
+ int awtFontSize = (int)Math.round((double)fontData.getHeight() * resolution / 72.0);
+
+ // The style constants for SWT and AWT map exactly, and since they are int constants, they should
+ // never change. So, the SWT style is passed through as the AWT style.
+ java.awt.Font awtFont = new java.awt.Font(fontData.getName(), fontData.getStyle(), awtFontSize);
+
+ // Update the look and feel defaults to use new font.
+ updateLookAndFeel(awtFont);
+
+ // Allow subclasses to react to font change if necessary.
+ updateAwtFont(awtFont);
+
+ // Allow components to update their UI based on new font
+ // TODO: should the update method be called on the root pane instead?
+ Container contentPane = SwingUtilities.getRootPane(swingComponent).getContentPane();
+ SwingUtilities.updateComponentTreeUI(contentPane);
+ }
+ }
+
+ private void updateLookAndFeel(java.awt.Font awtFont) {
+ assert awtFont != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // The FontUIResource class marks the font as replaceable by the look and feel
+ // implementation if font settings are later changed.
+ FontUIResource fontResource = new FontUIResource(awtFont);
+
+ // Assign the new font to the relevant L&F font properties. These are
+ // the properties that are initially assigned to the system font
+ // under the Windows look and feel.
+ // TODO: It's possible that other platforms will need other assignments.
+ // TODO: This does not handle fonts other than the "system" font.
+ // Other fonts may change, and the Swing L&F may not be adjusting.
+
+ UIManager.put("Button.font", fontResource); //$NON-NLS-1$
+ UIManager.put("CheckBox.font", fontResource); //$NON-NLS-1$
+ UIManager.put("ComboBox.font", fontResource); //$NON-NLS-1$
+ UIManager.put("EditorPane.font", fontResource); //$NON-NLS-1$
+ UIManager.put("Label.font", fontResource); //$NON-NLS-1$
+ UIManager.put("List.font", fontResource); //$NON-NLS-1$
+ UIManager.put("Panel.font", fontResource); //$NON-NLS-1$
+ UIManager.put("ProgressBar.font", fontResource); //$NON-NLS-1$
+ UIManager.put("RadioButton.font", fontResource); //$NON-NLS-1$
+ UIManager.put("ScrollPane.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TabbedPane.font", fontResource); //$NON-NLS-1$
+ UIManager.put("Table.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TableHeader.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TextField.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TextPane.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TitledBorder.font", fontResource); //$NON-NLS-1$
+ UIManager.put("ToggleButton.font", fontResource); //$NON-NLS-1$
+ UIManager.put("TreeFont.font", fontResource); //$NON-NLS-1$
+ UIManager.put("ViewportFont.font", fontResource); //$NON-NLS-1$
+ }
+
+ /**
+ * Performs custom updates to newly set fonts. This method is called whenever a change
+ * to the system font through the system settings (i.e. control panel) is detected.
+ *
+ * This method is called from the AWT event thread.
+ *
+ * In most cases it is not necessary to override this method. Normally, the implementation
+ * of this class will automatically propogate font changes to the embedded Swing components
+ * through Swing's Look and Feel support. However, if additional
+ * special processing is necessary, it can be done inside this method.
+ *
+ * @param newFont New AWT font
+ */
+ protected void updateAwtFont(java.awt.Font newFont) {
+ }
+
+ private void handleSettingsChange() {
+ Font newFont = getDisplay().getSystemFont();
+ if (!newFont.equals(currentSystemFont)) {
+ currentSystemFont = newFont;
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ setComponentFont();
+ }
+ });
+ }
+ }
+
+}
+ * embeddedComposite = new SWTAWTComposite(parent, SWT.NONE) {
+ * protected JComponent createSwingComponent() {
+ * scrollPane = new JScrollPane();
+ * table = new JTable();
+ * scrollPane.setViewportView(table);
+ * return scrollPane;
+ * }
+ * };
+ * // For asynchronous AWT UI population of the swing components:
+ * embeddedComposite.populate();
+ * // and optionally you can wait until the AWT UI population
+ * // has finished:
+ * embeddedComposite.waitUntilPopulated();
+ *
+ * // OR:
+ *
+ * // Do both things above in one call to block until the
+ * // AWT UI population is complete:
+ * embeddedComposite.syncPopulate();
+ *
+ * // OR:
+ *
+ * // Set a callback for asynchronous completion in the AWT thread:
+ * embeddedComposite.populate(component -> {
+ // AWT components have been created for component
+ * });
+ *
+ * // All methods assume all invocations are made from the SWT display thread.
+ *
+ *