[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[albireo-dev] AWT modal dialog support

I've merged in the support for AWT dialogs from the SAS contribution. SWT input is blocked while any AWT modal dialog is visible. AWT modal dialogs can be parented to an embedded AWT frame, but embedded components are not required.

There is a new menu item in the example application that opens a simple modal dialog.

This code works well on Windows. In earlier version there were some problems under Linux. I'll do more testing under Linux as soon as I can.
### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
Index: src/org/eclipse/albireo/core/AwtEnvironment.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/AwtEnvironment.java,v
retrieving revision 1.3
diff -u -r1.3 AwtEnvironment.java
--- src/org/eclipse/albireo/core/AwtEnvironment.java	25 Jan 2008 15:39:58 -0000	1.3
+++ src/org/eclipse/albireo/core/AwtEnvironment.java	27 Jan 2008 17:41:34 -0000
@@ -13,16 +13,26 @@
 package org.eclipse.albireo.core;
 
 import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.swing.UnsupportedLookAndFeelException;
 
+import org.eclipse.albireo.internal.SwtInputBlocker;
+import org.eclipse.albireo.internal.AwtDialogListener;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
 
 
 /**
@@ -55,6 +65,7 @@
     private static boolean isLookAndFeelInitialized = false;
 
     private final Display display;
+    private final AwtDialogListener dialogListener;
 
     /**
      * Returns the single instance of AwtEnvironment for the given display. On
@@ -134,6 +145,171 @@
         }
 
         this.display = display;
+        
+        // Listen for AWT modal dialogs to make them modal application-wide
+        dialogListener = new AwtDialogListener(display);
+    }
+
+    /**
+     * Invokes the given runnable in the AWT event thread while blocking user
+     * input on the SWT event thread. The SWT event thread will remain blocked
+     * until the runnable task completes, at which point this method will
+     * return.
+     * <p>
+     * This method is useful for displayng modal AWT/Swing dialogs from the SWT
+     * event thread. The modal AWT/Swing dialog will always block input across
+     * the whole application, but not until it appears. By calling this method,
+     * it is guaranteed that SWT input is blocked immediately, even before the
+     * AWT/Swing dialog appears.
+     * <p>
+     * To avoid unnecessary flicker, AWT/Swing dialogs should have their parent
+     * set to a frame returned by {@link #createDialogParentFrame()}.
+     * <p>
+     * This method must be called from the SWT event thread.
+     * 
+     * @param runnable
+     *            the code to schedule on the AWT event thread
+     * @exception IllegalArgumentException
+     *                <ul>
+     *                <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
+     *                </ul>
+     * @exception SWTException
+     *                <ul>
+     *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+     *                SWT event thread
+     *                </ul>
+     */
+    public void invokeAndBlockSwt(final Runnable runnable) {
+        assert display != null;
+
+        /*
+         * This code snippet is based on the following thread on
+         * news.eclipse.platform.swt:
+         * http://dev.eclipse.org/newslists/news.eclipse.platform.swt/msg24234.html
+         */
+        if (runnable == null) {
+            SWT.error(SWT.ERROR_NULL_ARGUMENT);
+        }
+        if (!display.equals(Display.getCurrent())) {
+            SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+        }
+        
+        // Switch to the AWT thread...
+        EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                try {
+                    // do swing work...
+                    runnable.run();
+                } finally {
+                    display.asyncExec(new Runnable() {
+                        public void run() {
+                            // Unblock SWT
+                            SwtInputBlocker.unblock();
+                        }
+                    });
+                }
+            }
+        });
+
+        // Prevent user input on SWT components
+        SwtInputBlocker.block(dialogListener);
+    }
+
+    /**
+     * Creates an AWT frame suitable as a parent for AWT/Swing dialogs. 
+     * <p>
+     * This method must be called from the SWT event thread. There must be an active
+     * shell associated with the environment's display.  
+     * <p>
+     * The created frame is a non-visible child of the active shell and will be disposed when that shell
+     * is disposed.
+     * <p>
+     * See {@link #createDialogParentFrame(Shell)} for more details. 
+     * 
+     * @return a {@link java.awt.Frame} to be used for parenting dialogs
+     * @exception SWTException
+     *                <ul>
+     *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+     *                SWT event thread
+     *                </ul>
+     * @exception IllegalStateException
+     *                if the current display has no shells
+     */
+    public Frame createDialogParentFrame() {
+        if (!display.equals(Display.getCurrent())) {
+            SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+        }
+        Shell parent = display.getActiveShell();
+        if (parent == null) {
+            throw new IllegalStateException("No Active Shell"); //$NON-NLS-1$
+        }
+        return createDialogParentFrame(parent);
+    }
+    
+    /**
+     * Creates an AWT frame suitable as a parent for AWT/Swing dialogs. 
+     * <p>
+     * This method must be called from the SWT event thread. There must be an active
+     * shell associated with the environment's display.
+     * <p>
+     * The created frame is a non-visible child of the given shell and will be disposed when that shell
+     * is disposed.
+     * <p>
+     * This method is useful for creating a frame to parent any AWT/Swing
+     * dialogs created for use inside a SWT application. A modal AWT/Swing
+     * dialogs will behave better if its parent is set to the returned frame
+     * rather than to null or to an independently created {@link java.awt.Frame}.
+     * <p>
+     * The frame is positioned such that its child AWT dialogs are centered over the given
+     * parent shell's position <i>when this method is called</i>. If the parent frame is 
+     * later moved, the child will no longer be properly positioned. For best results,
+     * create a new frame with this method immediately before creating and displaying each
+     * child AWT/Swing dialog. 
+     * <p>
+     * As with any AWT window, the returned frame must be explicitly disposed.
+     *    
+     * @param parent - the SWT parent shell of the shell that will contain the returned frame  
+     * @return a {@link java.awt.Frame} to be used for parenting dialogs
+     * @exception SWTException
+     *                <ul>
+     *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+     *                SWT event thread
+     *                </ul>
+     * @exception IllegalStateException
+     *                if the current display has no shells
+     */
+    public Frame createDialogParentFrame(Shell parent) {
+        if (parent == null) {
+            SWT.error(SWT.ERROR_NULL_ARGUMENT);
+        }
+        if (!display.equals(Display.getCurrent())) {
+            SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+        }
+        final Shell shell = new Shell(parent);
+        
+        // Position and size the shell and embedded composite. This ensures that 
+        // any child dialogs will be shown in the proper position, relative to the 
+        // parent shell. 
+        shell.setBounds(parent.getBounds());
+        Composite composite = new Composite(shell, SWT.EMBEDDED);
+        shell.setLayout(new FillLayout());
+        shell.layout();
+        
+        
+        Frame frame = SWT_AWT.new_Frame(composite);
+        
+        // Clean up the shell that was created above on dispose of the frame 
+        frame.addWindowListener(new WindowAdapter() {
+            public void windowClosed(WindowEvent e) {
+                display.asyncExec(new Runnable() {
+                    public void run() {
+                        shell.dispose();
+                    }
+                });
+            }
+        });
+        
+        return frame; 
     }
 
     static private void setLookAndFeel() {
@@ -159,7 +335,7 @@
         synchronized (environmentMap) {
             AwtEnvironment instance = (AwtEnvironment)environmentMap.remove(display);
             if (instance != null) {
-//                instance.dialogListener.dispose();
+                instance.dialogListener.dispose();
             }
         }
     }
Index: src/org/eclipse/albireo/internal/SwtInputBlocker.java
===================================================================
RCS file: src/org/eclipse/albireo/internal/SwtInputBlocker.java
diff -N src/org/eclipse/albireo/internal/SwtInputBlocker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/internal/SwtInputBlocker.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2007 SAS Institute Inc., ILOG S.A.
+ * 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:
+ *     SAS Institute Inc. - initial API and implementation
+ *     ILOG S.A. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.albireo.internal;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.widgets.Dialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+
+public class SwtInputBlocker extends Dialog {
+    static private SwtInputBlocker instance = null;
+    static private int blockCount = 0;
+    private Shell shell;
+    private final AwtDialogListener dialogListener;
+
+    private SwtInputBlocker(Shell parent, AwtDialogListener dialogListener) {
+        super(parent, SWT.NONE);
+        this.dialogListener = dialogListener; 
+    }
+    
+    private Object open() {
+        assert Display.getCurrent() != null;     // On SWT event thread
+        
+        // TODO: Will SWT.NO_FOCUS help in any way here?
+        // Construct with the current display, rather than parent. This reduces problems where
+        // the AWT dialog gets covered or does not have focus when opened. 
+        // Use ON_TOP to prevent a Windows task bar button
+        shell = new Shell(Display.getCurrent(), SWT.APPLICATION_MODAL | SWT.NO_TRIM | SWT.ON_TOP);
+        // shouldn't be necesssary: shell.setMinimumSize(0, 0);
+        shell.setSize(0, 0);
+        shell.addFocusListener(new FocusAdapter() {
+            public void focusGained(FocusEvent e) {
+                // On some platforms (e.g. Linux/GTK), the 0x0 shell still appears as a dot 
+                // on the screen, so make it invisible by moving it below other windows. This
+                // is unnecessary under Windows and causes a flash, so only make the call when necessary. 
+                if (Platform.isGtk()) {
+                    shell.moveBelow(null);
+                }
+                dialogListener.requestFocus();
+            }
+        });
+        shell.open();
+        
+        Shell parent = getParent();
+        Display display = parent.getDisplay();
+        while (!shell.isDisposed()) {
+            if (!display.readAndDispatch()) {
+                display.sleep();
+            }
+        }
+        
+        // If windows from other applications have been opened while SWT was being blocked, 
+        // the original parent shell can get lost under those windows after the blocking
+        // is stopped. Force the parent shell back to the front here. 
+        parent.forceActive();
+        
+        return null;
+    }
+
+    private void close() {
+        assert shell != null;
+        
+        shell.dispose();
+    }
+
+    public static void unblock() {
+        assert blockCount >= 0;
+        assert Display.getCurrent() != null;  // On SWT event thread
+
+        
+        // System.out.println("Deleting SWT blocker");
+        if (blockCount == 0) {
+            return;
+        }
+        if ((blockCount == 1) && (instance != null)) {
+            instance.close();
+            instance = null;
+        }
+        blockCount--;
+    }
+    
+    public static void block(AwtDialogListener dialogListener) {
+        assert blockCount >= 0;
+        
+        // System.out.println("Creating SWT blocker");
+        final Display display = Display.getCurrent();
+        assert display != null;  // On SWT event thread
+        
+        blockCount++;
+        if (blockCount == 1) {
+            assert instance == null;  // should be no existing blocker
+            
+            // get a shell to parent the blocking dialog
+            Shell shell = getShell(display);
+
+            // If there is a shell to block, block input now. If there are no shells, 
+            // then there is no input to block. In the case of no shells, we are not
+            // protecting against a shell that might get created later. This is a rare
+            // enough case to skip, at least for now. In the future, a listener could be 
+            // added to cover it. 
+            // TODO: if (shell==null) add listener to block shells created later?
+            //
+            // Block is implemented with a hidden modal dialog. Using setEnabled(false) is another option, but 
+            // on some platforms that will grey the disabled controls.
+            if (shell != null) {
+                instance = new SwtInputBlocker(shell, dialogListener);
+                instance.open();
+            }
+        }
+    }
+    
+    // Find a shell to use, giving preference to the active shell.
+    static private Shell getShell(Display display) {
+        Shell shell = display.getActiveShell();
+        if (shell == null) {
+            Shell[] allShells = display.getShells();
+            if (allShells.length > 0) {
+                shell = allShells[0];
+            }
+        }
+        return shell;
+    }
+}
Index: src/org/eclipse/albireo/internal/AwtDialogListener.java
===================================================================
RCS file: src/org/eclipse/albireo/internal/AwtDialogListener.java
diff -N src/org/eclipse/albireo/internal/AwtDialogListener.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/internal/AwtDialogListener.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2007 SAS Institute Inc., ILOG S.A.
+ * 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:
+ *     SAS Institute Inc. - initial API and implementation
+ *     ILOG S.A. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.albireo.internal;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.AWTEventListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A listener that insures the proper modal behavior of Swing dialogs when running
+ * within a SWT environment. When initialized, it blocks and unblocks SWT input
+ * as modal Swing dialogs are shown and hidden. 
+ */
+public class AwtDialogListener implements AWTEventListener, ComponentListener {
+    
+    // modalDialogs should be accessed only from the AWT thread, so no
+    // synchronization is needed. 
+    private final List modalDialogs = new ArrayList();
+    private final Display display;
+    
+    /**
+     * Registers this object as an AWT event listener so that Swing dialogs have the 
+     * proper modal behavior in the containing SWT environment. This is called automatically
+     * when you construct a {@link EmbeddedSwingComposite}, and it
+     * need not be called separately in that case.  
+     * @param shell 
+     */
+    public AwtDialogListener(Display display) {
+        assert display != null;
+        
+        this.display = display;
+        Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.WINDOW_EVENT_MASK);
+    }
+    
+    private void handleRemovedDialog(Dialog awtDialog, boolean removeListener) {
+        assert awtDialog != null;
+        assert modalDialogs != null;
+        assert display != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // System.out.println("Remove dialog: " + awtDialog);
+        if (removeListener) {
+            awtDialog.removeComponentListener(this);
+        }
+        // Note: there is no isModal() check here because the dialog might 
+        // have been changed from modal to non-modal after it was opened. In this case
+        // the currently visible dialog would still act modal and we'd need to unblock
+        // SWT here when it goes away.
+        if (modalDialogs.remove(awtDialog)) {
+            display.asyncExec(new Runnable() {
+                public void run() {
+                    SwtInputBlocker.unblock();
+                }
+            });            
+        }
+    }
+
+    private void handleAddedDialog(final Dialog awtDialog) {
+        assert awtDialog != null;
+        assert modalDialogs != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // System.out.println("Add dialog: " + awtDialog);
+        
+        // Don't block if 
+        // 1) the the dialog has already triggered a block
+        // 2) the dialog is not modal, or
+        // 3) the dialog is not (yet?) visible
+        // It's not clear why/when case 3 would happen, but it has been reported and the consequences
+        // are severe if the check is not in place. 
+        if (modalDialogs.contains(awtDialog) || !awtDialog.isModal() || !awtDialog.isVisible()) {
+            return;
+        }
+        modalDialogs.add(awtDialog);
+        awtDialog.addComponentListener(this);
+        display.asyncExec(new Runnable() {
+            public void run() {
+                SwtInputBlocker.block(AwtDialogListener.this);
+            }
+        });        
+    }
+    
+    void requestFocus() {
+        // TODO: in early testing this did not always bring the dialog to the top 
+        // under some Linux desktops/window managers (e.g. metacity under GNOME).
+        // Re-test with recent changes
+        EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                assert modalDialogs != null;
+                
+                int size = modalDialogs.size();
+                if (size > 0) {
+                    final Dialog awtDialog = (Dialog)modalDialogs.get(size - 1);
+
+                    // In one case, a call to requestFocus() alone does not 
+                    // bring the AWT dialog to the top. This happens if the 
+                    // dialog is given a null parent frame. When opened, the dialog
+                    // can be hidden by the SWT window even when it obtains focus.
+                    // Calling toFront() solves the problem.
+                    
+                    // System.out.println("Bringing to front");
+
+                    Component focusOwner = awtDialog.getMostRecentFocusOwner();
+                    if (focusOwner == null) {
+                        focusOwner = awtDialog; // try the dialog itself in this case
+                    }
+                    try {
+                        focusOwner.requestFocus();
+                        awtDialog.toFront();
+                    } catch (NullPointerException e) {
+                        // Some dialogs (e.g. Windows page setup and print dialogs on JDK 1.5+) throw an NPE on
+                        // requestFocus(). There's no way to check ahead of time, so just swallow the NPE here. 
+                    }
+                }
+            }
+        });
+    }
+
+    private void handleOpenedWindow(WindowEvent event) {
+        assert event != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        Window window = event.getWindow();
+        if (window instanceof Dialog) {
+            handleAddedDialog((Dialog)window);
+        }
+    }
+    
+    private void handleClosedWindow(WindowEvent event) {
+        assert event != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // Dispose-based close
+        Window window = event.getWindow();
+        if (window instanceof Dialog) {
+            // Remove dialog and component listener
+            handleRemovedDialog((Dialog)window, true);
+        }
+    }
+
+    private void handleClosingWindow(WindowEvent event) {
+        assert event != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // System-based close 
+        Window window = event.getWindow();
+        if (window instanceof Dialog) {
+            final Dialog dialog = (Dialog) window;
+            // Defer until later. Bad things happen if 
+            // handleRemovedDialog() is called directly from 
+            // this event handler. The Swing dialog does not close
+            // properly and its modality remains in effect.
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    // Remove dialog and component listener
+                    handleRemovedDialog(dialog, true);
+                }
+            });
+        }
+    }
+    
+    public void dispose() {
+        Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+    }
+    
+    public void eventDispatched(AWTEvent event) {
+        assert event != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        switch (event.getID()) {
+        case WindowEvent.WINDOW_OPENED:
+            handleOpenedWindow((WindowEvent)event);
+            break;
+            
+        case WindowEvent.WINDOW_CLOSED:
+            handleClosedWindow((WindowEvent)event);
+            break;
+
+        case WindowEvent.WINDOW_CLOSING:
+            handleClosingWindow((WindowEvent)event);
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    public void componentHidden(ComponentEvent e) {
+        assert e != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // System.out.println("Component hidden");
+        Object obj = e.getSource();
+        if (obj instanceof Dialog) {
+            // Remove dialog but keep listener in place so that we know if/when it is set visible
+            handleRemovedDialog((Dialog)obj, false);
+        }
+    }
+
+    public void componentShown(ComponentEvent e) {
+        assert e != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // System.out.println("Component shown");
+        Object obj = e.getSource();
+        if (obj instanceof Dialog) {
+            handleAddedDialog((Dialog)obj);
+        }
+    }
+
+    public void componentResized(ComponentEvent e) {
+        // Ignore event
+    }
+
+    public void componentMoved(ComponentEvent e) {
+        // Ignore event
+    }
+        
+}
#P org.eclipse.albireo.examples.plugin
Index: plugin.xml
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.examples.plugin/plugin.xml,v
retrieving revision 1.7
diff -u -r1.7 plugin.xml
--- plugin.xml	27 Jan 2008 00:56:11 -0000	1.7
+++ plugin.xml	27 Jan 2008 17:41:35 -0000
@@ -63,5 +63,26 @@
             name="SWT Bug #58308">
       </view>
    </extension>
+   <extension
+         point="org.eclipse.ui.actionSets">
+      <actionSet
+            id="org.eclipse.albireo.examples.plugin.actionSet"
+            label="AWT Dialog Action Set"
+            visible="true">
+         <menu
+               id="dialogMenu"
+               label="Dialogs">
+            <separator
+                  name="group">
+            </separator>
+         </menu>
+         <action
+               class="org.eclipse.albireo.examples.plugin.actions.SimpleDialogAction"
+               id="org.eclipse.albireo.examples.plugin.actions.SimpleDialogAction"
+               label="Open Simple Swing Dialog"
+               menubarPath="dialogMenu/group">
+         </action>
+      </actionSet>
+   </extension>
 
 </plugin>
Index: src/org/eclipse/albireo/examples/plugin/actions/SimpleDialogAction.java
===================================================================
RCS file: src/org/eclipse/albireo/examples/plugin/actions/SimpleDialogAction.java
diff -N src/org/eclipse/albireo/examples/plugin/actions/SimpleDialogAction.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/examples/plugin/actions/SimpleDialogAction.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,40 @@
+package org.eclipse.albireo.examples.plugin.actions;
+
+import java.awt.Frame;
+
+import javax.swing.JOptionPane;
+
+import org.eclipse.albireo.core.AwtEnvironment;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+public class SimpleDialogAction implements IWorkbenchWindowActionDelegate {
+	private IWorkbenchWindow window;
+	/**
+	 * The constructor.
+	 */
+	public SimpleDialogAction() {
+	}
+
+	public void run(IAction action) {
+	    AwtEnvironment env = AwtEnvironment.getInstance(window.getShell().getDisplay());
+	    final Frame frame = env.createDialogParentFrame(window.getShell());
+	    env.invokeAndBlockSwt(new Runnable() {
+            public void run() {
+                JOptionPane.showMessageDialog(frame, "A Simple Message Dialog");
+            }
+        });
+	}
+
+	public void selectionChanged(IAction action, ISelection selection) {
+	}
+
+	public void dispose() {
+	}
+
+	public void init(IWorkbenchWindow window) {
+		this.window = window;
+	}
+}