-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.scenegraph.example;\r
-\r
-import java.awt.AWTEvent;\r
-import java.awt.Component;\r
-import java.awt.Container;\r
-import java.awt.Frame;\r
-import java.awt.GridLayout;\r
-import java.awt.Toolkit;\r
-import java.awt.event.AWTEventListener;\r
-import java.awt.event.MouseEvent;\r
-import java.util.concurrent.Semaphore;\r
-import java.util.concurrent.TimeUnit;\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import javax.swing.JApplet;\r
-\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.awt.SWT_AWT;\r
-import org.eclipse.swt.events.ControlAdapter;\r
-import org.eclipse.swt.events.ControlEvent;\r
-import org.eclipse.swt.graphics.GC;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.simantics.utils.threads.AWTThread;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-\r
-/**\r
- * <pre>\r
- * embeddedComposite = new SWTAWTComposite(parent, SWT.NONE) {\r
- * protected JComponent createSwingComponent() {\r
- * scrollPane = new JScrollPane();\r
- * table = new JTable();\r
- * scrollPane.setViewportView(table);\r
- * return scrollPane;\r
- * }\r
- * };\r
- * // For asynchronous AWT UI population of the swing components:\r
- * embeddedComposite.populate();\r
- * // and optionally you can wait until the AWT UI population\r
- * // has finished:\r
- * embeddedComposite.waitUntilPopulated();\r
- *\r
- * // OR:\r
- *\r
- * // Do both things above in one call to block until the\r
- * // AWT UI population is complete:\r
- * embeddedComposite.syncPopulate();\r
- *\r
- * // Both methods assume all invocations are made from the SWT display thread.\r
- * </pre>\r
- * <p>\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public abstract class SWTAWTComponent extends Composite {\r
-\r
- private Frame frame;\r
-\r
- private Component awtComponent;\r
-\r
- private JApplet panel;\r
-\r
- private final AtomicBoolean populationStarted = new AtomicBoolean(false);\r
-\r
- private final AtomicBoolean populated = new AtomicBoolean(false);\r
-\r
- private final Semaphore populationSemaphore = new Semaphore(0);\r
-\r
- private static AWTEventListener awtListener = null;\r
- \r
- public SWTAWTComponent(Composite parent, int style) {\r
- super(parent, style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.EMBEDDED);\r
- }\r
- \r
- /**\r
- * Create a global AWTEventListener for focus management.\r
- * NOTE: There is really no need to dispose this once it's been initialized\r
- * \r
- */\r
- private synchronized void initAWTEventListener() {\r
- if(awtListener == null) {\r
- awtListener = new AWTEventListener() {\r
- public void eventDispatched(AWTEvent e) {\r
- if(e.getID() == MouseEvent.MOUSE_PRESSED) {\r
- Object src = e.getSource();\r
- if(src instanceof Component) {\r
- ((Component)src).requestFocus();\r
- }\r
- }\r
- }};\r
- // Execute in AWT thread..\r
- ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
- @Override\r
- public void run() {\r
- Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.MOUSE_EVENT_MASK);\r
- }\r
- });\r
- }\r
- }\r
-\r
- protected Container getContainer() {\r
- return panel;\r
- }\r
-\r
- public Component getAWTComponent() {\r
- return awtComponent;\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- if (!isDisposed()) {\r
- frame.dispose();\r
- super.dispose();\r
- }\r
- }\r
-\r
- /**\r
- * This method must always be called from SWT thread. This prevents the\r
- * possibility of deadlock (reported between AWT and SWT) by servicing SWT\r
- * events while waiting for AWT initialization\r
- */\r
- public void syncPopulate() {\r
- populate();\r
- waitUntilPopulated();\r
- }\r
-\r
- /**\r
- * This method will create an AWT {@link Frame} through {@link SWT_AWT} and\r
- * schedule AWT canvas initialization into the AWT thread. The AWT thread initialization will release\r
- */\r
- public void populate() {\r
- if (!populationStarted.compareAndSet(false, true))\r
- throw new IllegalStateException(this + ".populate was invoked multiple times");\r
-\r
- checkWidget();\r
- //ITask task = ThreadLogger.getInstance().begin("createFrame");\r
- createFrame();\r
- //task.finish();\r
- scheduleComponentCreation();\r
- }\r
-\r
- public void waitUntilPopulated() {\r
- if (populated.get())\r
- return;\r
-\r
- try {\r
- boolean done = false;\r
- while (!done) {\r
- done = populationSemaphore.tryAcquire(10, TimeUnit.MILLISECONDS);\r
- while (!done && getDisplay().readAndDispatch()) {\r
- /*\r
- * Note: readAndDispatch can cause this to be disposed.\r
- */\r
- if(isDisposed()) return;\r
- done = populationSemaphore.tryAcquire();\r
- }\r
- }\r
- } catch (InterruptedException e) {\r
- throw new Error("EmbeddedSwingComposite population interrupted for class " + this, e);\r
- }\r
- }\r
-\r
- private void createFrame() {\r
- /*\r
- * Set a Windows specific AWT property that prevents heavyweight\r
- * components from erasing their background. Note that this is a global\r
- * property and cannot be scoped. It might not be suitable for your\r
- * application.\r
- */\r
- System.setProperty("sun.awt.noerasebackground", "true");\r
-\r
- if (frame==null)\r
- frame = SWT_AWT.new_Frame(this);\r
-\r
- // This listener clears garbage during resizing, making it looker much cleaner\r
- addControlListener(new CleanResizeListener());\r
- initAWTEventListener();\r
- }\r
-\r
- private void scheduleComponentCreation() {\r
- // Create AWT/Swing components on the AWT thread. This is\r
- // especially necessary to avoid an AWT leak bug (6411042).\r
- ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
- @Override\r
- public void run() {\r
- panel = new JApplet();\r
- panel.setLayout(new GridLayout(1,1,0,0));\r
- frame.add(panel);\r
- try {\r
- awtComponent = createSwingComponent();\r
- panel.add(awtComponent);\r
- } finally {\r
- // Needed to support #waitUntilPopulated\r
- populated.set(true);\r
- if (populationSemaphore != null)\r
- populationSemaphore.release();\r
- }\r
- }\r
- });\r
- }\r
-\r
- protected abstract Component createSwingComponent();\r
-\r
- private static class CleanResizeListener extends ControlAdapter {\r
- private Rectangle oldRect = null;\r
-\r
- @Override\r
- public void controlResized(ControlEvent e) {\r
- assert e != null;\r
- assert Display.getCurrent() != null; // On SWT event thread\r
-\r
- // Prevent garbage from Swing lags during resize. Fill exposed areas\r
- // with background color.\r
- Composite composite = (Composite) e.widget;\r
- //Rectangle newRect = composite.getBounds();\r
- //newRect = composite.getDisplay().map(composite.getParent(), composite, newRect);\r
- Rectangle newRect = composite.getClientArea();\r
- if (oldRect != null) {\r
- int heightDelta = newRect.height - oldRect.height;\r
- int widthDelta = newRect.width - oldRect.width;\r
- if ((heightDelta > 0) || (widthDelta > 0)) {\r
- GC gc = new GC(composite);\r
- try {\r
- gc.fillRectangle(newRect.x, oldRect.height, newRect.width, heightDelta);\r
- gc.fillRectangle(oldRect.width, newRect.y, widthDelta, newRect.height);\r
- } finally {\r
- gc.dispose();\r
- }\r
- }\r
- }\r
- oldRect = newRect;\r
- }\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 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
+ *******************************************************************************/
+package org.simantics.scenegraph.example;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
+import java.awt.event.MouseEvent;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.swing.JApplet;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+
+
+/**
+ * <pre>
+ * 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();
+ *
+ * // Both methods assume all invocations are made from the SWT display thread.
+ * </pre>
+ * <p>
+ *
+ * @author Tuukka Lehtonen
+ */
+public abstract class SWTAWTComponent extends Composite {
+
+ private Frame frame;
+
+ private Component awtComponent;
+
+ 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 static AWTEventListener awtListener = null;
+
+ public SWTAWTComponent(Composite parent, int style) {
+ super(parent, style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.EMBEDDED);
+ }
+
+ /**
+ * Create a global AWTEventListener for focus management.
+ * NOTE: There is really no need to dispose this once it's been initialized
+ *
+ */
+ private synchronized void initAWTEventListener() {
+ if(awtListener == null) {
+ awtListener = new AWTEventListener() {
+ public void eventDispatched(AWTEvent e) {
+ if(e.getID() == MouseEvent.MOUSE_PRESSED) {
+ Object src = e.getSource();
+ if(src instanceof Component) {
+ ((Component)src).requestFocus();
+ }
+ }
+ }};
+ // Execute in AWT thread..
+ ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+ @Override
+ public void run() {
+ Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.MOUSE_EVENT_MASK);
+ }
+ });
+ }
+ }
+
+ protected Container getContainer() {
+ return panel;
+ }
+
+ public Component getAWTComponent() {
+ return awtComponent;
+ }
+
+ @Override
+ public void dispose() {
+ if (!isDisposed()) {
+ frame.dispose();
+ super.dispose();
+ }
+ }
+
+ /**
+ * This method must always be called from SWT thread. This prevents the
+ * possibility of deadlock (reported between AWT and SWT) by servicing SWT
+ * events while waiting for AWT initialization
+ */
+ public void syncPopulate() {
+ populate();
+ waitUntilPopulated();
+ }
+
+ /**
+ * This method will create an AWT {@link Frame} through {@link SWT_AWT} and
+ * schedule AWT canvas initialization into the AWT thread. The AWT thread initialization will release
+ */
+ public void populate() {
+ if (!populationStarted.compareAndSet(false, true))
+ throw new IllegalStateException(this + ".populate was invoked multiple times");
+
+ checkWidget();
+ //ITask task = ThreadLogger.getInstance().begin("createFrame");
+ createFrame();
+ //task.finish();
+ scheduleComponentCreation();
+ }
+
+ public void waitUntilPopulated() {
+ if (populated.get())
+ return;
+
+ try {
+ boolean done = false;
+ while (!done) {
+ done = populationSemaphore.tryAcquire(10, TimeUnit.MILLISECONDS);
+ while (!done && getDisplay().readAndDispatch()) {
+ /*
+ * Note: readAndDispatch can cause this to be disposed.
+ */
+ if(isDisposed()) return;
+ done = populationSemaphore.tryAcquire();
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new Error("EmbeddedSwingComposite population interrupted for class " + this, e);
+ }
+ }
+
+ private void createFrame() {
+ /*
+ * Set a Windows specific AWT property that prevents heavyweight
+ * components from erasing their background. Note that this is a global
+ * property and cannot be scoped. It might not be suitable for your
+ * application.
+ */
+ System.setProperty("sun.awt.noerasebackground", "true");
+
+ if (frame==null)
+ frame = SWT_AWT.new_Frame(this);
+
+ // This listener clears garbage during resizing, making it looker much cleaner
+ addControlListener(new CleanResizeListener());
+ initAWTEventListener();
+ }
+
+ private void scheduleComponentCreation() {
+ // Create AWT/Swing components on the AWT thread. This is
+ // especially necessary to avoid an AWT leak bug (6411042).
+ ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+ @Override
+ public void run() {
+ panel = new JApplet();
+ panel.setLayout(new GridLayout(1,1,0,0));
+ frame.add(panel);
+ try {
+ awtComponent = createSwingComponent();
+ panel.add(awtComponent);
+ } finally {
+ // Needed to support #waitUntilPopulated
+ populated.set(true);
+ if (populationSemaphore != null)
+ populationSemaphore.release();
+ }
+ }
+ });
+ }
+
+ protected abstract Component createSwingComponent();
+
+ private static class CleanResizeListener extends ControlAdapter {
+ private Rectangle oldRect = null;
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ assert e != null;
+ assert Display.getCurrent() != null; // On SWT event thread
+
+ // Prevent garbage from Swing lags during resize. Fill exposed areas
+ // with background color.
+ Composite composite = (Composite) e.widget;
+ //Rectangle newRect = composite.getBounds();
+ //newRect = composite.getDisplay().map(composite.getParent(), composite, newRect);
+ Rectangle newRect = composite.getClientArea();
+ if (oldRect != null) {
+ int heightDelta = newRect.height - oldRect.height;
+ int widthDelta = newRect.width - oldRect.width;
+ if ((heightDelta > 0) || (widthDelta > 0)) {
+ GC gc = new GC(composite);
+ try {
+ gc.fillRectangle(newRect.x, oldRect.height, newRect.width, heightDelta);
+ gc.fillRectangle(oldRect.width, newRect.y, widthDelta, newRect.height);
+ } finally {
+ gc.dispose();
+ }
+ }
+ }
+ oldRect = newRect;
+ }
+ }
+
+}