NativeComponentProxyPanel.java :  » Swing-Library » DJ-Project-0.9.9 » chrriis » dj » nativeswing » Java Open Source

Java Open Source » Swing Library » DJ Project 0.9.9 
DJ Project 0.9.9 » chrriis » dj » nativeswing » NativeComponentProxyPanel.java
/*
 * Christopher Deckers (chrriis@nextencia.net)
 * http://www.nextencia.net
 *
 * See the file "readme.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */
package chrriis.dj.nativeswing;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.HierarchyBoundsListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.beans.PropertyVetoException;
import java.util.Arrays;

import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;

import chrriis.common.Filter;
import chrriis.common.UIUtils;
import chrriis.dj.nativeswing.NativeComponentWrapper.NativeComponentHolder;

import com.sun.jna.examples.WindowUtils;


/**
 * @author Christopher Deckers
 */
class NativeComponentProxyPanel extends NativeComponentProxy {

  private static final boolean IS_DEBUGGING_SHAPE = Boolean.parseBoolean(NSSystemProperty.COMPONENTS_DEBUG_PRINTSHAPECOMPUTING.get());

  private boolean isProxiedFiliation;

  private AWTEventListener shapeAdjustmentEventListener;

  private boolean isDestructionOnFinalization;
  private boolean isVisibilityConstrained;

  NativeComponentProxyPanel(NativeComponentWrapper nativeComponentWrapper, boolean isVisibilityConstrained, boolean isDestructionOnFinalization, boolean isProxiedFiliation) {
    super(nativeComponentWrapper);
    this.isDestructionOnFinalization = isDestructionOnFinalization;
    this.isVisibilityConstrained = isVisibilityConstrained;
    hierarchyListener = new HierarchyListener() {
      public void hierarchyChanged(HierarchyEvent e) {
        long changeFlags = e.getChangeFlags();
        if((changeFlags & (HierarchyEvent.SHOWING_CHANGED)) != 0) {
          if(NativeComponentProxyPanel.this.isVisibilityConstrained) {
            adjustEmbeddedPanelShape();
          } else {
            adjustEmbeddedPanelBounds();
          }
        }
      }
    };
    if(isVisibilityConstrained) {
      shapeAdjustmentEventListener = new AWTEventListener() {
        public void eventDispatched(AWTEvent e) {
          boolean isAdjustingShape = false;
          switch(e.getID()) {
            case ContainerEvent.COMPONENT_ADDED:
            case ContainerEvent.COMPONENT_REMOVED:
            case ComponentEvent.COMPONENT_RESIZED:
            case ComponentEvent.COMPONENT_MOVED:
              isAdjustingShape = true;
              break;
            case ComponentEvent.COMPONENT_SHOWN:
            case ComponentEvent.COMPONENT_HIDDEN:
              if(e.getSource() instanceof Window) {
                isAdjustingShape = true;
              }
              break;
          }
          if(isAdjustingShape) {
            if(NativeComponentProxyPanel.this.nativeComponentWrapper.getNativeComponentProxy() == NativeComponentProxyPanel.this) {
              adjustEmbeddedPanelShape();
            }
          }
        }
      };
    }
    this.isProxiedFiliation = isProxiedFiliation;
  }

  private HierarchyBoundsListener hierarchyBoundsListener = new HierarchyBoundsListener() {
    public void ancestorMoved(HierarchyEvent e) {
      Component component = e.getChanged();
      if(component instanceof Window) {
        return;
      }
      adjustEmbeddedPanelBounds();
    }
    public void ancestorResized(HierarchyEvent e) {
      adjustEmbeddedPanelBounds();
    }
  };

  private MouseAdapter mouseListener = new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
      adjustFocus();
    }
    protected void adjustFocus() {
      for(Component parent = NativeComponentProxyPanel.this; parent != null && !(parent instanceof Window); parent = parent.getParent()) {
        if(parent instanceof JInternalFrame) {
          Window windowAncestor = SwingUtilities.getWindowAncestor(NativeComponentProxyPanel.this);
          if(windowAncestor != null) {
            boolean focusableWindowState = windowAncestor.getFocusableWindowState();
            windowAncestor.setFocusableWindowState(false);
            try {
              ((JInternalFrame)parent).setSelected(true);
            } catch (PropertyVetoException e1) {
            }
            windowAncestor.setFocusableWindowState(focusableWindowState);
          }
          break;
        }
      }
    }
  };


  private void adjustEmbeddedPanelBounds() {
    if(embeddedPanel == null) {
      return;
    }
    if(!isVisibilityConstrained) {
      boolean isShowing = isShowing();
      if(isShowing != embeddedPanel.isVisible()) {
        embeddedPanel.setVisible(isShowing);
      }
    }
    Point location = SwingUtilities.convertPoint(this, new Point(0, 0), embeddedPanel.getParent());
    Dimension size = getSize();
    Rectangle bounds = new Rectangle(location.x, location.y, size.width, size.height);
    if(!embeddedPanel.getBounds().equals(bounds)) {
      embeddedPanel.setBounds(bounds);
      embeddedPanel.invalidate();
      embeddedPanel.validate();
      embeddedPanel.repaint();
      if(isVisibilityConstrained) {
        adjustEmbeddedPanelShape();
      }
    }
  }

  private volatile boolean isInvoking;

  private void adjustEmbeddedPanelShape() {
    if(isInvoking) {
      return;
    }
    isInvoking = true;
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        isInvoking = false;
        adjustEmbeddedPanelShape_();
      }
    });
  }

  private Rectangle[] lastArea = new Rectangle[] {new Rectangle(getSize())};

  private void adjustEmbeddedPanelShape_() {
    if(embeddedPanel == null) {
      return;
    }
    Rectangle[] rectangles = computePeerShapeArea();
    if(Arrays.equals(lastArea, rectangles)) {
      return;
    }
    lastArea = rectangles;
    if(rectangles.length == 0) {
      embeddedPanel.setVisible(false);
    } else {
      if(!embeddedPanel.isVisible()) {
        embeddedPanel.setVisible(true);
      }
      WindowUtils.setComponentMask(embeddedPanel, rectangles);
//      nativeComponent.repaintNativeControl();
    }
  }

  private Rectangle[] computePeerShapeArea() {
    if(IS_DEBUGGING_SHAPE) {
      System.err.println("Computing shape: [" + NativeComponentProxyPanel.this.getWidth() + "x" + NativeComponentProxyPanel.this.getHeight() + "] " + nativeComponentWrapper.getComponentDescription());
    }
    Rectangle[] shape = UIUtils.getComponentVisibleArea(this, new Filter<Component>() {
      public boolean accept(Component c) {
        boolean isAccepted = !(c instanceof EmbeddedPanel);
        if(IS_DEBUGGING_SHAPE && isAccepted) {
          Rectangle intersectionRectangle = SwingUtilities.convertRectangle(c, new Rectangle(c.getSize()), NativeComponentProxyPanel.this).intersection(new Rectangle(NativeComponentProxyPanel.this.getSize()));
          if(!intersectionRectangle.isEmpty()) {
            System.err.println("  -> Subtracting [" + intersectionRectangle.x + "," + intersectionRectangle.y + "," + intersectionRectangle.width + "x" + intersectionRectangle.height + "] " + c);
          }
        }
        return isAccepted;
      }
    }, false);
    return shape;
  }

  @Override
  public void paint(Graphics g) {
    super.paint(g);
    // On Linux, a JInternalFrame brought to the front may generate a paint call only to that one.
    // We need to adjust the shape of the frames that go to the back as well.
    for(NativeComponentWrapper ncw: NativeSwing.getNativeComponentWrappers()) {
      NativeComponentProxy nativeComponentProxy = ncw.getNativeComponentProxy();
      if(nativeComponentProxy instanceof NativeComponentProxyPanel) {
        if(((NativeComponentProxyPanel)nativeComponentProxy).isVisibilityConstrained) {
          ((NativeComponentProxyPanel)nativeComponentProxy).adjustEmbeddedPanelShape();
        }
      }
    }
  }

  @SuppressWarnings("deprecation")
  @Override
  public void reshape(int x, int y, int w, int h) {
    if(x == getX() && y == getY() && w == getWidth() && h == getHeight()) {
      return;
    }
    super.reshape(x, y, w, h);
    adjustEmbeddedPanelBounds();
  }

  private static class EmbeddedPanel extends Panel implements NativeComponentHolder {

    public EmbeddedPanel() {
      super(new BorderLayout());
      enableEvents(MouseWheelEvent.MOUSE_WHEEL_EVENT_MASK);
    }

    @Override
    public boolean contains(int x, int y) {
      return false;
    }

    @Override
    public boolean contains(Point p) {
      return false;
    }

  }

  private EmbeddedPanel embeddedPanel;
  private HierarchyListener hierarchyListener;

  @Override
  public void addNotify() {
    super.addNotify();
    if(hierarchyListener != null) {
      addHierarchyListener(hierarchyListener);
    }
    if(shapeAdjustmentEventListener != null) {
      Toolkit.getDefaultToolkit().addAWTEventListener(shapeAdjustmentEventListener, AWTEvent.COMPONENT_EVENT_MASK | AWTEvent.CONTAINER_EVENT_MASK);
    }
    JLayeredPane layeredPane = null;
    if(isProxiedFiliation) {
      // This call throws a runtime exception if the hierarchy is not compatible
      layeredPane = findLayeredPane(this);
    }
    boolean isEmbeddedPanelCreated = embeddedPanel != null;
    if(isEmbeddedPanelCreated) {
      if(isProxiedFiliation) {
        JLayeredPane oldLayeredPane = findLayeredPane(embeddedPanel);
        if(layeredPane != oldLayeredPane) {
          nativeComponentWrapper.prepareCrossWindowReparenting();
          Container oldParent = embeddedPanel.getParent();
          oldParent.remove(embeddedPanel);
          UIUtils.revalidate(oldParent);
          oldParent.repaint();
          layeredPane.setLayer(embeddedPanel, Integer.MIN_VALUE);
          layeredPane.add(embeddedPanel);
          nativeComponentWrapper.commitCrossWindowReparenting();
          UIUtils.revalidate(layeredPane);
          layeredPane.repaint();
          revalidate();
          repaint();
        }
      }
    } else {
      embeddedPanel = new EmbeddedPanel();
      embeddedPanel.add(nativeComponentWrapper.getNativeComponent(), BorderLayout.CENTER);
    }
    adjustEmbeddedPanelBounds();
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        addHierarchyBoundsListener(hierarchyBoundsListener);
        adjustEmbeddedPanelBounds();
      }
    });
    nativeComponentWrapper.getNativeComponent().addMouseListener(mouseListener);
    if(!isEmbeddedPanelCreated) {
      if(isProxiedFiliation) {
        layeredPane.setLayer(embeddedPanel, Integer.MIN_VALUE);
        layeredPane.add(embeddedPanel);
        UIUtils.revalidate(layeredPane);
        layeredPane.repaint();
      } else {
        add(embeddedPanel, BorderLayout.CENTER);
        revalidate();
        repaint();
      }
    }
  }

  @Override
  public void removeNotify() {
    super.removeNotify();
    if(hierarchyListener != null) {
      removeHierarchyListener(hierarchyListener);
    }
    if(shapeAdjustmentEventListener != null) {
      Toolkit.getDefaultToolkit().removeAWTEventListener(shapeAdjustmentEventListener);
    }
    if(isDestructionOnFinalization) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          removeHierarchyBoundsListener(hierarchyBoundsListener);
          adjustEmbeddedPanelBounds();
        }
      });
      nativeComponentWrapper.getNativeComponent().removeMouseListener(mouseListener);
      if(isVisibilityConstrained) {
        adjustEmbeddedPanelShape();
      } else {
        adjustEmbeddedPanelBounds();
      }
      return;
    }
    dispose();
  }

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    if(embeddedPanel != null) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          dispose();
        }
      });
    }
  }

  @Override
  public void dispose() {
    if(embeddedPanel == null) {
      return;
    }
    EmbeddedPanel panel = embeddedPanel;
    embeddedPanel = null;
    Container parent = panel.getParent();
    if(parent != null) {
      parent.remove(panel);
      parent.invalidate();
      parent.validate();
      parent.repaint();
    }
  }

  @Override
  public Dimension getPreferredSize() {
    if(embeddedPanel != null) {
      return embeddedPanel.getPreferredSize();
    }
    return super.getPreferredSize();
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.