Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[albireo-dev] SWT Popup Support

I've merged in the ILOG contribution to allow SWT menus to be attached to Swing components. Things went smoothly on Windows, but not on Gtk.

After first merging the code into our codebase, I was not able to show SWT popups on Gtk. I'd right click on the AWT component, and nothing would happen. I found this newsgroup post which describes my problem:

http://dev.eclipse.org/newslists/news.eclipse.platform.swt/msg33991.html

If the initial ILOG contribution had a fix for this, I apologize. I was not able to find it.

I did find a better solution than the one described in the newsgroup post. It works by delaying the display of the SWT popup until after the mouse button was released in the AWT component. I also needed to create a parent shell for the popup rather than using the main shell. (This change affects how clients construct their menus.) See the code for more details.

Let me know if there's a better solution.

Other than the above (on GTK only), I made only minor changes to the logic:

1) I removed the findComponentAt method since the comments indicated that it was necessary only for non-native embedded frames. We may still have to bring it back. I'm not sure.

2) I changed the way the SWT composite is discovered from the embedded AWT component. I removed the IlvSWTEmbedded interface and instead used the putClientProperty method to store a reference to the composite.

SwingControl is getting very large so I added this new code elsewhere, mostly over two new files.

There are a number of todo items. See the code.

### 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.12
diff -u -r1.12 AwtEnvironment.java
--- src/org/eclipse/albireo/core/AwtEnvironment.java	27 Feb 2008 06:23:36 -0000	1.12
+++ src/org/eclipse/albireo/core/AwtEnvironment.java	28 Feb 2008 04:46:08 -0000
@@ -77,6 +77,8 @@
 
     private final Display display;
     private final AwtDialogListener dialogListener;
+    private Shell popupParent;
+
 
     /**
      * Returns the single instance of AwtEnvironment for the given display. On
@@ -382,7 +384,7 @@
             });
         }
     };
-    
+
     private static final boolean HIDE_SWING_POPUPS_ON_SWT_MENU_OPEN = 
         (Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||  // GTK: pre-Java1.6
         (Platform.isWin32());                                                           // Win32: all JDKs
@@ -445,5 +447,28 @@
         }
     }
 
-
+    /**
+     * Returns a suitable parent shell for a SWT menu attached to a Swing control. 
+     * Use the return value from this method to create any SWT menus that 
+     * are used in calls to 
+     * {@link SwtPopupRegistry#setMenu(Component, boolean, org.eclipse.swt.widgets.Menu)}.
+     * Otherwise, the popup menu may not display on some platforms. 
+     * 
+     * @param control the SwingControl that owns the AWT component which will have
+     * a menu attached. 
+     * @return
+     */
+    public Shell getSwtPopupParent(SwingControl control) {
+        // TODO: move to AwtEnvironment and dispose properly
+        if (Platform.isGtk()) {
+            if (true && (popupParent == null)) {
+                // System.err.println("*** Creating separate popup parent shell");
+                popupParent = new Shell(display, SWT.NO_TRIM | SWT.NO_FOCUS | SWT.ON_TOP);
+                popupParent.setSize(0, 0);
+            }
+            return popupParent;
+        } else {
+            return control.getShell();
+        }
+    }
 }
Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.49
diff -u -r1.49 SwingControl.java
--- src/org/eclipse/albireo/core/SwingControl.java	27 Feb 2008 17:24:51 -0000	1.49
+++ src/org/eclipse/albireo/core/SwingControl.java	28 Feb 2008 04:46:08 -0000
@@ -35,6 +35,7 @@
 import org.eclipse.albireo.internal.ComponentDebugging;
 import org.eclipse.albireo.internal.FocusHandler;
 import org.eclipse.albireo.internal.Platform;
+import org.eclipse.albireo.internal.SwtPopupHandler;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.awt.SWT_AWT;
@@ -51,6 +52,7 @@
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.Widget;
 
 public abstract class SwingControl extends Composite {
@@ -59,6 +61,8 @@
     // and layout.
     static final boolean verboseSizeLayout = false;
 
+    public static final String SWT_PARENT_PROPERTY_KEY = "org.eclipse.albireo.swtParent";
+
     private Listener settingsListener = new Listener() {
         public void handleEvent(Event event) {
             handleSettingsChange();
@@ -207,6 +211,7 @@
         EventQueue.invokeLater(new Runnable() {
             public void run() {
                 rootPaneContainer = addRootPaneContainer(frame);
+                initPopupMenuSupport(rootPaneContainer.getRootPane());
 
                 // Customize the UI look&feel before calling
                 // createSwingComponent(), so that preferred sizes will be
@@ -217,8 +222,10 @@
                 swingComponent = createSwingComponent();
                 if (swingComponent != null) {
                     rootPaneContainer.getRootPane().getContentPane().add(swingComponent);
+                    swingComponent.putClientProperty(SWT_PARENT_PROPERTY_KEY, SwingControl.this);
                 }
-
+                setComponentFont();
+                setComponentColors(foreground, background);
                 // Invoke hooks, for use by the application.
                 afterComponentCreatedAWTThread();
                 try {
@@ -452,8 +459,9 @@
     }
 
     // We have bidirectional size propagation, from AWT to SWT, and from
-    // SWT to AWT. To minimize pointless notification, we inhibit propagation
-    // in this situation:
+    // SWT to AWT. To avoid endless recursion in weird cases (for example,
+    // when the AWT component refuses to accept the size that the SWT
+    // component assigns it), we inhibit propagation in this situation:
     // AWT rootpane.validate() ---> SWT layout() -|->  AWT frame.setBounds.
     //
     // When more than one SwingControl is involved, the situation is more
@@ -653,13 +661,13 @@
             // values then! It is better than to use them.
             //
             // Do not optimize with the cachedSizesInitialized flag on GTK/Java5 or 
-            // win32 since this may prevent the initial contents of the control
-            // from being displayed. Testcases: EmbeddedJTableView, TestResizeView.
+            // win32/SWT3.3 since this may prevent the initial contents of the control
+            // from being displayed. Testcase: EmbeddedJTableView.
             // TODO: research the initial content display problem further
             synchronized (this) {
                 if ((cachedSizesInitialized >= 2) || 
                         (Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||
-                        Platform.isWin32()) {
+                        (Platform.isWin32() && Platform.SWT_VERSION < Platform.SWT_34)) {
                     setAWTSize(width, height);
                 }
             }
@@ -794,7 +802,7 @@
         assert currentSystemFont != null;
         assert EventQueue.isDispatchThread();    // On AWT event thread
 
-        if (!currentSystemFont.getDevice().isDisposed()) {
+        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
@@ -812,12 +820,10 @@
             // Allow subclasses to react to font change if necessary.
             updateAwtFont(awtFont);
 
-            // Allow components to update their UI based on new font.
-            if (swingComponent != null) {
-                // TODO: should the update method be called on the root pane instead?
-                Container contentPane = swingComponent.getRootPane().getContentPane();
-                SwingUtilities.updateComponentTreeUI(contentPane);
-            }
+            // Allow components to update their UI based on new font
+            // TODO: should the update method be called on the root pane instead?
+            Container contentPane = swingComponent.getRootPane().getContentPane();
+            SwingUtilities.updateComponentTreeUI(contentPane);
         }
     }
 
@@ -1074,9 +1080,44 @@
         }
     };
 
+    // ============================= SWT Popup Management =============================
+
+    // ------------------------ Displaying a popup menu ------------------------
+
+    /**
+     * Returns the popup menu to be used on a given component.
+     * <p>
+     * The default implementation walks up the component hierarchy, looking
+     * for popup menus registered with {@link #setMenu} and as fallback at
+     * the popup menu registered on this <code>Control</code>.
+     * <p>
+     * This method can be overridden, to achieve dynamic popup menus.
+     * @param component The component on which a popup event was received.
+     * @param x The x coordinate, relative to the component's top left corner,
+     *          of the mouse cursor when the event occurred.
+     * @param y The y coordinate, relative to the component's top left corner,
+     *          of the mouse cursor when the event occurred.
+     * @param xAbsolute The x coordinate, relative to this control's top left
+     *                  corner, of the mouse cursor when the event occurred.
+     * @param yAbsolute The y coordinate, relative to this control's top left
+     *                  corner, of the mouse cursor when the event occurred.
+     */
+    public Menu getMenu(java.awt.Component component, int x, int y, int xAbsolute, int yAbsolute) {
+        assert Display.getCurrent() != null;
+
+        Menu menu = SwtPopupRegistry.getInstance().findMenu(component, x, y, xAbsolute, yAbsolute);
+        if (menu == null) {
+            // Fallback: The menu set through the SWT API on this Control.
+            menu = getMenu();
+        }
+        return menu;
+    }
+
+    protected void initPopupMenuSupport(javax.swing.JRootPane root) {
+        SwtPopupHandler.getInstance().monitorAwtComponent(root);
+    }
+
     public String toString() {
         return super.toString() + " [frame=" + ((frame != null) ? frame.getName() : "null") + "]";
     }
-    
-    
 }
Index: src/org/eclipse/albireo/core/SwtPopupRegistry.java
===================================================================
RCS file: src/org/eclipse/albireo/core/SwtPopupRegistry.java
diff -N src/org/eclipse/albireo/core/SwtPopupRegistry.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/core/SwtPopupRegistry.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2005-2008 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.core;
+
+import java.util.WeakHashMap;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+
+
+/**
+ */
+public class SwtPopupRegistry {
+    // -------------------- Static registry of popup menus --------------------
+
+    /**
+     * A popup menu specification.
+     */
+    private static class MenuInfo {
+        // The menu that shall appear.
+        Menu menu;
+        // Whether it also applies to subcomponents (if not overridden).
+        boolean recursive;
+        // Constructor.
+        MenuInfo(Menu menu, boolean recursive) {
+            this.menu = menu;
+            this.recursive = recursive;
+        }
+    }
+
+    private WeakHashMap /* java.awt.Component -> MenuInfo */ menuTable =
+        new WeakHashMap();
+
+    /**
+     * Returns the registered menu for a given component.
+     * @param component An AWT/Swing component.
+     * @param recursive Whether to look for a recursive or for a non-recursive
+     *                  specification of a popup menu.
+     * @return A popup menu, or <code>null</code>.
+     */
+    public Menu getMenu(java.awt.Component component, boolean recursive) {
+        synchronized(menuTable) {
+            MenuInfo mi = (MenuInfo)menuTable.get(component);
+            if (mi != null && mi.recursive == recursive)
+                return mi.menu;
+            else
+                return null;
+        }
+    }
+
+    /**
+     * Registers a popup menu for a given component and, optionally, its
+     * subcomponents.
+     * <p>
+     * Note: You can only specify one popup menu on a given component. You
+     * cannot specify a recursive and a non-recursive popup menu simultaneously
+     * on the same component.
+     * @param component An AWT/Swing component.
+     * @param recursive Whether the menu also applies to subcomponents (unless
+     *                  another popup menu is specified on the subcomponent or
+     *                  a component in between in the hierarchy).
+     * @param menu A popup menu, or <code>null</code> to clear the previously
+     *             specified popup menu.
+     */
+    public void setMenu(java.awt.Component component, boolean recursive, final Menu menu) {
+        synchronized(menuTable) {
+            MenuInfo mi = (MenuInfo)menuTable.get(component);
+            if (menu != null) {
+                if (mi != null) {
+                    mi.menu = menu;
+                    mi.recursive = recursive;
+                } else {
+                    mi = new MenuInfo(menu, recursive);
+                    menuTable.put(component, mi);
+                }
+            } else {
+                if (mi != null)
+                    menuTable.remove(component);
+            }
+        }
+        
+    }
+    
+    /**
+     * Searches for a popup menu to be used on a given component.
+     * <p>
+     * The default implementation walks up the component hierarchy, looking
+     * for popup menus registered with {@link #setMenu}.
+     * <p>
+     * This method can be overridden, to achieve dynamic popup menus.
+     * @param component The component on which a popup event was received.
+     * @param x The x coordinate, relative to the component's top left corner,
+     *          of the mouse cursor when the event occurred.
+     * @param y The y coordinate, relative to the component's top left corner,
+     *          of the mouse cursor when the event occurred.
+     * @param xAbsolute The x coordinate, relative to this control's top left
+     *                  corner, of the mouse cursor when the event occurred.
+     * @param yAbsolute The y coordinate, relative to this control's top left
+     *                  corner, of the mouse cursor when the event occurred.
+     */
+    protected Menu findMenu(java.awt.Component component, int x, int y, int xAbsolute, int yAbsolute) {
+        assert Display.getCurrent() != null;
+        
+        synchronized(menuTable) {
+            MenuInfo mi = (MenuInfo)menuTable.get(component);
+            if (mi != null)
+                // On the component itself, ignore whether recursive or not.
+                return mi.menu;
+            for (java.awt.Component parent = component.getParent();
+                   parent != null;
+                   parent = parent.getParent()) {
+                mi = (MenuInfo)menuTable.get(parent);
+                if (mi != null) {
+                    if (mi.recursive)
+                        return mi.menu;
+                    else
+                        return null;
+                }
+            }
+        }
+        // not found
+        return null;
+    }
+
+    // ========================================================================
+    // Singleton design pattern
+
+    private static SwtPopupRegistry theRegistry = new SwtPopupRegistry();
+
+    /**
+     * Returns the currently active singleton of this class.
+     */
+    public static SwtPopupRegistry getInstance() {
+        return theRegistry;
+    }
+
+    /**
+     * Replaces the singleton of this class.
+     * @param instance An instance of this class or of a customized subclass.
+     */
+    public static void setInstance(SwtPopupRegistry instance) {
+        theRegistry = instance;
+    }
+
+}
Index: src/org/eclipse/albireo/internal/SwtPopupHandler.java
===================================================================
RCS file: src/org/eclipse/albireo/internal/SwtPopupHandler.java
diff -N src/org/eclipse/albireo/internal/SwtPopupHandler.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/internal/SwtPopupHandler.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,262 @@
+package org.eclipse.albireo.internal;
+
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.event.MouseEvent;
+import java.util.WeakHashMap;
+
+import javax.swing.JComponent;
+
+import org.eclipse.albireo.core.AwtEnvironment;
+import org.eclipse.albireo.core.SwingControl;
+import org.eclipse.albireo.core.ThreadingHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+
+public class SwtPopupHandler {
+
+    // Gtk will not display popup menus that are parented to the
+    // main shell. Instead we need to create and open a second
+    // shell to own the popup. Note that this means the SWT menu
+    // needs to be created by the client with the parent returned by 
+    // AwtEnvironment#getSwtPopupParent. 
+    private static final boolean CREATE_POPUP_PARENT_SHELL = Platform.isGtk();
+
+    // Gtk will not display popup menus that are made visible by an 
+    // AWT mouse click (mouse pressed event), unless we wait until 
+    // 1) the mouse has been released and 
+    // 2) the mouse event for entering the parent shell has been processed
+    // This flag enables the delay
+    // TODO: this flag effectively changes the popup trigger from mouse down to mouse up (can it be avoided?) 
+    private static final boolean DELAY_MOUSE_DOWN_SWT_POPUP_TRIGGERS = Platform.isGtk();
+    
+    // TODO: in some relatively rare cases, on GTK, SWT popups are not dismissed 
+    // It can happen if you try to dismiss it with a left click while
+    // rapidly moving the mouse. A second click will dismiss it.
+    
+    // TODO: SWT popups cannot be attached to JLabels. 
+    // Do we need to use ILOG's findComponentAt() method?
+    
+    // TODO: On windows, the AWT/Swing cursor is retained after showing the SWT popup
+    // Setting CREATE_POPUP_PARENT_SHELL to true might be a solution, but we also 
+    // need general cursor support which might also solve this problem.
+    
+    private boolean pendingSwtPopup = false;
+
+    // Listen to AWT mouse events and show SWT popups as necessary
+    private java.awt.event.AWTEventListener popupEventListener =
+        new java.awt.event.AWTEventListener() {
+        public void eventDispatched(java.awt.AWTEvent event) {
+            if (event instanceof MouseEvent) {
+                final MouseEvent me = (MouseEvent)event;
+                switch (me.getID()) {
+                case java.awt.event.MouseEvent.MOUSE_PRESSED:
+                    boolean isTrigger = me.isPopupTrigger();
+                    
+                    if (DELAY_MOUSE_DOWN_SWT_POPUP_TRIGGERS && CREATE_POPUP_PARENT_SHELL && isTrigger) {
+                        // We must delay the Swt popup here. Otherwise the parent shell will not be
+                        // properly opened if the user clicks, then drags, then releases the mouse. 
+                        
+                        // System.err.println("delaying any SWT popup display");
+                        pendingSwtPopup = true;
+                        isTrigger = false;
+                    }
+                    if (isTrigger) {
+                        handlePopupTrigger(me);
+                    }
+                    break;
+                    
+                case java.awt.event.MouseEvent.MOUSE_RELEASED:
+                    // TODO: can both conditions below ever be true on the same event? 
+                    if (pendingSwtPopup) {
+                        // Now handle any previously delayed popups
+                        // if (pendingSwtPopup) {
+                        //    System.err.println("handling any delayed SWT popup display");
+                        // }
+                        handlePopupTrigger(me);
+                        pendingSwtPopup = false;
+                    }
+                    if (me.isPopupTrigger()) {
+                        handlePopupTrigger(me);
+                    }
+                    break;
+                    
+                case java.awt.event.MouseEvent.MOUSE_CLICKED:
+                    // TODO: is MOUSE_CLICKED a valid trigger point? 
+                    if (me.isPopupTrigger()) {
+                         handlePopupTrigger(me);
+                    }
+                    break;
+                }
+            }
+        }
+
+    };
+    
+
+    // The set of toolkits to which the popupEventListener has already been added.
+    private WeakHashMap /* java.awt.Toolkit -> Boolean */ popupSupportedToolkits =
+        new WeakHashMap();
+
+    public void monitorAwtComponent(Component component) {
+        assert EventQueue.isDispatchThread();
+        
+        // Ensure the toolkit has the popupEventListener attached.
+        java.awt.Toolkit toolkit = component.getToolkit();
+        synchronized(popupSupportedToolkits) {
+            if (popupSupportedToolkits.get(toolkit) == null) {
+                toolkit.addAWTEventListener(popupEventListener, java.awt.AWTEvent.MOUSE_EVENT_MASK);
+                popupSupportedToolkits.put(toolkit, Boolean.TRUE);
+            }
+        }
+    }
+
+    protected SwingControl getSwtParent(Component c) {
+        // Return the SwingControl, if any, associated with the component
+        if (c instanceof JComponent) {
+            JComponent jc = (JComponent)c;
+            return (SwingControl)jc.getClientProperty(SwingControl.SWT_PARENT_PROPERTY_KEY);
+        } else {
+            return null;
+        }
+    }
+
+
+    protected void handlePopupTrigger(MouseEvent event) {
+        assert EventQueue.isDispatchThread();
+        
+        java.awt.Component component = (java.awt.Component)event.getSource();
+        int x = event.getX();
+        int y = event.getY();
+        // Climb up until the we find the SwingControl mapped to one of our parents
+        java.awt.Component parent = component;
+        while (parent != null && (getSwtParent(parent) == null)) {
+            x += parent.getX();
+            y += parent.getY();
+            parent = parent.getParent();
+        }
+        if (parent != null) {
+            SwingControl swtParent = getSwtParent(parent);
+            int xAbsolute = x;
+            int yAbsolute = y;
+            java.awt.Component subcomp = (Component)event.getSource();
+            showPopupMenu(swtParent, subcomp, x, y, xAbsolute, yAbsolute);
+        }
+    }
+    
+
+    // Trigger the display of the popup menu.
+    protected void showPopupMenu(final SwingControl swtParent, final java.awt.Component component, final int x, final int y, final int xAbsolute, final int yAbsolute) {
+        assert EventQueue.isDispatchThread();   
+        
+        Display display;
+        try {
+            display = swtParent.getDisplay();
+        } catch (SWTException e) {
+            if (e.code == SWT.ERROR_WIDGET_DISPOSED)
+                return;
+            else
+                throw e;
+        }
+        Runnable task =
+            new Runnable() {
+            public void run() {
+                try {
+                    if (!swtParent.isDisposed()) {
+                        showPopupMenuSWTThread(swtParent, component, x, y, xAbsolute, yAbsolute);
+                    }
+                } catch (Throwable e) {
+                    e.printStackTrace();
+                }
+            }
+        };
+        try {
+            ThreadingHandler.getInstance().asyncExec(display, task);
+        } catch (SWTException e) {
+            if (e.code == SWT.ERROR_DEVICE_DISPOSED)
+                return;
+            else
+                throw e;
+        }
+    }
+
+    // Trigger the display of the popup menu from the SWT thread.
+    protected void showPopupMenuSWTThread(SwingControl swtParent, java.awt.Component component, int x, int y, int xAbsolute, int yAbsolute) {
+        assert Display.getCurrent() != null;
+        
+        final Menu menu = swtParent.getMenu(component, x, y, xAbsolute, yAbsolute);
+        Display display = swtParent.getDisplay();
+        if (menu != null) {
+            final Shell popupParent = AwtEnvironment.getInstance(display).getSwtPopupParent(swtParent);
+            
+            if (DELAY_MOUSE_DOWN_SWT_POPUP_TRIGGERS) {
+                // Install a listener that waits until the popup parent receives 
+                // a MouseEnter event before displaying the menu. If we don't wait
+                // for this event, the menu is not displayed. 
+                popupParent.addListener(SWT.MouseEnter, new Listener() {
+                    public void handleEvent(Event e) {
+                        if (CREATE_POPUP_PARENT_SHELL) {
+                            // Install a listener to hide the (created) popup parent once the menu is 
+                            // dismissed. (Don't count on 0x0 sized shells to be invisible without this)
+                            menu.addListener(SWT.Hide, new Listener() {
+                                public void handleEvent(Event e) {
+                                    if (!popupParent.isDisposed()) {
+                                        // System.err.println("hiding popup parent");
+                                        popupParent.setVisible(false);
+                                    }
+                                    // Clean up
+                                    menu.removeListener(SWT.Hide, this);
+                                }
+                            });
+                        }
+                        
+                        if (!menu.isDisposed()) {
+                            menu.setVisible(true);
+                        }
+                        // Clean up
+                        popupParent.removeListener(SWT.MouseEnter, this);
+                    }
+                });
+            }
+            
+            if (CREATE_POPUP_PARENT_SHELL) {
+                // Display the created parent shell at the current cursor location
+                // System.err.println("*** opening popup parent" + display.getCursorLocation());
+                popupParent.setLocation(display.getCursorLocation());
+                popupParent.open();
+                // The menu is made visible in the listener above
+            } 
+            if (!DELAY_MOUSE_DOWN_SWT_POPUP_TRIGGERS) {
+                // If we are not waiting for MouseEnter, then open the menu right here
+                menu.setVisible(true);
+            }
+        }
+    }
+
+    // ========================================================================
+    // Singleton design pattern
+
+    private static SwtPopupHandler theHandler = new SwtPopupHandler();
+
+    /**
+     * Returns the currently active singleton of this class.
+     */
+    public static SwtPopupHandler getInstance() {
+        return theHandler;
+    }
+
+    /**
+     * Replaces the singleton of this class.
+     * @param instance An instance of this class or of a customized subclass.
+     */
+    public static void setInstance(SwtPopupHandler instance) {
+        theHandler = instance;
+    }
+
+
+}
#P org.eclipse.albireo.examples.plugin
Index: src/org/eclipse/albireo/examples/plugin/views/AwtPopupView.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.examples.plugin/src/org/eclipse/albireo/examples/plugin/views/AwtPopupView.java,v
retrieving revision 1.1
diff -u -r1.1 AwtPopupView.java
--- src/org/eclipse/albireo/examples/plugin/views/AwtPopupView.java	27 Feb 2008 06:23:33 -0000	1.1
+++ src/org/eclipse/albireo/examples/plugin/views/AwtPopupView.java	28 Feb 2008 04:46:09 -0000
@@ -1,10 +1,8 @@
 package org.eclipse.albireo.examples.plugin.views;
 
-import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.GridLayout;
-import java.awt.Label;
 import java.awt.MenuItem;
 import java.awt.PopupMenu;
 import java.awt.event.MouseAdapter;
@@ -12,15 +10,22 @@
 
 import javax.swing.BorderFactory;
 import javax.swing.JComponent;
-import javax.swing.JLabel;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
-import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
 
+import org.eclipse.albireo.core.AwtEnvironment;
 import org.eclipse.albireo.core.SwingControl;
+import org.eclipse.albireo.core.SwtPopupRegistry;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.part.ViewPart;
 
 public class AwtPopupView extends ViewPart {
@@ -35,17 +40,26 @@
         swingControl = new SwingControl(parent, SWT.NONE) {
 
             protected JComponent createSwingComponent() {
-                JPanel panel = new JPanel(new GridLayout(2, 1, 20, 20));
-                JLabel swingLabel = new JLabel("Open Swing Popup Here");
+                JPanel panel = new JPanel(new GridLayout(3, 1, 20, 20));
+                
+                JTextField swingLabel = new JTextField("Open Swing popup here", SwingConstants.CENTER);
                 swingLabel.setFocusable(true);
                 swingLabel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
                 addSwingPopup(swingLabel);
                 panel.add(swingLabel);
-                JLabel awtLabel = new JLabel("Open AWT Popup Here");
+                
+                JTextField awtLabel = new JTextField("Open AWT popup here", SwingConstants.CENTER);
                 awtLabel.setFocusable(true);
                 awtLabel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                 addAwtPopup(awtLabel);
                 panel.add(awtLabel);
+                
+                JTextField swtPopupLabel = new JTextField("Open SWT popup here", SwingConstants.CENTER);
+                //swtPopupLabel.setFocusable(true);
+                swtPopupLabel.setBorder(BorderFactory.createLineBorder(Color.RED));
+                addSwtPopup(swtPopupLabel);
+                panel.add(swtPopupLabel);
+                
                 return panel;
 
             }
@@ -58,6 +72,41 @@
 
     }
     
+    private void addSwtPopup(final Component c) {
+        swingControl.getDisplay().asyncExec(new Runnable() {
+            public void run() {
+                Shell parent = AwtEnvironment.getInstance(swingControl.getDisplay()).getSwtPopupParent(swingControl);
+                Menu menu = new Menu(parent, SWT.POP_UP);
+                final org.eclipse.swt.widgets.MenuItem item = new org.eclipse.swt.widgets.MenuItem(
+                        menu, SWT.PUSH);
+                item.setText("SWT Item 1");
+                item.addSelectionListener(new SelectionListener() {
+                    public void widgetDefaultSelected(SelectionEvent e) {
+                        showMessage(item);
+                    }
+                    public void widgetSelected(SelectionEvent e) {
+                        showMessage(item);
+                    }
+                });
+                final org.eclipse.swt.widgets.MenuItem item2 = new org.eclipse.swt.widgets.MenuItem(menu, SWT.PUSH);
+                item2.setText("SWT Item 2");
+                item2.addSelectionListener(new SelectionListener() {
+                    public void widgetDefaultSelected(SelectionEvent e) {
+                        showMessage(item2);
+                    }
+                    public void widgetSelected(SelectionEvent e) {
+                        showMessage(item2);
+                    }
+                });
+                SwtPopupRegistry.getInstance().setMenu(c, false, menu);
+            }
+
+            private void showMessage(final org.eclipse.swt.widgets.MenuItem item2) {
+                MessageDialog.openConfirm(swingControl.getShell(), item2.getText(), item2.getText());
+            }
+        });
+    }
+
     private void addAwtPopup(Component c) {
         final PopupMenu popup = new PopupMenu();
         MenuItem item = new MenuItem("AWT Item 1");

Back to the top