1 /* SwingComponentPeer.java -- An abstract base class for Swing based peers
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.awt.peer.swing;
40 import java.awt.AWTEvent;
41 import java.awt.AWTException;
42 import java.awt.BufferCapabilities;
43 import java.awt.Color;
44 import java.awt.Component;
45 import java.awt.Cursor;
46 import java.awt.Dimension;
48 import java.awt.FontMetrics;
49 import java.awt.Graphics;
50 import java.awt.GraphicsConfiguration;
51 import java.awt.GraphicsDevice;
52 import java.awt.GraphicsEnvironment;
53 import java.awt.Image;
54 import java.awt.Point;
55 import java.awt.Rectangle;
56 import java.awt.Toolkit;
57 import java.awt.BufferCapabilities.FlipContents;
58 import java.awt.event.KeyEvent;
59 import java.awt.event.MouseEvent;
60 import java.awt.event.PaintEvent;
61 import java.awt.image.ColorModel;
62 import java.awt.image.ImageObserver;
63 import java.awt.image.ImageProducer;
64 import java.awt.image.VolatileImage;
65 import java.awt.peer.ComponentPeer;
66 import java.awt.peer.ContainerPeer;
69 * The base class for Swing based component peers. This provides the basic
70 * functionality needed for Swing based component peers. Many methods are
71 * implemented to forward to the Swing component. Others however forward
72 * to the component's parent and expect the toplevel component peer to provide
73 * a real implementation of it. These are for example the key methods
74 * {@link #getGraphics()} and {@link #createImage(int, int)}, as well as
75 * {@link #getLocationOnScreen()}.
77 * This class also provides the necesary hooks into the Swing painting and
78 * event handling system. In order to achieve this, it traps paint, mouse and
79 * key events in {@link #handleEvent(AWTEvent)} and calls some special methods
80 * ({@link #peerPaint(Graphics)}, {@link #handleKeyEvent(KeyEvent)},
81 * {@link #handleMouseEvent(MouseEvent)} and
82 * {@link #handleMouseMotionEvent(MouseEvent)}) that call the corresponding
85 * @author Roman Kennke (kennke@aicas.com)
87 public class SwingComponentPeer
88 implements ComponentPeer
92 * The AWT component for this peer.
94 protected Component awtComponent;
97 * The Swing component for this peer.
99 protected SwingComponent swingComponent;
102 * Creates a SwingComponentPeer instance. Subclasses are expected to call
103 * this constructor and thereafter call
104 * {@link #init(Component, SwingComponent)} in order to setup the AWT and
105 * Swing components properly.
107 protected SwingComponentPeer()
109 // Nothing to do here.
113 * Initializes the AWT and Swing component for this peer. It is expected that
114 * subclasses call this from within their constructor.
116 * @param awtComp the AWT component for this peer
117 * @param swingComp the Swing component for this peer
119 protected void init(Component awtComp, SwingComponent swingComp)
121 awtComponent = awtComp;
122 swingComponent = swingComp;
126 * Returns the construction status of the specified image. This is called
127 * by {@link Component#checkImage(Image, int, int, ImageObserver)}.
129 * @param img the image
130 * @param width the width of the image
131 * @param height the height of the image
132 * @param ob the image observer to be notified of updates of the status
134 * @return a bitwise ORed set of ImageObserver flags
136 public int checkImage(Image img, int width, int height, ImageObserver ob)
138 return Toolkit.getDefaultToolkit().checkImage(img, width, height, ob);
142 * Creates an image by starting the specified image producer. This is called
143 * by {@link Component#createImage(ImageProducer)}.
145 * @param prod the image producer to be used to create the image
147 * @return the created image
149 public Image createImage(ImageProducer prod)
151 Image image = Toolkit.getDefaultToolkit().createImage(prod);
156 * Creates an empty image with the specified <code>width</code> and
157 * <code>height</code>.
159 * This is implemented to let the parent component create the image. This
160 * eventually goes up to the top-level component peer, which is then expected
161 * to deliver the image.
163 * @param width the width of the image to be created
164 * @param height the height of the image to be created
166 * @return the created image
168 public Image createImage(int width, int height)
170 GraphicsEnvironment graphicsEnv =
171 GraphicsEnvironment.getLocalGraphicsEnvironment();
172 GraphicsDevice dev = graphicsEnv.getDefaultScreenDevice();
173 GraphicsConfiguration conf = dev.getDefaultConfiguration();
174 Image image = conf.createCompatibleImage(width, height);
179 * Disables the component. This is called by {@link Component#disable()}.
181 public void disable()
183 if (swingComponent != null)
184 swingComponent.getJComponent().setEnabled(false);
188 * Disposes the component peer. This should release all resources held by the
189 * peer. This is called when the component is no longer in use.
191 public void dispose()
194 swingComponent = null;
198 * Enables the component. This is called by {@link Component#enable()}.
202 if (swingComponent != null)
203 swingComponent.getJComponent().setEnabled(true);
207 * Returns the color model of the component. This is currently not used.
209 * @return the color model of the component
211 public ColorModel getColorModel()
213 // FIXME: When this peer method will be used, we need to provide an
214 // implementation of this, probably forwarding to the toplevel peer, like
215 // in the other methods.
220 * Returns the font metrics for the specified font. This is called by
221 * {@link Component#getFontMetrics(Font)}.
223 * This is implemented to query the font metrics from the parent component.
224 * This will eventually call the top-level component peer, which is then
225 * expected to deliver a font metrics object.
227 * @param f the font for which to query the font metrics
229 * @return the font metrics for the specified font
231 public FontMetrics getFontMetrics(Font f)
233 Component parent = awtComponent.getParent();
234 ComponentPeer parentPeer = parent.getPeer();
235 return parentPeer.getFontMetrics(f);
239 * Returns a {@link Graphics} object suitable for drawing on this component.
240 * This is called by {@link Component#getGraphics()}.
242 * This is implemented to query the graphics from the parent component and
243 * adjust the clip and translation to match this component.
244 * This will eventually call the top-level component peer, which is then
245 * expected to deliver a graphics object.
247 * @return a graphics object suitable for drawing on this component
249 public Graphics getGraphics()
251 Component parent = awtComponent.getParent();
252 ComponentPeer parentPeer = parent.getPeer();
253 Graphics g = parentPeer.getGraphics();
254 g.translate(awtComponent.getX(), awtComponent.getY());
255 g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight());
260 * Returns the location of this component in screen coordinates. This is
261 * called by {@link Component#getLocationOnScreen()}.
263 * This is implemented to query the parent component peer for its screen
264 * location and adds the offset of this component to it. This will eventually
265 * call the top-level component's peer, which is then expected to provide
266 * it's screen location.
268 * @return the location of this component in screen coordinates
270 public Point getLocationOnScreen()
272 Component parent = awtComponent.getParent();
273 ComponentPeer parentPeer = parent.getPeer();
274 Point location = parentPeer.getLocationOnScreen();
275 location.x += awtComponent.getX();
276 location.y += awtComponent.getY();
281 * Returns the minimum size for the component. This is called by
282 * {@link Component#getMinimumSize()}.
284 * This is implemented to return the Swing component's minimum size.
286 * @return the minimum size for the component
288 public Dimension getMinimumSize()
291 if (swingComponent != null)
292 retVal = swingComponent.getJComponent().getMinimumSize();
294 retVal = new Dimension(0, 0);
299 * Returns the preferred size for the component. This is called by
300 * {@link Component#getPreferredSize()}.
302 * This is implemented to return the Swing component's preferred size.
304 * @return the preferred size for the component
306 public Dimension getPreferredSize()
309 if (swingComponent != null)
310 retVal = swingComponent.getJComponent().getPreferredSize();
312 retVal = new Dimension(0, 0);
317 * Returns the toolkit that created this peer.
319 * @return the toolkit that created this peer
321 public Toolkit getToolkit()
323 return Toolkit.getDefaultToolkit();
327 * Handles the given event. This is called from
328 * {@link Component#dispatchEvent(AWTEvent)} to give the peer a chance to
329 * react to events for the component.
333 public void handleEvent(AWTEvent e)
337 case PaintEvent.UPDATE:
338 case PaintEvent.PAINT:
339 Graphics g = getGraphics();
340 Rectangle clip = ((PaintEvent)e).getUpdateRect();
341 g.clipRect(clip.x, clip.y, clip.width, clip.height);
342 //if (this instanceof LightweightPeer)
344 if (e.getID() == PaintEvent.UPDATE)
345 awtComponent.update(g);
347 awtComponent.paint(g);
349 // We paint the 'heavyweights' at last, so that they appear on top of
355 case MouseEvent.MOUSE_PRESSED:
356 case MouseEvent.MOUSE_RELEASED:
357 case MouseEvent.MOUSE_CLICKED:
358 case MouseEvent.MOUSE_ENTERED:
359 case MouseEvent.MOUSE_EXITED:
360 handleMouseEvent((MouseEvent) e);
362 case MouseEvent.MOUSE_MOVED:
363 case MouseEvent.MOUSE_DRAGGED:
364 handleMouseMotionEvent((MouseEvent) e);
366 case KeyEvent.KEY_PRESSED:
367 case KeyEvent.KEY_RELEASED:
368 case KeyEvent.KEY_TYPED:
369 handleKeyEvent((KeyEvent) e);
372 // Other event types are not handled here.
378 * Makes the component invisible. This is called from
379 * {@link Component#hide()}.
381 * This is implemented to call setVisible(false) on the Swing component.
385 if (swingComponent != null)
386 swingComponent.getJComponent().setVisible(false);
390 * Returns <code>true</code> if the component can receive keyboard input
391 * focus. This is called from {@link Component#isFocusTraversable()}.
393 * This is implemented to return isFocusable() from the Swing component.
395 * @specnote Part of the earlier 1.1 API, replaced by isFocusable().
397 public boolean isFocusTraversable()
399 return swingComponent != null ?
400 swingComponent.getJComponent().isFocusable() : false;
404 * Returns <code>true</code> if the component can receive keyboard input
405 * focus. This is called from {@link Component#isFocusable()}.
407 * This is implemented to return isFocusable() from the Swing component.
409 public boolean isFocusable()
411 return swingComponent != null ?
412 swingComponent.getJComponent().isFocusable() : false;
416 * Returns the minimum size for the component. This is called by
417 * {@link Component#minimumSize()}.
419 * This is implemented to return the Swing component's minimum size.
421 * @return the minimum size for the component
423 public Dimension minimumSize()
426 if (swingComponent != null)
427 retVal = swingComponent.getJComponent().getMinimumSize();
429 retVal = new Dimension(0, 0);
434 * Returns the preferred size for the component. This is called by
435 * {@link Component#getPreferredSize()}.
437 * This is implemented to return the Swing component's preferred size.
439 * @return the preferred size for the component
441 public Dimension preferredSize()
444 if (swingComponent != null)
445 retVal = swingComponent.getJComponent().getPreferredSize();
447 retVal = new Dimension(0, 0);
451 public void paint(Graphics graphics)
453 // FIXME: I don't know what this method is supposed to do.
457 * Prepares an image for rendering on this component. This is called by
458 * {@link Component#prepareImage(Image, int, int, ImageObserver)}.
460 * @param img the image to prepare
461 * @param width the desired width of the rendered image
462 * @param height the desired height of the rendered image
463 * @param ob the image observer to be notified of updates in the preparation
466 * @return <code>true</code> if the image has been fully prepared,
467 * <code>false</code> otherwise (in which case the image observer
470 public boolean prepareImage(Image img, int width, int height, ImageObserver ob)
472 Component parent = awtComponent.getParent();
476 ComponentPeer parentPeer = parent.getPeer();
477 res = parentPeer.prepareImage(img, width, height, ob);
481 res = Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob);
486 public void print(Graphics graphics)
488 // FIXME: I don't know what this method is supposed to do.
492 * Repaints the specified rectangle of this component. This is called from
493 * {@link Component#repaint(long, int, int, int, int)}.
495 * This is implemented to call repaint() on the Swing component.
497 * @param tm number of milliseconds to wait with repainting
498 * @param x the X coordinate of the upper left corner of the damaged rectangle
499 * @param y the Y coordinate of the upper left corner of the damaged rectangle
500 * @param width the width of the damaged rectangle
501 * @param height the height of the damaged rectangle
503 public void repaint(long tm, int x, int y, int width, int height)
505 if (swingComponent != null)
506 swingComponent.getJComponent().repaint(tm, x, y, width, height);
509 PaintEvent ev = new PaintEvent(awtComponent, PaintEvent.UPDATE,
510 new Rectangle(x, y, width, height));
511 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ev);
516 * Requests that this component receives the focus. This is called from
517 * {@link Component#requestFocus()}.
519 * This calls requestFocus() on the Swing component.
521 * @specnote Part of the earlier 1.1 API, apparently replaced by argument
522 * form of the same method.
524 public void requestFocus()
526 if (swingComponent != null)
527 swingComponent.getJComponent().requestFocus();
531 * Requests that this component receives the focus. This is called from
532 * {@link Component#requestFocus()}.
534 * This calls requestFocus() on the Swing component.
543 public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x)
545 if (swingComponent != null)
546 swingComponent.getJComponent().requestFocus();
547 return swingComponent != null;
551 * Notifies the peer that the bounds of this component have changed. This
552 * is called by {@link Component#reshape(int, int, int, int)}.
554 * This is implemented to call setBounds() on the Swing component.
556 * @param x the X coordinate of the upper left corner of the component
557 * @param y the Y coordinate of the upper left corner of the component
558 * @param width the width of the component
559 * @param height the height of the component
561 public void reshape(int x, int y, int width, int height)
563 if (swingComponent != null)
564 swingComponent.getJComponent().setBounds(x, y, width, height);
568 * Sets the background color of the component. This is called by
569 * {@link Component#setBackground(Color)}.
571 * This is implemented to call setBackground() on the Swing component.
573 * @param color the background color to set
575 public void setBackground(Color color)
577 if (swingComponent != null)
578 swingComponent.getJComponent().setBackground(color);
582 * Notifies the peer that the bounds of this component have changed. This
583 * is called by {@link Component#setBounds(int, int, int, int)}.
585 * This is implemented to call setBounds() on the Swing component.
587 * @param x the X coordinate of the upper left corner of the component
588 * @param y the Y coordinate of the upper left corner of the component
589 * @param width the width of the component
590 * @param height the height of the component
592 public void setBounds(int x, int y, int width, int height)
594 reshape(x, y, width, height);
598 * Sets the cursor of the component. This is called by
599 * {@link Component#setCursor(Cursor)}.
601 * This is implemented to call setCursor() on the Swing component.
603 * @specnote Part of the earlier 1.1 API, apparently no longer needed.
605 public void setCursor(Cursor cursor)
607 if (swingComponent != null)
608 swingComponent.getJComponent().setCursor(cursor);
612 * Sets the enabled/disabled state of this component. This is called by
613 * {@link Component#setEnabled(boolean)}.
615 * This is implemented to call setEnabled() on the Swing component.
617 * @param enabled <code>true</code> to enable the component,
618 * <code>false</code> to disable it
620 public void setEnabled(boolean enabled)
622 if (swingComponent != null)
623 swingComponent.getJComponent().setEnabled(enabled);
627 * Sets the font of the component. This is called by
628 * {@link Component#setFont(Font)}.
630 * This is implemented to call setFont() on the Swing component.
632 * @param font the font to set
634 public void setFont(Font font)
636 if (swingComponent != null)
637 swingComponent.getJComponent().setFont(font);
641 * Sets the foreground color of the component. This is called by
642 * {@link Component#setForeground(Color)}.
644 * This is implemented to call setForeground() on the Swing component.
646 * @param color the foreground color to set
648 public void setForeground(Color color)
650 if (swingComponent != null)
651 swingComponent.getJComponent().setForeground(color);
655 * Sets the visibility state of the component. This is called by
656 * {@link Component#setVisible(boolean)}.
658 * This is implemented to call setVisible() on the Swing component.
660 * @param visible <code>true</code> to make the component visible,
661 * <code>false</code> to make it invisible
663 public void setVisible(boolean visible)
665 if (swingComponent != null)
666 swingComponent.getJComponent().setVisible(visible);
670 * Makes the component visible. This is called by {@link Component#show()}.
672 * This is implemented to call setVisible(true) on the Swing component.
676 if (swingComponent != null)
677 swingComponent.getJComponent().setVisible(true);
681 * Get the graphics configuration of the component. The color model
682 * of the component can be derived from the configuration.
684 * This is implemented to return the GraphicsConfiguration of the parent
685 * component. This will eventually call the toplevel component peer, which
686 * is expected to provide a real implementation.
688 * @return the graphics configuration of the component
690 public GraphicsConfiguration getGraphicsConfiguration()
692 Component parent = awtComponent.getParent();
693 ComponentPeer parentPeer = parent.getPeer();
694 return parentPeer.getGraphicsConfiguration();
698 * Part of an older API, no longer needed.
700 public void setEventMask(long mask)
702 // Nothing to do here.
706 * Returns <code>true</code> if this component has been obscured,
707 * <code>false</code> otherwise. This will only work if
708 * {@link #canDetermineObscurity()} also returns <code>true</code>.
710 * This is not yet implemented.
712 * @return <code>true</code> if this component has been obscured,
713 * <code>false</code> otherwise.
715 public boolean isObscured()
721 * Returns <code>true</code> if this component peer can determine if the
722 * component has been obscured, <code>false</code> otherwise.
724 * This is not yet implemented.
726 * @return <code>true</code> if this component peer can determine if the
727 * component has been obscured, <code>false</code> otherwise
729 public boolean canDetermineObscurity()
735 * Coalesces the specified paint event.
737 * @param e the paint event
739 public void coalescePaintEvent(PaintEvent e)
741 // Nothing to do here yet.
745 * Updates the cursor. This is not yet implemented.
747 public void updateCursorImmediately()
749 // Nothing to do here yet.
753 * Returns true, if this component can handle wheel scrolling,
754 * <code>false</code> otherwise.
756 * This is not yet implemented and returns <code>false</code>.
758 * @return true, if this component can handle wheel scrolling,
759 * <code>false</code> otherwise
761 public boolean handlesWheelScrolling()
767 * A convenience method that creates a volatile image. The volatile
768 * image is created on the screen device on which this component is
769 * displayed, in the device's current graphics configuration.
771 * This is implemented to let the parent component peer create an image.
772 * This eventually ends up in the toplevel component peer, which is then
773 * responsible for creating the real image.
775 * @param width width of the image
776 * @param height height of the image
782 public VolatileImage createVolatileImage(int width, int height)
784 Component parent = awtComponent.getParent();
785 ComponentPeer parentPeer = parent.getPeer();
786 return parentPeer.createVolatileImage(width, height);
790 * Create a number of image buffers that implement a buffering
791 * strategy according to the given capabilities.
793 * This is implemented to forward to the parent component peer. Eventually
794 * this ends up in the top level component peer, which is then responsible
795 * for doing the real work.
797 * @param numBuffers the number of buffers
798 * @param caps the buffering capabilities
800 * @throws AWTException if the specified buffering strategy is not
805 public void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException
807 Component parent = awtComponent.getParent();
808 ComponentPeer parentPeer = parent.getPeer();
809 parentPeer.createBuffers(numBuffers, caps);
813 * Return the back buffer of this component.
815 * This is implemented to forward to the parent. Eventually this ends
816 * up in the toplevel component, which is then responsible for providing
819 * @return the back buffer of this component.
823 public Image getBackBuffer()
825 Component parent = awtComponent.getParent();
826 ComponentPeer parentPeer = parent.getPeer();
827 return parentPeer.getBackBuffer();
831 * Perform a page flip, leaving the contents of the back buffer in
832 * the specified state.
834 * This is implemented to forward to the parent. Eventually this ends
835 * up in the toplevel component, which is then responsible for doing the real
838 * @param contents the state in which to leave the back buffer
842 public void flip(FlipContents contents)
844 Component parent = awtComponent.getParent();
845 ComponentPeer parentPeer = parent.getPeer();
846 parentPeer.flip(contents);
850 * Destroy the resources created by createBuffers.
852 * This is implemented to forward to the parent component peer. Eventually
853 * this ends up in the top level component peer, which is then responsible
854 * for doing the real work.
858 public void destroyBuffers()
860 Component parent = awtComponent.getParent();
861 ComponentPeer parentPeer = parent.getPeer();
862 parentPeer.destroyBuffers();
866 * Get the bounds of this component peer.
868 * This is implemented to forward to the Swing component.
870 * @return component peer bounds
873 public Rectangle getBounds()
876 if (swingComponent != null)
877 retVal = swingComponent.getJComponent().getBounds();
879 retVal = new Rectangle();
884 * Reparent this component under another container.
889 public void reparent(ContainerPeer parent)
891 // Nothing to do here.
895 * Set the bounds of this component peer.
897 * This is implemented to forward to the swing component.
899 * @param x the new x co-ordinate
900 * @param y the new y co-ordinate
901 * @param width the new width
902 * @param height the new height
903 * @param z the new stacking level
906 public void setBounds(int x, int y, int width, int height, int z)
908 if (swingComponent != null)
909 swingComponent.getJComponent().setBounds(x, y, width, height);
910 // FIXME: Somehow handle the Z order.
914 * Check if this component supports being reparented.
916 * @return true if this component can be reparented,
920 public boolean isReparentSupported()
927 * Layout this component peer.
933 if (swingComponent != null)
934 swingComponent.getJComponent().doLayout();
938 * Triggers 'heavyweight' painting of the components. This usually calls
939 * paint() on the Swing component.
941 * @param g the graphics context to use for painting
943 protected void peerPaint(Graphics g)
945 if (swingComponent != null)
946 swingComponent.getJComponent().paint(g);
950 * Handles mouse events on the component. This is usually forwarded to the
951 * SwingComponent's processMouseEvent() method.
953 * @param e the mouse event
955 protected void handleMouseEvent(MouseEvent e)
957 if (swingComponent != null)
958 swingComponent.handleMouseEvent(e);
962 * Handles mouse motion events on the component. This is usually forwarded
963 * to the SwingComponent's processMouseMotionEvent() method.
965 * @param e the mouse motion event
967 protected void handleMouseMotionEvent(MouseEvent e)
969 if (swingComponent != null)
970 swingComponent.handleMouseMotionEvent(e);
974 * Handles key events on the component. This is usually forwarded to the
975 * SwingComponent's processKeyEvent() method.
977 * @param e the key event
979 protected void handleKeyEvent(KeyEvent e)
981 if (swingComponent != null)
982 swingComponent.handleKeyEvent(e);
986 * Returns the AWT component for this peer.
988 * @return the AWT component for this peer
990 public Component getComponent()