package org.expeditee.items.widgets; import java.awt.Component; import java.awt.Container; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import javax.swing.JComponent; import org.expeditee.core.bounds.AxisAlignedBoxBounds; import org.expeditee.gio.EcosystemManager; import org.expeditee.gio.EcosystemManager.Ecosystem; import org.expeditee.gio.swing.SwingGraphicsManager; import org.expeditee.gio.swing.SwingMiscManager; import org.expeditee.gui.DisplayController; import org.expeditee.items.ItemParentStateChangedEvent; import org.expeditee.items.Text; import org.expeditee.items.UserAppliedPermission; public abstract class SwingWidget extends Widget implements ContainerListener, KeyListener { // A flag for signifying whether the swing components are ready to paint. // If the swing components has not been layed out, if they are painted they // will not draw in the correct positions. // Also for setting AWT and Swing -Related drawing options after // construction private boolean _isReadyToPaint = false; protected JComponent _swingComponent; protected SwingWidget(Text source, JComponent component, int minWidth, int maxWidth, int minHeight, int maxHeight) { super(source, minWidth, maxWidth, minHeight, maxHeight); if (component == null) { throw new NullPointerException("component"); } _swingComponent = component; _swingComponent.setFocusable(true); addKeyListenerToWidget(); addThisAsContainerListenerToContent(); onBoundsChanged(); System.err.println("SwingWidget::Suppressed static setDefaultLightWeightPopupEnabled to false."); //JPopupMenu.setDefaultLightWeightPopupEnabled(false); } public JComponent getComponent() { return _swingComponent; } @Override public void keyTyped(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { //((SwingInputManager) EcosystemManager.getInputManager()).keyTyped(e); } } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { //((SwingInputManager) EcosystemManager.getInputManager()).keyTyped(e); } } @Override public void keyReleased(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { //((SwingInputManager) EcosystemManager.getInputManager()).keyTyped(e); } } /** * Makes sure we add our KeyListener to every child component, * since it seems that's the only way to make sure we capture key events in Java * (without using KeyBindings which seem to only support the keyTyped event) */ @Override public void componentAdded(ContainerEvent e) { if(e == null || e.getChild() == null) { return; } keyListenerToChildren(e.getChild(), true); } @Override public void componentRemoved(ContainerEvent e) { if(e == null || e.getChild() == null) { return; } keyListenerToChildren(e.getChild(), false); } @Override protected void addWidgetContent(final ItemParentStateChangedEvent e) { if ((e.getEventType() == ItemParentStateChangedEvent.EVENT_TYPE_ADDED_VIA_OVERLAY || e .getEventType() == ItemParentStateChangedEvent.EVENT_TYPE_SHOWN_VIA_OVERLAY) && e.getOverlayLevel().equals(UserAppliedPermission.none)) { return; // item belongs to a non-active overlay } if(_swingComponent.getParent() == null) { if (e.getEventType() == ItemParentStateChangedEvent.EVENT_TYPE_SHOWN || e.getEventType() == ItemParentStateChangedEvent.EVENT_TYPE_SHOWN_VIA_OVERLAY || e.getSource() == DisplayController.getCurrentFrame()) { onBoundsChanged(); ((SwingGraphicsManager) EcosystemManager.getGraphicsManager()).getContentPane().add(_swingComponent); layout(_swingComponent); } } } @Override protected void addKeyListenerToWidget() { keyListenerToChildren(_swingComponent, true); } @Override protected void addThisAsContainerListenerToContent() { _swingComponent.addContainerListener(this); } @Override public AxisAlignedBoxBounds getContentBounds() { //final Rectangle bounds = _swingComponent.getBounds(); //final AccessibleContext accessibleContext = _swingComponent.getAccessibleContext(); //if (accessibleContext != null) { // final Rectangle accessibleBounds = _swingComponent.getAccessibleContext().getAccessibleComponent().getBounds(); // return new AxisAlignedBoxBounds(bounds.x, bounds.y, bounds.width, bounds.height + accessibleBounds.height); //} else { // return new AxisAlignedBoxBounds(bounds.x, bounds.y, bounds.width, bounds.height); //} final Rectangle bounds = _swingComponent.getBounds(); return new AxisAlignedBoxBounds(bounds.x, bounds.y, bounds.width, bounds.height); } @Override protected void layout() { layout(_swingComponent); } private void keyListenerToChildren(Component parent, boolean add) { List components = new LinkedList(); components.add(parent); while(!components.isEmpty()) { Component c = components.remove(0); if(c instanceof Container) { components.addAll(Arrays.asList(((Container)c).getComponents())); } if(add && !Arrays.asList(c.getKeyListeners()).contains(this)) { c.addKeyListener(this); } else if (!add && Arrays.asList(c.getKeyListeners()).contains(this)) { c.removeKeyListener(this); } } } @Override protected void onMoved() { // Do nothing } @Override protected void onSizeChanged() { onBoundsChanged(); layout(_swingComponent); } @Override public final void onBoundsChanged() { if (_swingComponent == null) { return; } if (isFixedSize()) { _swingComponent.setBounds(getX(), getY(), getMaxWidth(), getMaxHeight()); } else { _swingComponent.setBounds(getX(), getY(), getWidth(), getHeight()); } } private void prepareToPaint() { _isReadyToPaint = true; layout(_swingComponent); ignoreAWTPainting(_swingComponent); } private void ignoreAWTPainting(Component c) { if (c == null) { return; } if (c instanceof JComponent) { ((JComponent) c).setDoubleBuffered(false); } c.setIgnoreRepaint(true); if (c instanceof Container) { for (Component child : ((Container) c).getComponents()) { if(child instanceof Container) { ignoreAWTPainting(child); } else { if(child instanceof JComponent) { ((JComponent) child).setDoubleBuffered(false); } child.setIgnoreRepaint(true); } } } } /** * Due to absolute positioning... * * @param parent */ private void layout(Component parent) { if (parent == null) { return; } parent.validate(); if (parent instanceof Container) { for (Component child : ((Container) parent).getComponents()) { layout(child); } } } @Override protected final void paintWidget() { if (!_isReadyToPaint) { prepareToPaint(); } Graphics2D g = SwingMiscManager.getIfUsingSwingGraphicsManager().getCurrentSurface(); paintSwingWidget(g); } /** Can be overridden to enable custom painting of widgets. */ protected void paintSwingWidget(Graphics2D g) { final Point location = _swingComponent.getLocation(); int x = location.x; int y = location.y; g.translate(x, y); _swingComponent.paint(g); g.translate(-x, -y); } @Override public boolean isSupportedOnEcosystem(Ecosystem type) { return type == Ecosystem.Swing; } }