diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-07-08 07:44:30 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-07-08 07:44:30 +0200 |
commit | 3d75736bb30623c5858fec33ad8c0a3419d35c52 (patch) | |
tree | 766f0f5b7db7f175b5578d8c4c79798119d04d3d /com |
Diffstat (limited to 'com')
7 files changed, 623 insertions, 0 deletions
diff --git a/com/trolltech/research/qtjambiawtbridge/QComponentHost.java b/com/trolltech/research/qtjambiawtbridge/QComponentHost.java new file mode 100644 index 0000000..9da0640 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QComponentHost.java @@ -0,0 +1,149 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.research.qtjambiawtbridge.generated.QComponentHostNative; +import com.trolltech.qt.gui.*; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.core.QEvent; + +import javax.swing.*; +import java.awt.*; + +public final class QComponentHost extends QComponentHostNative { + static { + Toolkit.getDefaultToolkit(); + javax.swing.UIManager.getDefaults(); + } + + private Component component; + private Frame container; + public QComponentHost(final Component hostedComponent, QWidget parent) { + super(parent); + component = hostedComponent; + setFocusPolicy(Qt.FocusPolicy.TabFocus); + } + + @Override + public void resizeEvent(QResizeEvent e) { + if (container == null) + return; + container.setBounds(0, 0, e.size().width(), e.size().height()); + } + + @Override + public boolean event(QEvent e) { + return super.event(e); + } + + @Override + protected void focusInEvent(QFocusEvent e) { + final boolean backwards = (e.reason() == Qt.FocusReason.BacktabFocusReason); + + if (!backwards && e.reason() != Qt.FocusReason.TabFocusReason) + return; + + try { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + focusAwt(backwards); + } + }); + } catch (Exception f) { + f.printStackTrace(); + } + } + + @Override + public void showEvent(QShowEvent e) { + // By trial and error, the only way to get the window handle is + // to put the component inside a Frame (which gets a window handle) + // and retrieving this in the paint method. Also, we need to make + // sure the Qt window is visible (if you attach prior to this + // then showing the window will hang indefinitely) hence we do + // this in the showEvent + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + container = RedirectContainer.embedComponent(QComponentHost.this, component); + container.setVisible(true); + } + }); + } catch (Throwable f) { f.printStackTrace(); } + } + + public QComponentHost(Component hostedComponent) { + this(hostedComponent, null); + } + + @Override + protected void closeEvent(QCloseEvent e) { + container.setVisible(false); + } + + @Override + public QSize minimumSizeHint() { + if (container == null) + return new QSize(); + + Dimension dim = container.getMinimumSize(); + return new QSize(dim.width, dim.height); + } + + @Override + public QSize sizeHint() { + if (container == null) + return new QSize(); + + Dimension d = component.getPreferredSize(); + return new QSize((int) d.getWidth(), (int) d.getHeight()); + } + + private void setFocusInQt(QWidget w, Qt.FocusReason reason) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + w.window().activateWindow(); + w.setFocus(reason); + w.update(); + } + + private void focusAwt(final boolean backwards) { + container.toFront(); + + Component c = null; + if (component instanceof Container) { + c = !backwards + ? container.getFocusTraversalPolicy().getFirstComponent((Container) component) + : container.getFocusTraversalPolicy().getLastComponent((Container) component); + } else { + c = component; + } + + if (c != null) + c.requestFocus(); + + } + + + void focusQt(final boolean backwards) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + QWidget startWidget = backwards ? QtJambiAwtBridge.previousInFocusChain(QComponentHost.this) + : nextInFocusChain(); + QWidget w = startWidget; + while (w.focusPolicy() != Qt.FocusPolicy.TabFocus + && w.focusPolicy() != Qt.FocusPolicy.StrongFocus) { + w = backwards ? QtJambiAwtBridge.previousInFocusChain(w) : w.nextInFocusChain(); + + if (w == startWidget) + break; + } + + if (w.focusPolicy() == Qt.FocusPolicy.TabFocus + || w.focusPolicy() == Qt.FocusPolicy.StrongFocus) { + w.window().setAttribute(Qt.WidgetAttribute.WA_KeyboardFocusChange, true); + setFocusInQt(w, backwards ? Qt.FocusReason.BacktabFocusReason : Qt.FocusReason.TabFocusReason); + } + } + }); + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java b/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java new file mode 100644 index 0000000..421fdb7 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java @@ -0,0 +1,128 @@ +package com.trolltech.research.qtjambiawtbridge; + +import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QWidget; + +public class QWidgetHost extends Canvas { + private static final long serialVersionUID = 1L; + + private void focusQt(final boolean backwards) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + QWidget startWidget = backwards ? QtJambiAwtBridge.previousInFocusChain(QWidgetHost.this.containedWidget) + : QWidgetHost.this.containedWidget.nextInFocusChain(); + QWidget w = startWidget; + while (w.focusPolicy() != Qt.FocusPolicy.TabFocus + && w.focusPolicy() != Qt.FocusPolicy.StrongFocus) { + w = backwards ? QtJambiAwtBridge.previousInFocusChain(w) : w.nextInFocusChain(); + + if (w == startWidget) + break; + } + + if (w.focusPolicy() == Qt.FocusPolicy.TabFocus + || w.focusPolicy() == Qt.FocusPolicy.StrongFocus) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + w.window().activateWindow(); + w.window().setAttribute(Qt.WidgetAttribute.WA_KeyboardFocusChange, true); + w.setFocus(backwards ? Qt.FocusReason.BacktabFocusReason : Qt.FocusReason.TabFocusReason); + w.update(); + } + } + }); + } + + /** + * Constructs a binding layer between AWT and a QWidget. + * + * @param containedWidget This widget will become a child of the QWidgetHost on the first AWT paint event. + */ + public QWidgetHost(QWidget containedWidget) { + QApplication.setQuitOnLastWindowClosed(false); + setFocusable(true); + + childWidget = containedWidget; + sizeHint = new QSize(); + minimumSizeHint = new QSize(); + + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (e.getOppositeComponent() == null) { + return ; + } + + Container focusCycleRoot = getFocusCycleRootAncestor(); + boolean backwards = (e.getOppositeComponent() == focusCycleRoot.getFocusTraversalPolicy().getComponentAfter(focusCycleRoot, QWidgetHost.this)); + focusQt(backwards); + } + + }); + } + + private QWidget childWidget; + private QWidgetWrapper containedWidget; + + @Override + public void paint(Graphics g) { + if (containedWidget == null) { + setVisible(false); + QApplication.invokeAndWait(new Runnable() { + public void run() { + containedWidget = new QWidgetWrapper(childWidget, QWidgetHost.this); + sizeHint = containedWidget.sizeHint(); + minimumSizeHint = containedWidget.minimumSizeHint(); + } + }); + setVisible(true); + } + + super.paint(g); + } + + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + containedWidget.move(0, 0); + containedWidget.resize(width, height); + } + }); + } + + super.setBounds(x, y, width, height); + } + + @Override + public Dimension getPreferredSize() { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + sizeHint = containedWidget.sizeHint(); + } + }); + } + return new Dimension(sizeHint.width(), sizeHint.height()); + } + QSize sizeHint; + + @Override + public Dimension getMinimumSize() { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + minimumSizeHint = containedWidget.minimumSizeHint(); + } + }); + } + return new Dimension(minimumSizeHint.width(), minimumSizeHint.height()); + } + private QSize minimumSizeHint; +} diff --git a/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java b/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java new file mode 100644 index 0000000..9bcd82d --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java @@ -0,0 +1,69 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.research.qtjambiawtbridge.generated.QWidgetHostNative; +import com.trolltech.qt.gui.*; +import com.trolltech.qt.core.Qt; + +import javax.swing.*; +import java.awt.*; + +class QWidgetWrapper extends QWidgetHostNative { + private QWidgetHost host; + + public QWidgetWrapper(QWidget child, QWidgetHost host) { + super(host); + + // Call this to make sure the widget is connected to a native window + winId(); + + this.host = host; + child.setParent(this); + + // Make sure widget fills entire parent rect + QHBoxLayout layout = new QHBoxLayout(this); + layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); + layout.setSpacing(0); + layout.addWidget(child); + + setFocusPolicy(Qt.FocusPolicy.TabFocus); + setVisible(true); + } + + @Override + public void closeEvent(QCloseEvent e) { + e.setAccepted(false); + } + + private void focusAwt(final boolean backwards) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Container c = host.getFocusCycleRootAncestor(); + + if (c != null) { + host.requestFocus(); + Component component = backwards + ? c.getFocusTraversalPolicy().getComponentBefore(c, host) + : c.getFocusTraversalPolicy().getComponentAfter(c, host); + + component.requestFocus(); + } + } + }); + } + + @Override + protected void showEvent(QShowEvent e) { + move(0, 0); + resize(host.getBounds().width, host.getBounds().height); + } + + @Override + protected synchronized void focusInEvent(QFocusEvent event) { + if (event.reason() == Qt.FocusReason.BacktabFocusReason) { + focusAwt(true); + } else if (event.reason() == Qt.FocusReason.TabFocusReason) { + focusAwt(false); + } + } +} diff --git a/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java b/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java new file mode 100644 index 0000000..943f8ff --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java @@ -0,0 +1,18 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.qt.gui.QWidget; + +import java.awt.*; + +class QtJambiAwtBridge { + public static QWidget previousInFocusChain(QWidget w ) { + QWidget prev = null, next = w.nextInFocusChain(); + while (next != w) { + prev = next; + next = next.nextInFocusChain(); + } + return prev; + } + + static native Frame getEmbeddedFrame(long widgetNativeId); +} diff --git a/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java b/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java new file mode 100644 index 0000000..424c955 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java @@ -0,0 +1,104 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QApplication; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + + +// sun.awt.x11.embeddedFrame on Linux +// see text file for osx info +class RedirectContainer { + + private static class FocusComponent extends Component { + private static final long serialVersionUID = 1L; + private QComponentHost host; + + public FocusComponent(final boolean isFocusIn, final QComponentHost host) { + this.host = host; + + setFocusable(true); + setBounds(0, 0, 1, 1); + + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + + if (e.getOppositeComponent() == null) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + return ; + } + + if (isFocusIn) { + host.focusQt(true); + } else { + host.focusQt(false); + } + } + + }); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(1, 1); + } + + @Override + public Dimension getMaximumSize() { + return new Dimension(1, 1); + } + } + + private static final long serialVersionUID = 1L; + + static Frame embedComponent(QComponentHost parent, Component component) { + Frame f = QtJambiAwtBridge.getEmbeddedFrame(parent.nativeId()); + if (f != null) { + // Connect the frame to its window handle, since it's no longer + // handled by Swing (for event processing) + f.addNotify(); + + GridBagLayout layout = new GridBagLayout(); + + f.setLayout(layout); + f.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy()); + f.setFocusTraversalPolicyProvider(true); + + GridBagConstraints focusConstraints = new GridBagConstraints(); + focusConstraints.ipadx = 0; + focusConstraints.ipady = 0; + focusConstraints.anchor = GridBagConstraints.CENTER; + focusConstraints.fill = GridBagConstraints.NONE; + focusConstraints.insets.left = 0; + focusConstraints.insets.right = 0; + focusConstraints.insets.bottom = 0; + focusConstraints.insets.top = 0; + + FocusComponent focusIn = new FocusComponent(true, parent); + + layout.setConstraints(focusIn, focusConstraints); + f.add(focusIn); + + { + GridBagConstraints constraints = (GridBagConstraints) focusConstraints.clone(); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = 1; + + f.add(component); + } + + FocusComponent focusOut = new FocusComponent(false, parent); + layout.setConstraints(focusOut, focusConstraints); + f.add(focusOut); + + f.pack(); + } + + return f; + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java b/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java new file mode 100644 index 0000000..6a2f2eb --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java @@ -0,0 +1,67 @@ +package com.trolltech.research.qtjambiawtbridge.examples; + +import com.trolltech.qt.gui.*; +import com.trolltech.research.qtjambiawtbridge.QComponentHost; + +import javax.swing.*; +import java.awt.*; + +public class AwtInQt extends QWidget { + + public AwtInQt() { + QGridLayout layout = new QGridLayout(this); + + // A few Qt widgets + layout.addWidget(new QLabel("First name:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + layout.addWidget(new QLabel("Last name:"), 1, 0); + layout.addWidget(new QLineEdit(), 1, 1); + + // The AWT part of the GUI + { + JPanel panel = new JPanel(); + + panel.setLayout(new GridLayout(1, 2)); + + panel.add(new JLabel("Social security number:")); + panel.add(new JTextField()); + + // Add the AWT panel to Qt's layout + layout.addWidget(new QComponentHost(panel), 2, 0, 1, 2); + } + + { + JPanel panel = new JPanel(); + + panel.setLayout(new GridLayout(2, 4)); + + panel.add(new JLabel("Phone number:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Address:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Credit card #:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Expiration date:")); + panel.add(new JTextField()); + + // Add the AWT panel to Qt's layout + layout.addWidget(new QComponentHost(panel), 4, 0, 1, 2); + } + + } + + public static void main(String[] args) { + QApplication.initialize(args); + + AwtInQt awtInQt = new AwtInQt(); + awtInQt.show(); + + QApplication.exec(); + + System.exit(0); + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java b/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java new file mode 100644 index 0000000..bef356e --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java @@ -0,0 +1,88 @@ +package com.trolltech.research.qtjambiawtbridge.examples; + +import java.awt.GridLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QGridLayout; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QLineEdit; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.research.qtjambiawtbridge.QWidgetHost; + +public class QtInAwt extends JFrame { + + private static final long serialVersionUID = 1L; + + public QtInAwt() { + setLayout(new GridLayout(4, 1)); + + { + JPanel row = new JPanel(); + row.setLayout(new GridLayout(1, 2)); + row.add(new JLabel("First name:")); + row.add(new JTextField()); + + add(row); + } + + { + JPanel row = new JPanel(); + row.setLayout(new GridLayout(1, 2)); + row.add(new JLabel("Last name:")); + row.add(new JTextField()); + + add(row); + } + + // The Qt part of the GUI + { + QWidget row = new QWidget(); + QGridLayout layout = new QGridLayout(row); + layout.addWidget(new QLabel("Social security number:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + + // Add the Qt widget to AWT's layout + add(new QWidgetHost(row)); + } + + { + QWidget row = new QWidget(); + QGridLayout layout = new QGridLayout(row); + layout.addWidget(new QLabel("Phone number:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + + layout.addWidget(new QLabel("Address:"), 1, 0); + layout.addWidget(new QLineEdit(), 1, 1); + + layout.addWidget(new QLabel("Credit card #:"), 0, 2); + layout.addWidget(new QLineEdit(), 0, 3); + + layout.addWidget(new QLabel("Expiration date:"), 1, 2); + layout.addWidget(new QLineEdit(), 1, 3); + + // Add the Qt widget to AWT's layout + add(new QWidgetHost(row)); + } + + } + + public static void main(String args[]) { + // We have to initialize Qt Jambi in order to use its widgets + QApplication.initialize(args); + + QtInAwt qtInAwt = new QtInAwt(); + qtInAwt.setVisible(true); + qtInAwt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + qtInAwt.setSize(640, 480); + + // We need to run a Qt Jambi event loop in this thread in order + // for its widgets to receive events + QApplication.exec(); + } + +} |