You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/03/26 00:12:17 UTC
svn commit: r758461 [16/47] - in /incubator/pivot/branches: ./ 1.1/
1.1/charts-test/ 1.1/charts-test/src/ 1.1/charts-test/src/pivot/
1.1/charts-test/src/pivot/charts/ 1.1/charts-test/src/pivot/charts/test/
1.1/charts/ 1.1/charts/lib/ 1.1/charts/src/ 1....
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/ApplicationContext.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/ApplicationContext.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/ApplicationContext.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/ApplicationContext.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,1357 @@
+/*
+ * Copyright (c) 2009 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import java.awt.AWTEvent;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Toolkit;
+import java.awt.Transparency;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureRecognizer;
+import java.awt.dnd.DragSourceContext;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceEvent;
+import java.awt.dnd.DragSourceListener;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import pivot.collections.Dictionary;
+import pivot.collections.HashMap;
+import pivot.util.ImmutableIterator;
+import pivot.wtk.Component.DecoratorSequence;
+import pivot.wtk.Manifest;
+import pivot.wtk.RemoteManifest;
+import pivot.wtk.effects.Decorator;
+
+/**
+ * Base class for application contexts.
+ * <p>
+ * TODO Fire events when entries are added to/removed from the cache?
+ * <p>
+ * TODO Provide a means of mapping common "actions" to keystrokes (e.g. "copy"
+ * to Control-C or Command-C)
+ *
+ * @author gbrown
+ */
+public abstract class ApplicationContext {
+ /**
+ * Native display host.
+ *
+ * @author gbrown
+ */
+ public final class DisplayHost extends java.awt.Container {
+ private static final long serialVersionUID = 0;
+
+ private Point mouseLocation = null;
+
+ private Component focusedComponent = null;
+
+ private Point dragLocation = null;
+ private Component dragDescendant = null;
+
+ private Manifest dragManifest = null;
+
+ private DropAction userDropAction = null;
+ private Component dropDescendant = null;
+
+ private DropTargetListener dropTargetListener = new DropTargetListener() {
+ public void dragEnter(DropTargetDragEvent event) {
+ if (dragDescendant != null) {
+ throw new IllegalStateException("Local drag already in progress.");
+ }
+
+ java.awt.Point location = event.getLocation();
+ mouseLocation = new Point(location.x, location.y);
+
+ // Initialize drag state
+ dragManifest = new RemoteManifest(event.getTransferable());
+
+ // Initialize drop state
+ userDropAction = getDropAction(event.getDropAction());
+
+ // Notify drop target
+ dropDescendant = getDropDescendant(location.x, location.y);
+
+ DropAction dropAction = null;
+
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ dropAction = dropTarget.dragEnter(dropDescendant, dragManifest,
+ getSupportedDropActions(event.getSourceActions()), userDropAction);
+ }
+
+ if (dropAction == null) {
+ event.rejectDrag();
+ } else {
+ event.acceptDrag(getNativeDropAction(dropAction));
+ }
+ }
+
+ public void dragExit(DropTargetEvent event) {
+ // Clear mouse location
+ mouseLocation = null;
+
+ // Clear drag state
+ dragManifest = null;
+
+ // Clear drop state
+ userDropAction = null;
+
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ dropTarget.dragExit(dropDescendant);
+ }
+
+ dropDescendant = null;
+ }
+
+ public void dragOver(DropTargetDragEvent event) {
+ java.awt.Point location = event.getLocation();
+
+ // Get the previous and current drop descendant and call
+ // move or exit/enter as appropriate
+ Component previousDropDescendant = dropDescendant;
+ dropDescendant = getDropDescendant(location.x, location.y);
+
+ DropAction dropAction = null;
+
+ if (previousDropDescendant == dropDescendant) {
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+
+ Point dropLocation = dropDescendant.mapPointFromAncestor(display,
+ location.x, location.y);
+ dropAction = dropTarget.dragMove(dropDescendant, dragManifest,
+ getSupportedDropActions(event.getSourceActions()),
+ dropLocation.x, dropLocation.y, userDropAction);
+ }
+ } else {
+ if (previousDropDescendant != null) {
+ DropTarget previousDropTarget = previousDropDescendant.getDropTarget();
+ previousDropTarget.dragExit(previousDropDescendant);
+ }
+
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ dropAction = dropTarget.dragEnter(dropDescendant, dragManifest,
+ getSupportedDropActions(event.getSourceActions()),
+ userDropAction);
+ }
+ }
+
+ // Update cursor
+ setCursor(getDropCursor(dropAction));
+
+ if (dropAction == null) {
+ event.rejectDrag();
+ } else {
+ event.acceptDrag(getNativeDropAction(dropAction));
+ }
+ }
+
+ public void dropActionChanged(DropTargetDragEvent event) {
+ userDropAction = getDropAction(event.getDropAction());
+
+ DropAction dropAction = null;
+
+ if (dropDescendant != null) {
+ java.awt.Point location = event.getLocation();
+ Point dropLocation = dropDescendant.mapPointFromAncestor(display,
+ location.x, location.y);
+
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ dropAction = dropTarget.userDropActionChange(dropDescendant, dragManifest,
+ getSupportedDropActions(event.getSourceActions()), dropLocation.x, dropLocation.y,
+ userDropAction);
+ }
+
+ if (dropAction == null) {
+ event.rejectDrag();
+ } else {
+ event.acceptDrag(getNativeDropAction(dropAction));
+ }
+ }
+
+ public void drop(DropTargetDropEvent event) {
+ java.awt.Point location = event.getLocation();
+ dropDescendant = getDropDescendant(location.x, location.y);
+
+ DropAction dropAction = null;
+
+ if (dropDescendant != null) {
+ Point dropLocation = dropDescendant.mapPointFromAncestor(display,
+ location.x, location.y);
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+
+ // Simulate a user drop action change to get the current drop action
+ int supportedDropActions = getSupportedDropActions(event.getSourceActions());
+
+ dropAction = dropTarget.userDropActionChange(dropDescendant, dragManifest,
+ supportedDropActions, dropLocation.x, dropLocation.y, userDropAction);
+
+ if (dropAction != null) {
+ // Perform the drop
+ event.acceptDrop(getNativeDropAction(dropAction));
+ dropTarget.drop(dropDescendant, dragManifest,
+ supportedDropActions, dropLocation.x, dropLocation.y, userDropAction);
+ }
+ }
+
+ if (dropAction == null) {
+ event.rejectDrop();
+ }
+
+ event.dropComplete(true);
+
+ // Restore the cursor to the default
+ setCursor(java.awt.Cursor.getDefaultCursor());
+
+ // Clear drag state
+ dragManifest = null;
+
+ // Clear drop state
+ dropDescendant = null;
+ }
+ };
+
+ protected DisplayHost() {
+ enableEvents(AWTEvent.COMPONENT_EVENT_MASK
+ | AWTEvent.FOCUS_EVENT_MASK
+ | AWTEvent.MOUSE_EVENT_MASK
+ | AWTEvent.MOUSE_MOTION_EVENT_MASK
+ | AWTEvent.MOUSE_WHEEL_EVENT_MASK
+ | AWTEvent.KEY_EVENT_MASK);
+
+ try {
+ System.setProperty("sun.awt.noerasebackground", "true");
+ System.setProperty("sun.awt.erasebackgroundonresize", "true");
+ } catch (SecurityException exception) {
+ }
+
+ // Add native drop support
+ new java.awt.dnd.DropTarget(this, dropTargetListener);
+
+ setFocusTraversalKeysEnabled(false);
+ }
+
+ public Point getMouseLocation() {
+ return mouseLocation;
+ }
+
+ @Override
+ public void repaint(int x, int y, int width, int height) {
+ // Ensure that the repaint call is properly bounded (some
+ // implementations of AWT do not properly clip the repaint call
+ // when x or y is negative: the negative value is converted to 0,
+ // but the width/height is not adjusted)
+ if (x < 0) {
+ width = Math.max(width + x, 0);
+ x = 0;
+ }
+
+ if (y < 0) {
+ height = Math.max(height + y, 0);
+ y = 0;
+ }
+
+ if (width > 0
+ && height > 0) {
+ super.repaint(x, y, width, height);
+ }
+ }
+
+ @Override
+ public void paint(Graphics graphics) {
+ // Intersect the clip region with the bounds of this component
+ // (for some reason, AWT does not do this automatically)
+ ((Graphics2D)graphics).clip(new java.awt.Rectangle(0, 0, getWidth(), getHeight()));
+
+ java.awt.Rectangle clipBounds = graphics.getClipBounds();
+ if (clipBounds != null
+ && !clipBounds.isEmpty()) {
+ try {
+ if (!paintVolatileBuffered((Graphics2D)graphics)) {
+ if (!paintBuffered((Graphics2D)graphics)) {
+ paintDisplay((Graphics2D)graphics);
+ }
+ }
+ } catch (RuntimeException exception) {
+ System.err.println("Exception thrown during paint(): " + exception);
+ throw exception;
+ }
+ }
+ }
+
+ /**
+ * Attempts to paint the display using an offscreen buffer.
+ *
+ * @param graphics
+ * The source graphics context.
+ *
+ * @return
+ * <tt>true</tt> if the display was painted using the offscreen
+ * buffer; <tt>false</tt>, otherwise.
+ */
+ private boolean paintBuffered(Graphics2D graphics) {
+ boolean painted = false;
+
+ // Paint the display into an offscreen buffer
+ GraphicsConfiguration gc = graphics.getDeviceConfiguration();
+ java.awt.Rectangle clipBounds = graphics.getClipBounds();
+ java.awt.image.BufferedImage bufferedImage =
+ gc.createCompatibleImage(clipBounds.width, clipBounds.height,
+ Transparency.OPAQUE);
+
+ if (bufferedImage != null) {
+ Graphics2D bufferedImageGraphics = (Graphics2D)bufferedImage.getGraphics();
+ bufferedImageGraphics.setClip(0, 0, clipBounds.width, clipBounds.height);
+ bufferedImageGraphics.translate(-clipBounds.x, -clipBounds.y);
+
+ try {
+ paintDisplay(bufferedImageGraphics);
+ graphics.drawImage(bufferedImage, clipBounds.x, clipBounds.y, this);
+ } finally {
+ bufferedImageGraphics.dispose();
+ }
+
+ painted = true;
+ }
+
+ return painted;
+ }
+
+ /**
+ * Attempts to paint the display using a volatile offscreen buffer.
+ *
+ * @param graphics
+ * The source graphics context.
+ *
+ * @return
+ * <tt>true</tt> if the display was painted using the offscreen
+ * buffer; <tt>false</tt>, otherwise.
+ */
+ private boolean paintVolatileBuffered(Graphics2D graphics) {
+ boolean painted = false;
+
+ // Paint the display into a volatile offscreen buffer
+ GraphicsConfiguration gc = graphics.getDeviceConfiguration();
+ java.awt.Rectangle clipBounds = graphics.getClipBounds();
+ java.awt.image.VolatileImage volatileImage =
+ gc.createCompatibleVolatileImage(clipBounds.width, clipBounds.height,
+ Transparency.OPAQUE);
+
+ // If we have a valid volatile image, attempt to paint the
+ // display to it
+ if (volatileImage != null) {
+ int valid = volatileImage.validate(getGraphicsConfiguration());
+
+ if (valid == java.awt.image.VolatileImage.IMAGE_OK
+ || valid == java.awt.image.VolatileImage.IMAGE_RESTORED) {
+ Graphics2D volatileImageGraphics = (Graphics2D)volatileImage.getGraphics();
+ volatileImageGraphics.setClip(0, 0, clipBounds.width, clipBounds.height);
+ volatileImageGraphics.translate(-clipBounds.x, -clipBounds.y);
+
+ try {
+ paintDisplay(volatileImageGraphics);
+ graphics.drawImage(volatileImage, clipBounds.x, clipBounds.y, this);
+ } finally {
+ volatileImageGraphics.dispose();
+ }
+
+ painted = !volatileImage.contentsLost();
+ }
+ }
+
+ return painted;
+ }
+
+ /**
+ * Paints the display including any decorators.
+ *
+ * @param graphics
+ */
+ private void paintDisplay(Graphics2D graphics) {
+ Graphics2D decoratedGraphics = graphics;
+
+ DecoratorSequence decorators = display.getDecorators();
+ int n = decorators.getLength();
+ for (int i = n - 1; i >= 0; i--) {
+ Decorator decorator = decorators.get(i);
+ decoratedGraphics = decorator.prepare(display, decoratedGraphics);
+ }
+
+ display.paint(graphics);
+
+ for (int i = 0; i < n; i++) {
+ Decorator decorator = decorators.get(i);
+ decorator.update();
+ }
+
+ // Paint the drag visual
+ if (dragDescendant != null) {
+ DragSource dragSource = dragDescendant.getDragSource();
+ Visual dragRepresentation = dragSource.getRepresentation();
+
+ if (dragRepresentation != null) {
+ Point dragOffset = dragSource.getOffset();
+ int tx = dragLocation.x - dragOffset.x;
+ int ty = dragLocation.y - dragOffset.y;
+
+ graphics.translate(tx, ty);
+ dragRepresentation.paint(graphics);
+ }
+ }
+ }
+
+ private void repaintDragRepresentation() {
+ DragSource dragSource = dragDescendant.getDragSource();
+ Visual dragRepresentation = dragSource.getRepresentation();
+
+ if (dragRepresentation != null) {
+ Point dragOffset = dragSource.getOffset();
+
+ repaint(dragLocation.x - dragOffset.x, dragLocation.y - dragOffset.y,
+ dragRepresentation.getWidth(), dragRepresentation.getHeight());
+ }
+ }
+
+ private Component getDropDescendant(int x, int y) {
+ Component dropDescendant = display.getDescendantAt(x, y);
+
+ while (dropDescendant != null
+ && dropDescendant.getDropTarget() == null) {
+ dropDescendant = dropDescendant.getParent();
+ }
+
+ if (dropDescendant != null
+ && dropDescendant.isBlocked()) {
+ dropDescendant = null;
+ }
+
+ return dropDescendant;
+ }
+
+ private void startNativeDrag(final DragSource dragSource, final MouseEvent mouseEvent) {
+ java.awt.dnd.DragSource awtDragSource = java.awt.dnd.DragSource.getDefaultDragSource();
+
+ final int supportedDropActions = dragSource.getSupportedDropActions();
+
+ DragGestureRecognizer dragGestureRecognizer =
+ new DragGestureRecognizer(java.awt.dnd.DragSource.getDefaultDragSource(), displayHost) {
+ private static final long serialVersionUID = 0;
+
+ { appendEvent(mouseEvent);
+ }
+
+ public int getSourceActions() {
+ int awtSourceActions = 0;
+
+ if (DropAction.COPY.isSelected(supportedDropActions)) {
+ awtSourceActions |= DnDConstants.ACTION_COPY;
+ }
+
+ if (DropAction.MOVE.isSelected(supportedDropActions)) {
+ awtSourceActions |= DnDConstants.ACTION_MOVE;
+ }
+
+ if (DropAction.LINK.isSelected(supportedDropActions)) {
+ awtSourceActions |= DnDConstants.ACTION_LINK;
+ }
+
+ return awtSourceActions;
+ }
+
+ protected void registerListeners() {
+ // No-op
+ }
+
+ protected void unregisterListeners() {
+ // No-op
+ }
+ };
+
+ java.util.List<InputEvent> inputEvents = new java.util.ArrayList<InputEvent>();
+ inputEvents.add(mouseEvent);
+
+ // TODO If current user drop action is supported by drag source, use it
+ // as initial action - otherwise, select MOVE, COPY, LINK in that order
+ java.awt.Point location = new java.awt.Point(mouseEvent.getX(), mouseEvent.getY());
+ DragGestureEvent trigger = new DragGestureEvent(dragGestureRecognizer,
+ DnDConstants.ACTION_MOVE, location, inputEvents);
+
+ LocalManifest dragContent = dragSource.getContent();
+ LocalManifestAdapter localManifestAdapter = new LocalManifestAdapter(dragContent);
+
+ awtDragSource.startDrag(trigger, java.awt.Cursor.getDefaultCursor(),
+ null, null, localManifestAdapter, new DragSourceListener() {
+ public void dragEnter(DragSourceDragEvent event) {
+ DragSourceContext context = event.getDragSourceContext();
+ context.setCursor(getDropCursor(getDropAction(event.getDropAction())));
+ }
+
+ public void dragExit(DragSourceEvent event) {
+ DragSourceContext context = event.getDragSourceContext();
+ context.setCursor(java.awt.Cursor.getDefaultCursor());
+ }
+
+ public void dragOver(DragSourceDragEvent event) {
+ DragSourceContext context = event.getDragSourceContext();
+ context.setCursor(getDropCursor(getDropAction(event.getDropAction())));
+ }
+
+ public void dropActionChanged(DragSourceDragEvent event) {
+ DragSourceContext context = event.getDragSourceContext();
+ context.setCursor(getDropCursor(getDropAction(event.getDropAction())));
+ }
+
+ public void dragDropEnd(DragSourceDropEvent event) {
+ DragSourceContext context = event.getDragSourceContext();
+ context.setCursor(java.awt.Cursor.getDefaultCursor());
+ }
+ });
+ }
+
+ @Override
+ protected void processComponentEvent(ComponentEvent event) {
+ super.processComponentEvent(event);
+
+ switch (event.getID()) {
+ case ComponentEvent.COMPONENT_RESIZED: {
+ display.setSize(getWidth(), getHeight());
+ break;
+ }
+
+ case ComponentEvent.COMPONENT_MOVED: {
+ // No-op
+ break;
+ }
+
+ case ComponentEvent.COMPONENT_SHOWN: {
+ // No-op
+ break;
+ }
+
+ case ComponentEvent.COMPONENT_HIDDEN: {
+ // No-op
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent event) {
+ super.processFocusEvent(event);
+
+ switch(event.getID()) {
+ case FocusEvent.FOCUS_GAINED: {
+ if (focusedComponent != null
+ && focusedComponent.isShowing()
+ && !focusedComponent.isBlocked()) {
+ focusedComponent.requestFocus(true);
+ }
+
+ break;
+ }
+
+ case FocusEvent.FOCUS_LOST: {
+ focusedComponent = Component.getFocusedComponent();
+ Component.clearFocus(true);
+
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void processMouseEvent(MouseEvent event) {
+ super.processMouseEvent(event);
+
+ int x = event.getX();
+ int y = event.getY();
+
+ // Set the mouse button state
+ int mouseButtons = 0x00;
+
+ int modifiersEx = event.getModifiersEx();
+ if ((modifiersEx & MouseEvent.BUTTON1_DOWN_MASK) > 0) {
+ mouseButtons |= Mouse.Button.LEFT.getMask();
+ }
+
+ if ((modifiersEx & MouseEvent.BUTTON2_DOWN_MASK) > 0) {
+ mouseButtons |= Mouse.Button.MIDDLE.getMask();
+ }
+
+ if ((modifiersEx & MouseEvent.BUTTON3_DOWN_MASK) > 0) {
+ mouseButtons |= Mouse.Button.RIGHT.getMask();
+ }
+
+ Mouse.setButtons(mouseButtons);
+
+ // Get the button associated with this event
+ Mouse.Button button = null;
+ switch (event.getButton()) {
+ case MouseEvent.BUTTON1: {
+ button = Mouse.Button.LEFT;
+ break;
+ }
+
+ case MouseEvent.BUTTON2: {
+ button = Mouse.Button.MIDDLE;
+ break;
+ }
+
+ case MouseEvent.BUTTON3: {
+ button = Mouse.Button.RIGHT;
+ break;
+ }
+ }
+
+ // Process the event
+ int eventID = event.getID();
+ if (eventID == MouseEvent.MOUSE_ENTERED
+ || eventID == MouseEvent.MOUSE_EXITED) {
+ switch(eventID) {
+ case MouseEvent.MOUSE_ENTERED: {
+ mouseLocation = new Point(x, y);
+ display.mouseOver();
+ break;
+ }
+
+ case MouseEvent.MOUSE_EXITED: {
+ display.mouseOut();
+ mouseLocation = null;
+ break;
+ }
+ }
+ } else {
+ // Determine the mouse owner
+ Component mouseOwner;
+ Component mouseCapturer = Mouse.getCapturer();
+ if (mouseCapturer == null) {
+ mouseOwner = display;
+ } else {
+ mouseOwner = mouseCapturer;
+ Point location = mouseOwner.mapPointFromAncestor(display, x, y);
+ x = location.x;
+ y = location.y;
+ }
+
+ // Delegate the event to the owner
+ switch (eventID) {
+ case MouseEvent.MOUSE_PRESSED: {
+ requestFocus();
+ dragLocation = new Point(x, y);
+ mouseOwner.mouseDown(button, x, y);
+ break;
+ }
+
+ case MouseEvent.MOUSE_RELEASED: {
+ if (dragDescendant == null) {
+ mouseOwner.mouseUp(button, x, y);
+ } else {
+ DragSource dragSource = dragDescendant.getDragSource();
+
+ repaintDragRepresentation();
+
+ if (dropDescendant == null) {
+ dragSource.endDrag(dragDescendant, null);
+ } else {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ DropAction dropAction = dropTarget.drop(dropDescendant, dragManifest,
+ dragSource.getSupportedDropActions(), x, y, getUserDropAction(event));
+ dragSource.endDrag(dragDescendant, dropAction);
+ }
+
+ setCursor(java.awt.Cursor.getDefaultCursor());
+
+ // Clear the drag state
+ dragDescendant = null;
+ dragManifest = null;
+
+ // Clear the drop state
+ userDropAction = null;
+ dropDescendant = null;
+ }
+
+ // Clear the drag location
+ dragLocation = null;
+
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void processMouseMotionEvent(MouseEvent event) {
+ super.processMouseMotionEvent(event);
+
+ int x = event.getX();
+ int y = event.getY();
+
+ // Set the mouse location
+ if (mouseLocation == null) {
+ mouseLocation = new Point();
+ }
+
+ mouseLocation.x = x;
+ mouseLocation.y = y;
+
+ // Process the event
+ switch (event.getID()) {
+ case MouseEvent.MOUSE_MOVED:
+ case MouseEvent.MOUSE_DRAGGED: {
+ if (dragDescendant == null) {
+ // A drag is not active
+ Component mouseCapturer = Mouse.getCapturer();
+
+ if (mouseCapturer == null) {
+ // The mouse is not captured, so propagate the event to the display
+ display.mouseMove(x, y);
+
+ int dragThreshold = Platform.getDragThreshold();
+
+ if (dragLocation != null
+ && (Math.abs(x - dragLocation.x) > dragThreshold
+ || Math.abs(y - dragLocation.y) > dragThreshold)) {
+ // The user has dragged the mouse past the drag threshold; try
+ // to find a drag source
+ dragDescendant = display.getDescendantAt(dragLocation.x,
+ dragLocation.y);
+
+ while (dragDescendant != null
+ && dragDescendant.getDragSource() == null) {
+ dragDescendant = dragDescendant.getParent();
+ }
+
+ if (dragDescendant == null
+ || dragDescendant.isBlocked()) {
+ // There was nothing to drag, so clear the drag location
+ dragDescendant = null;
+ dragLocation = null;
+ } else {
+ DragSource dragSource = dragDescendant.getDragSource();
+ dragLocation = dragDescendant.mapPointFromAncestor(display, x, y);
+
+ if (dragSource.beginDrag(dragDescendant, dragLocation.x, dragLocation.y)) {
+ // A drag has started
+ if (dragSource.isNative()) {
+ // Clear the drag state since it is not used for
+ // native drags
+ dragDescendant = null;
+ dragLocation = null;
+
+ startNativeDrag(dragSource, event);
+ } else {
+ if (dragSource.getRepresentation() != null
+ && dragSource.getOffset() == null) {
+ throw new IllegalStateException("Drag offset is required when a "
+ + " respresentation is specified.");
+ }
+
+ if (display.isMouseOver()) {
+ display.mouseOut();
+ }
+
+ // Get the drag content
+ dragManifest = dragSource.getContent();
+
+ // Get the initial user drop action
+ userDropAction = getUserDropAction(event);
+
+ // Repaint the drag visual
+ dragLocation.x = x;
+ dragLocation.y = y;
+
+ repaintDragRepresentation();
+ }
+ } else {
+ // Clear the drag state
+ dragDescendant = null;
+ dragLocation = null;
+ }
+ }
+ }
+ } else {
+ // Delegate the event to the capturer
+ Point location = mouseCapturer.mapPointFromAncestor(display, x, y);
+ mouseCapturer.mouseMove(location.x, location.y);
+ }
+ } else {
+ if (dragLocation != null) {
+ DragSource dragSource = dragDescendant.getDragSource();
+
+ // Get the previous and current drop descendant and call
+ // move or exit/enter as appropriate
+ Component previousDropDescendant = dropDescendant;
+ dropDescendant = getDropDescendant(x, y);
+
+ DropAction dropAction = null;
+
+ if (previousDropDescendant == dropDescendant) {
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+
+ Point dropLocation = dropDescendant.mapPointFromAncestor(display, x, y);
+ dropAction = dropTarget.dragMove(dropDescendant, dragManifest,
+ dragSource.getSupportedDropActions(),
+ dropLocation.x, dropLocation.y, userDropAction);
+ }
+ } else {
+ if (previousDropDescendant != null) {
+ DropTarget previousDropTarget = previousDropDescendant.getDropTarget();
+ previousDropTarget.dragExit(previousDropDescendant);
+ }
+
+ if (dropDescendant != null) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+ dropAction = dropTarget.dragEnter(dropDescendant, dragManifest,
+ dragSource.getSupportedDropActions(), userDropAction);
+ }
+ }
+
+ // Update cursor
+ setCursor(getDropCursor(dropAction));
+
+ // Repaint the drag visual
+ repaintDragRepresentation();
+
+ dragLocation.x = x;
+ dragLocation.y = y;
+
+ repaintDragRepresentation();
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void processMouseWheelEvent(MouseWheelEvent event) {
+ super.processMouseWheelEvent(event);
+
+ // Get the event coordinates
+ int x = event.getX();
+ int y = event.getY();
+
+ // Get the scroll type
+ Mouse.ScrollType scrollType = null;
+ switch (event.getScrollType()) {
+ case MouseWheelEvent.WHEEL_BLOCK_SCROLL: {
+ scrollType = Mouse.ScrollType.BLOCK;
+ break;
+ }
+
+ case MouseWheelEvent.WHEEL_UNIT_SCROLL: {
+ scrollType = Mouse.ScrollType.UNIT;
+ break;
+ }
+ }
+
+ // Process the event
+ switch (event.getID()) {
+ case MouseEvent.MOUSE_WHEEL: {
+ if (dragDescendant == null) {
+ // Determine the mouse owner
+ Component mouseOwner;
+ Component mouseCapturer = Mouse.getCapturer();
+ if (mouseCapturer == null) {
+ mouseOwner = display;
+ } else {
+ mouseOwner = mouseCapturer;
+ Point location = mouseOwner.mapPointFromAncestor(display, x, y);
+ x = location.x;
+ y = location.y;
+ }
+
+ // Delegate the event to the owner
+ mouseOwner.mouseWheel(scrollType, event.getScrollAmount(),
+ event.getWheelRotation(), x, y);
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void processKeyEvent(KeyEvent event) {
+ super.processKeyEvent(event);
+
+ // Set the keyboard modifier state
+ int keyboardModifiers = 0;
+
+ int modifiersEx = event.getModifiersEx();
+ if ((modifiersEx & KeyEvent.SHIFT_DOWN_MASK) > 0) {
+ keyboardModifiers |= Keyboard.Modifier.SHIFT.getMask();
+ }
+
+ if ((modifiersEx & KeyEvent.CTRL_DOWN_MASK) > 0) {
+ keyboardModifiers |= Keyboard.Modifier.CTRL.getMask();
+ }
+
+ if ((modifiersEx & KeyEvent.ALT_DOWN_MASK) > 0) {
+ keyboardModifiers |= Keyboard.Modifier.ALT.getMask();
+ }
+
+ if ((modifiersEx & KeyEvent.META_DOWN_MASK) > 0) {
+ keyboardModifiers |= Keyboard.Modifier.META.getMask();
+ }
+
+ Keyboard.setModifiers(keyboardModifiers);
+
+ // Get the key location
+ Keyboard.KeyLocation keyLocation = null;
+ switch (event.getKeyLocation()) {
+ case KeyEvent.KEY_LOCATION_STANDARD: {
+ keyLocation = Keyboard.KeyLocation.STANDARD;
+ break;
+ }
+
+ case KeyEvent.KEY_LOCATION_LEFT: {
+ keyLocation = Keyboard.KeyLocation.LEFT;
+ break;
+ }
+
+ case KeyEvent.KEY_LOCATION_RIGHT: {
+ keyLocation = Keyboard.KeyLocation.RIGHT;
+ break;
+ }
+
+ case KeyEvent.KEY_LOCATION_NUMPAD: {
+ keyLocation = Keyboard.KeyLocation.KEYPAD;
+ break;
+ }
+ }
+
+ if (dragDescendant == null) {
+ // Process the event
+ Component focusedComponent = Component.getFocusedComponent();
+
+ switch (event.getID()) {
+ case KeyEvent.KEY_PRESSED: {
+ int keyCode = event.getKeyCode();
+ boolean consumed = false;
+
+ if (focusedComponent != null) {
+ consumed = focusedComponent.keyPressed(keyCode, keyLocation);
+ }
+
+ if (consumed) {
+ event.consume();
+ }
+
+ break;
+ }
+
+ case KeyEvent.KEY_RELEASED: {
+ int keyCode = event.getKeyCode();
+ boolean consumed = false;
+
+ if (focusedComponent != null) {
+ consumed = focusedComponent.keyReleased(keyCode, keyLocation);
+ }
+
+ if (consumed) {
+ event.consume();
+ }
+
+ break;
+ }
+
+ case KeyEvent.KEY_TYPED: {
+ boolean consumed = false;
+
+ if (focusedComponent != null) {
+ char keyChar = event.getKeyChar();
+ consumed = focusedComponent.keyTyped(keyChar);
+ }
+
+ if (consumed) {
+ event.consume();
+ }
+
+ break;
+ }
+ }
+ } else {
+ DragSource dragSource = dragDescendant.getDragSource();
+
+ // If the user drop action changed, notify the drop descendant
+ if (dropDescendant != null) {
+ DropAction previousUserDropAction = userDropAction;
+ userDropAction = getUserDropAction(event);
+
+ if (previousUserDropAction != userDropAction) {
+ DropTarget dropTarget = dropDescendant.getDropTarget();
+
+ Point dropLocation = dropDescendant.mapPointFromAncestor(display,
+ mouseLocation.x, mouseLocation.y);
+ dropTarget.userDropActionChange(dropDescendant, dragManifest,
+ dragSource.getSupportedDropActions(),
+ dropLocation.x, dropLocation.y, userDropAction);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Resource cache dictionary implementation.
+ *
+ * @author gbrown
+ */
+ public static final class ResourceCacheDictionary
+ implements Dictionary<URL, Object>, Iterable<URL> {
+ public Object get(URL key) {
+ return resourceCache.get(key);
+ }
+
+ public Object put(URL key, Object value) {
+ return resourceCache.put(key, value);
+ }
+
+ public Object remove(URL key) {
+ return resourceCache.remove(key);
+ }
+
+ public boolean containsKey(URL key) {
+ return resourceCache.containsKey(key);
+ }
+
+ public boolean isEmpty() {
+ return resourceCache.isEmpty();
+ }
+
+ public Iterator<URL> iterator() {
+ return new ImmutableIterator<URL>(resourceCache.iterator());
+ }
+ }
+
+ public static class ScheduledCallback extends TimerTask {
+ private Runnable runnable = null;
+
+ private ScheduledCallback(Runnable runnable) {
+ this.runnable = runnable;
+ }
+
+ public void run() {
+ queueCallback(runnable);
+ }
+ }
+
+ private DisplayHost displayHost;
+ private Display display;
+
+ protected static URL origin = null;
+
+ private static HashMap<URL, Object> resourceCache = new HashMap<URL, Object>();
+ private static ResourceCacheDictionary resourceCacheDictionary = new ResourceCacheDictionary();
+
+ private static Timer timer = null;
+
+ private static final String DEFAULT_THEME_CLASS_NAME = "pivot.wtk.skin.terra.TerraTheme";
+
+ protected ApplicationContext() {
+ // Create the display host and display
+ displayHost = new DisplayHost();
+ display = new Display(displayHost);
+
+ try {
+ // Load and instantiate the default theme, if possible
+ Class<?> themeClass = Class.forName(DEFAULT_THEME_CLASS_NAME);
+ Theme.setTheme((Theme)themeClass.newInstance());
+ } catch (Exception exception) {
+ // No-op; assume that a custom theme will be installed later
+ // by the caller
+ System.err.println("Warning: Unable to load default theme.");
+ }
+ }
+
+ protected DisplayHost getDisplayHost() {
+ return displayHost;
+ }
+
+ protected Display getDisplay() {
+ return display;
+ }
+
+ /**
+ * Returns this application's origin (the URL of it's originating server).
+ */
+ public static URL getOrigin() {
+ return origin;
+ }
+
+ /**
+ * Resource properties accessor.
+ */
+ public static ResourceCacheDictionary getResourceCache() {
+ return resourceCacheDictionary;
+ }
+
+ /**
+ * Opens the resource at the given location.
+ *
+ * @param location
+ */
+ public static void open(URL location) {
+ // TODO Remove dynamic invocation when Java 6 is supported on the Mac
+
+ try {
+ Class<?> desktopClass = Class.forName("java.awt.Desktop");
+ Method getDesktopMethod = desktopClass.getMethod("getDesktop", new Class<?>[] {});
+ Method browseMethod = desktopClass.getMethod("browse", new Class[] {URI.class});
+ Object desktop = getDesktopMethod.invoke(null, (Object[]) null);
+ browseMethod.invoke(desktop, location.toURI());
+ } catch (Exception exception) {
+ System.err.println("Unable to open URL in default browser.");
+ }
+ }
+
+ /**
+ * Issues a system alert sound.
+ */
+ public static void beep() {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ /**
+ * Schedules a task for one-time execution. The task will be executed on
+ * the UI thread.
+ *
+ * @param callback
+ * The task to execute.
+ *
+ * @param delay
+ * The length of time to wait before executing the task.
+ */
+ public static ScheduledCallback scheduleCallback(Runnable callback, long delay) {
+ ScheduledCallback scheduledCallback = new ScheduledCallback(callback);
+ timer.schedule(scheduledCallback, delay);
+
+ return scheduledCallback;
+ }
+
+ /**
+ * Schedules a task for repeated execution. The task will be executed on the
+ * UI thread and will begin executing immediately.
+ *
+ * @param callback
+ * The task to execute.
+ *
+ * @param period
+ * The interval at which the task will be repeated.
+ */
+ public static ScheduledCallback scheduleRecurringCallback(Runnable callback, long period) {
+ return scheduleRecurringCallback(callback, 0, period);
+ }
+
+ /**
+ * Schedules a task for repeated execution. The task will be executed on the
+ * UI thread.
+ *
+ * @param callback
+ * The task to execute.
+ *
+ * @param delay
+ * The length of time to wait before the first execution of the task
+ *
+ * @param period
+ * The interval at which the task will be repeated.
+ */
+ public static ScheduledCallback scheduleRecurringCallback(Runnable callback, long delay, long period) {
+ ScheduledCallback scheduledCallback = new ScheduledCallback(callback);
+ timer.schedule(scheduledCallback, delay, period);
+
+ return scheduledCallback;
+ }
+
+ /**
+ * Queues a task to execute after all pending events have been processed and
+ * returns without waiting for the task to complete.
+ *
+ * @param callback
+ * The task to execute.
+ */
+ public static void queueCallback(Runnable callback) {
+ queueCallback(callback, false);
+ }
+
+ /**
+ * Queues a task to execute after all pending events have been processed and
+ * optionally waits for the task to complete.
+ *
+ * @param callback
+ * The task to execute.
+ *
+ * @param wait
+ * If <tt>true</tt>, does not return until the task has executed.
+ * Otherwise, returns immediately.
+ */
+ public static void queueCallback(Runnable callback, boolean wait) {
+ if (wait) {
+ try {
+ java.awt.EventQueue.invokeAndWait(callback);
+ } catch (InvocationTargetException exception) {
+ } catch (InterruptedException exception) {
+ }
+ } else {
+ java.awt.EventQueue.invokeLater(callback);
+ }
+ }
+
+ protected static void createTimer() {
+ timer = new Timer();
+ }
+
+ protected static void destroyTimer() {
+ timer.cancel();
+ timer = null;
+ }
+
+ private static DropAction getUserDropAction(InputEvent event) {
+ DropAction userDropAction;
+
+ if ((event.isControlDown() && event.isShiftDown())
+ || (event.isAltDown() && event.isMetaDown())) {
+ userDropAction = DropAction.LINK;
+ } else if (event.isControlDown()
+ || (event.isAltDown())) {
+ userDropAction = DropAction.COPY;
+ } else if (event.isShiftDown()){
+ userDropAction = DropAction.MOVE;
+ } else {
+ userDropAction = null;
+ }
+
+ return userDropAction;
+ }
+
+ private static DropAction getDropAction(int nativeDropAction) {
+ DropAction dropAction = null;
+
+ switch (nativeDropAction) {
+ case DnDConstants.ACTION_COPY: {
+ dropAction = DropAction.COPY;
+ break;
+ }
+
+ case DnDConstants.ACTION_MOVE: {
+ dropAction = DropAction.MOVE;
+ break;
+ }
+
+ case DnDConstants.ACTION_LINK: {
+ dropAction = DropAction.LINK;
+ break;
+ }
+ }
+
+ return dropAction;
+ }
+
+ private static int getSupportedDropActions(int sourceActions) {
+ int dropActions = 0;
+
+ if ((sourceActions & DnDConstants.ACTION_COPY) > 0) {
+ dropActions |= DropAction.COPY.getMask();
+ }
+
+ if ((sourceActions & DnDConstants.ACTION_MOVE) > 0) {
+ dropActions |= DropAction.MOVE.getMask();
+ }
+
+ if ((sourceActions & DnDConstants.ACTION_LINK) > 0) {
+ dropActions |= DropAction.LINK.getMask();
+ }
+
+ return dropActions;
+ }
+
+ private static int getNativeDropAction(DropAction dropAction) {
+ int nativeDropAction = 0;
+
+ if (dropAction != null) {
+ switch(dropAction) {
+ case COPY: {
+ nativeDropAction = DnDConstants.ACTION_COPY;
+ break;
+ }
+
+ case MOVE: {
+ nativeDropAction = DnDConstants.ACTION_MOVE;
+ break;
+ }
+
+ case LINK: {
+ nativeDropAction = DnDConstants.ACTION_LINK;
+ break;
+ }
+ }
+ }
+
+ return nativeDropAction;
+ }
+
+ private static java.awt.Cursor getDropCursor(DropAction dropAction) {
+ // Update the drop cursor
+ java.awt.Cursor cursor = java.awt.Cursor.getDefaultCursor();
+
+ if (dropAction != null) {
+ // Show the cursor for the drop action returned by the
+ // drop target
+ switch (dropAction) {
+ case COPY: {
+ cursor = java.awt.dnd.DragSource.DefaultCopyDrop;
+ break;
+ }
+
+ case MOVE: {
+ cursor = java.awt.dnd.DragSource.DefaultMoveDrop;
+ break;
+ }
+
+ case LINK: {
+ cursor = java.awt.dnd.DragSource.DefaultLinkDrop;
+ break;
+ }
+ }
+ }
+
+ return cursor;
+ }
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Border.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Border.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Border.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Border.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import pivot.collections.Sequence;
+import pivot.util.ListenerList;
+
+/**
+ * Container that displays a border.
+ * <p>
+ * TODO Add styles to support different border styles (e.g. inset, outset) or
+ * create subclasses for these border types.
+ *
+ * @author gbrown
+ */
+public class Border extends Container {
+ private static class BorderListenerList extends ListenerList<BorderListener>
+ implements BorderListener {
+ public void titleChanged(Border border, String previousTitle) {
+ for (BorderListener listener : this) {
+ listener.titleChanged(border, previousTitle);
+ }
+ }
+
+ public void contentChanged(Border border, Component previousContent) {
+ for (BorderListener listener : this) {
+ listener.contentChanged(border, previousContent);
+ }
+ }
+ }
+
+ private String title = null;
+ private Component content = null;
+ private BorderListenerList borderListeners = new BorderListenerList();
+
+ public Border() {
+ this(null);
+ }
+
+ public Border(Component content) {
+ installSkin(Border.class);
+
+ setContent(content);
+ }
+
+ /**
+ * Returns the border's title.
+ *
+ * @return
+ * The border's title, or <tt>null</tt> if no title is set.
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets the border's title.
+ *
+ * @param title
+ * The new title, or <tt>null</tt> for no title.
+ */
+ public void setTitle(String title) {
+ String previousTitle = this.title;
+
+ if (previousTitle != title) {
+ this.title = title;
+ borderListeners.titleChanged(this, previousTitle);
+ }
+ }
+
+ /**
+ * Returns the border's content component.
+ *
+ * @return
+ * The border's content component, or <tt>null</tt> if the border does
+ * not have a content component.
+ */
+ public Component getContent() {
+ return content;
+ }
+
+ /**
+ * Sets the border's content component.
+ *
+ * @param content
+ * The border's content component, or <tt>null</tt> for no content.
+ */
+ public void setContent(Component content) {
+ Component previousContent = this.content;
+
+ if (content != previousContent) {
+ this.content = null;
+
+ // Remove any previous content component
+ if (previousContent != null) {
+ remove(previousContent);
+ }
+
+ // Add the component
+ if (content != null) {
+ add(content);
+ }
+
+ this.content = content;
+
+ borderListeners.contentChanged(this, previousContent);
+ }
+ }
+
+ @Override
+ public Sequence<Component> remove(int index, int count) {
+ for (int i = index, n = index + count; i < n; i++) {
+ Component component = get(i);
+ if (component == content) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // Call the base method to remove the components
+ return super.remove(index, count);
+ }
+
+ public ListenerList<BorderListener> getBorderListeners() {
+ return borderListeners;
+ }
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BorderListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BorderListener.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BorderListener.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BorderListener.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,25 @@
+package pivot.wtk;
+
+/**
+ * Border listener interface.
+ *
+ * @author gbrown
+ *
+ */
+public interface BorderListener {
+ /**
+ * Called when a border's title has changed.
+ *
+ * @param border
+ * @param previousTitle
+ */
+ public void titleChanged(Border border, String previousTitle);
+
+ /**
+ * Called when a border's content component has changed.
+ *
+ * @param border
+ * @param previousContent
+ */
+ public void contentChanged(Border border, Component previousContent);
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Bounds.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Bounds.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Bounds.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/Bounds.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import pivot.collections.Dictionary;
+
+/**
+ * Class representing the bounds of an object.
+ *
+ * @author gbrown
+ */
+public class Bounds {
+ public int x = 0;
+ public int y = 0;
+ public int width = 0;
+ public int height = 0;
+
+ public static final String X_KEY = "x";
+ public static final String Y_KEY = "y";
+ public static final String WIDTH_KEY = "width";
+ public static final String HEIGHT_KEY = "height";
+
+ public Bounds() {
+ }
+
+ public Bounds(Dictionary<String, ?> bounds) {
+ if (bounds == null) {
+ throw new IllegalArgumentException("bounds is null.");
+ }
+
+ if (bounds.containsKey(X_KEY)) {
+ x = (Integer)bounds.get(X_KEY);
+ }
+
+ if (bounds.containsKey(Y_KEY)) {
+ y = (Integer)bounds.get(Y_KEY);
+ }
+
+ if (bounds.containsKey(WIDTH_KEY)) {
+ width = (Integer)bounds.get(WIDTH_KEY);
+ }
+
+ if (bounds.containsKey(HEIGHT_KEY)) {
+ height = (Integer)bounds.get(HEIGHT_KEY);
+ }
+ }
+
+ public Bounds(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public Bounds(Point origin, Dimensions size) {
+ if (origin == null) {
+ throw new IllegalArgumentException("origin is null.");
+ }
+
+ if (size == null) {
+ throw new IllegalArgumentException("size is null.");
+ }
+
+ x = origin.x;
+ y = origin.y;
+ width = size.width;
+ height = size.height;
+ }
+
+ public Bounds(Bounds bounds) {
+ if (bounds == null) {
+ throw new IllegalArgumentException("bounds is null.");
+ }
+
+ x = bounds.x;
+ y = bounds.y;
+ width = bounds.width;
+ height = bounds.height;
+ }
+
+ public Bounds(java.awt.Rectangle rectangle) {
+ if (rectangle == null) {
+ throw new IllegalArgumentException("rectangle is null.");
+ }
+
+ x = rectangle.x;
+ y = rectangle.y;
+ width = rectangle.width;
+ height = rectangle.height;
+ }
+
+ public Point getLocation() {
+ return new Point(x, y);
+ }
+
+ public Dimensions getSize() {
+ return new Dimensions(width, height);
+ }
+
+ public void union(Bounds bounds) {
+ int x1 = Math.min(x, bounds.x);
+ int y1 = Math.min(y, bounds.y);
+ int x2 = Math.max(x + width, bounds.x + bounds.width);
+ int y2 = Math.max(y + height, bounds.y + bounds.height);
+
+ this.x = x1;
+ this.y = y1;
+ this.width = x2 - x1;
+ this.height = y2 - y1;
+ }
+
+ public void intersect(Bounds bounds) {
+ int x1 = Math.max(x, bounds.x);
+ int y1 = Math.max(y, bounds.y);
+ int x2 = Math.min(x + width, bounds.x + bounds.width);
+ int y2 = Math.min(y + height, bounds.y + bounds.height);
+
+ this.x = x1;
+ this.y = y1;
+ this.width = x2 - x1;
+ this.height = y2 - y1;
+ }
+
+ public void translate(int dx, int dy) {
+ this.x += dx;
+ this.y += dy;
+ }
+
+ public boolean contains(Point point) {
+ if (point == null) {
+ throw new IllegalArgumentException("point is null");
+ }
+
+ return contains(point.x, point.y);
+ }
+
+ public boolean contains(int x, int y) {
+ return (x >= this.x
+ && y >= this.y
+ && x < this.x + width
+ && y < this.y + height);
+ }
+
+ public boolean contains(Bounds bounds) {
+ if (bounds == null) {
+ throw new IllegalArgumentException("bounds is null");
+ }
+
+ return contains(bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+
+ public boolean contains(int x, int y, int width, int height) {
+ return (!isEmpty()
+ && x >= this.x
+ && y >= this.y
+ && x + width <= this.x + this.width
+ && y + height <= this.y + this.height);
+ }
+
+ public boolean intersects(Bounds bounds) {
+ if (bounds == null) {
+ throw new IllegalArgumentException("bounds is null");
+ }
+
+ return intersects(bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+
+ public boolean intersects(int x, int y, int width, int height) {
+ return (!isEmpty()
+ && x + width > this.x
+ && y + height > this.y
+ && x < this.x + this.width
+ && y < this.y + this.height);
+ }
+
+ public boolean isEmpty() {
+ return (width <= 0
+ || height <= 0);
+ }
+
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof Bounds) {
+ Bounds bounds = (Bounds)object;
+ equals = (x == bounds.x
+ && y == bounds.y
+ && width == bounds.width
+ && height == bounds.height);
+ }
+
+ return equals;
+ }
+
+ public java.awt.Rectangle toRectangle() {
+ return new java.awt.Rectangle(x, y, width, height);
+ }
+
+ public String toString() {
+ return getClass().getName() + " [" + x + "," + y + ";" + width + "x" + height + "]";
+ }
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BrowserApplicationContext.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BrowserApplicationContext.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BrowserApplicationContext.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/BrowserApplicationContext.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import java.applet.Applet;
+import java.awt.Graphics;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLDecoder;
+
+import netscape.javascript.JSObject;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
+import pivot.collections.HashMap;
+
+/**
+ * Application context used to execute applications in a web browser.
+ *
+ * @author gbrown
+ */
+@SuppressWarnings("deprecation")
+public final class BrowserApplicationContext extends ApplicationContext {
+ /**
+ * Applet used to host applications in a web browser.
+ *
+ * @author gbrown
+ */
+ public static final class HostApplet extends Applet {
+ private class PropertyDictionary implements Dictionary<String, String> {
+ public String get(String key) {
+ String value = properties.containsKey(key) ?
+ properties.get(key) : getParameter(key);
+ return value;
+ }
+
+ public String put(String key, String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String remove(String key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean containsKey(String key) {
+ return properties.containsKey(key)
+ || getParameter(key) != null;
+ }
+
+ public boolean isEmpty() {
+ return properties.isEmpty();
+ }
+ }
+
+ private class InitCallback implements Runnable {
+ public void run() {
+ // Set the origin
+ URL codeBase = getCodeBase();
+ if (codeBase != null) {
+ try {
+ origin = new URL(codeBase.getProtocol(), codeBase.getHost(),
+ codeBase.getPort(), "");
+ } catch(Exception exception) {
+ System.out.print("Unable to determine application origin: "
+ + exception);
+ }
+ }
+
+ // Create the application context
+ applicationContext = new BrowserApplicationContext();
+
+ // Load properties specified on the query string
+ properties = new HashMap<String, String>();
+
+ URL documentBase = getDocumentBase();
+ if (documentBase != null) {
+ String queryString = documentBase.getQuery();
+ if (queryString != null) {
+ String[] arguments = queryString.split("&");
+
+ for (int i = 0, n = arguments.length; i < n; i++) {
+ String argument = arguments[i];
+ String[] property = argument.split("=");
+
+ if (property.length == 2) {
+ String key, value;
+ try {
+ final String encoding = "UTF-8";
+ key = URLDecoder.decode(property[0], encoding);
+ value = URLDecoder.decode(property[1], encoding);
+ properties.put(key, value);
+ } catch(UnsupportedEncodingException exception) {
+ }
+ } else {
+ System.err.println(argument + " is not a valid startup property.");
+ }
+ }
+ }
+ }
+
+ // Add the display host to the applet
+ DisplayHost displayHost = applicationContext.getDisplayHost();
+ setLayout(new java.awt.BorderLayout());
+ add(displayHost);
+
+ // Disable focus traversal keys
+ setFocusTraversalKeysEnabled(false);
+
+ // Clear the background
+ setBackground(null);
+
+ // Load the application
+ String applicationClassName = getParameter(APPLICATION_CLASS_NAME_PARAMETER);
+ if (applicationClassName == null) {
+ Alert.alert(MessageType.ERROR, "Application class name is required.",
+ applicationContext.getDisplay());
+ } else {
+ try {
+ Class<?> applicationClass = Class.forName(applicationClassName);
+ application = (Application)applicationClass.newInstance();
+ } catch(Exception exception) {
+ Alert.alert(MessageType.ERROR, exception.getMessage(),
+ applicationContext.getDisplay());
+ exception.printStackTrace();
+ }
+ }
+
+ if (hostApplets.getLength() == 0) {
+ createTimer();
+ }
+
+ hostApplets.add(HostApplet.this);
+ }
+ }
+
+ private class StartCallback implements Runnable {
+ public void run() {
+ // Set focus to the display host
+ DisplayHost displayHost = applicationContext.getDisplayHost();
+ displayHost.requestFocus();
+
+ if (application != null) {
+ try {
+ application.startup(applicationContext.getDisplay(), propertyDictionary);
+ } catch(Exception exception) {
+ Alert.alert(MessageType.ERROR, exception.getMessage(),
+ applicationContext.getDisplay());
+ exception.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private class StopCallback implements Runnable {
+ public void run() {
+ try {
+ application.shutdown(false);
+ } catch(Exception exception) {
+ Alert.alert(MessageType.ERROR, exception.getMessage(),
+ applicationContext.getDisplay());
+ exception.printStackTrace();
+ }
+ }
+ }
+
+ private class DestroyCallback implements Runnable {
+ public void run() {
+ hostApplets.remove(HostApplet.this);
+
+ if (hostApplets.getLength() == 0) {
+ destroyTimer();
+ }
+ }
+ }
+
+ private BrowserApplicationContext applicationContext = null;
+ private HashMap<String, String> properties = null;
+ private PropertyDictionary propertyDictionary = new PropertyDictionary();
+ private Application application = null;
+
+ public static final String APPLICATION_CLASS_NAME_PARAMETER = "applicationClassName";
+
+ private static final long serialVersionUID = 0;
+
+ public Application getApplication() {
+ return application;
+ }
+
+ @Override
+ public void init() {
+ InitCallback initCallback = new InitCallback();
+
+ if (java.awt.EventQueue.isDispatchThread()) {
+ initCallback.run();
+ } else {
+ queueCallback(initCallback, true);
+ }
+ }
+
+ @Override
+ public void start() {
+ StartCallback startCallback = new StartCallback();
+
+ if (java.awt.EventQueue.isDispatchThread()) {
+ startCallback.run();
+ } else {
+ queueCallback(startCallback, true);
+ }
+ }
+
+ @Override
+ public void stop() {
+ StopCallback stopCallback = new StopCallback();
+
+ if (java.awt.EventQueue.isDispatchThread()) {
+ stopCallback.run();
+ } else {
+ queueCallback(stopCallback, true);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ DestroyCallback destroyCallback = new DestroyCallback();
+
+ if (java.awt.EventQueue.isDispatchThread()) {
+ destroyCallback.run();
+ } else {
+ queueCallback(destroyCallback, true);
+ }
+ }
+
+ @Override
+ public void update(Graphics graphics) {
+ paint(graphics);
+ }
+ }
+
+ private static ArrayList<HostApplet> hostApplets = new ArrayList<HostApplet>();
+
+ /**
+ * Retrieves a named application.
+ *
+ * @param name
+ * The name of the applet hosting the application.
+ */
+ public static Application getApplication(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name is null.");
+ }
+
+ Application application = null;
+ for (HostApplet hostApplet : hostApplets) {
+ if (hostApplet.getName().equals(name)) {
+ application = hostApplet.getApplication();
+ break;
+ }
+ }
+
+ return application;
+ }
+
+ /**
+ * Evaluates a script in the page context and returns the result.
+ *
+ * @param script
+ * @param application
+ */
+ public static Object eval(String script, Application application) {
+ if (application == null) {
+ throw new IllegalArgumentException("application is null.");
+ }
+
+ HostApplet applicationHostApplet = null;
+ for (HostApplet hostApplet : hostApplets) {
+ if (hostApplet.getApplication() == application) {
+ applicationHostApplet = hostApplet;
+ break;
+ }
+ }
+
+ if (applicationHostApplet == null) {
+ throw new IllegalArgumentException("No applet is hosting the given application.");
+ }
+
+ try {
+ JSObject window = JSObject.getWindow(applicationHostApplet);
+ return window.eval(script);
+ } catch (Throwable throwable) {
+ throw new UnsupportedOperationException(throwable);
+ }
+ }
+}