Package org.jcsp.awt

# Class ActiveCanvas

java.lang.Object
java.awt.Component
java.awt.Canvas
org.jcsp.awt.ActiveCanvas

All Implemented Interfaces:
  `ImageObserver`, `MenuContainer`, `Serializable`, `Accessible`, `CSProcess`

public class ActiveCanvas extends Canvas implements CSProcess
``java.awt.Canvas`` with a channel interface.

## Process Diagram

## Description

`ActiveCanvas` is a process extension of `java.awt.Canvas` with channels for run-time configuration/interrogation and event notification. The event channels should be connected to one or more application-specific server. processes (instead of registering a passive object as a Listener to this component).

All channels are optional. The `toGraphics`/`fromGraphics` channels are set by calling the ``setGraphicsChannels`` method. Event channels can be added to notify the occurrence of any type of `Event` the component generates by calling the appropriate `add` XXX `EventChannel` method. All channel connections must be made before the process is run.

Messages can be sent down the `toGraphics` channel at any time to configure or interrogate the component. A reply or acknowledgment is returned down the `fromGraphics` channel and must be read. See the table below and `GraphicsProtocol` for details.

Graphics operations on an `ActiveCanvas` are most conveniently managed by attaching, and then setting `GraphicsCommand`s on, a `DisplayList` (or any user-defined object implementing the `Paintable` interface). This can be done either statically via the `setPaintable` method, or dynamically via the ``toGraphics`/`fromGraphics`` channels (see `GraphicsProtocol.SetPaintable`).

All channels are managed by independent internal handler processes. It is, therefore, safe for a serial application process both to service an event channel and configure the component -- no deadlock can occur.

IMPORTANT: it is essential that event channels from this process are always serviced -- otherwise the Java Event Thread will be blocked and the GUI will stop responding. A simple way to guarantee this is to use channels configured with overwriting buffers. For example:

       final One2OneChannel myMouseEvent = Channel.one2one (new OverWriteOldestBuffer (n));

       final ActiveCanvas myCanvas = new ActiveCanvas ();
       myCanvas.addMouseEventChannel (myMouseEvent.out ());

This will ensure that the Java Event Thread will never be blocked. Slow or inattentive readers may miss rapidly generated events, but the `n` most recent events will always be available.

## Channel Protocols

Input Channels
displayList | GraphicsCommand[] | See `DisplayList` and `GraphicsCommand`.
toGraphics | GraphicsProtocol | See `GraphicsProtocol`.
Output Channels
fromGraphics | Object | Response to the `fromGraphics` message. See the documentation on `GraphicsProtocol`.
componentEvent | ComponentEvent | See the ``addComponentEventChannel`` method.
focusEvent | FocusEvent | See the ``addFocusEventChannel`` method.
keyEvent | KeyEvent | See the ``addKeyEventChannel`` method.
mouseEvent | MouseEvent | See the ``addMouseEventChannel`` method.
mouseMotionEvent | MouseEvent | See the ``addMouseMotionEventChannel`` method.

## Example

     import java.awt.*;
     import java.awt.event.*;
     import org.jcsp.lang.*;
     import org.jcsp.util.*;
     import org.jcsp.awt.*;

     public class ActiveCanvasExample {

       public static void main (String argv[]) {

         final ActiveClosingFrame activeClosingFrame =
           new ActiveClosingFrame ("ActiveCanvas Example");
         final Frame frame = activeClosingFrame.getActiveFrame ();

         final One2OneChannel mouseEvent = Channel.one2one (new OverWriteOldestBuffer (10));

         final DisplayList displayList = new DisplayList ();

         final ActiveCanvas canvas = new ActiveCanvas ();
         canvas.addMouseEventChannel (mouseEvent.out ());
         canvas.setPaintable (displayList);
         canvas.setSize (600, 400);

         frame.add (canvas);
         frame.pack ();
         frame.setVisible (true);

         new Parallel (
           new CSProcess[] {
             activeClosingFrame,
             canvas,
             new CSProcess () {
               public void run () {
                 final String clickMessage = "D O U B L E - C L I C K   T H E   M O U S E   T O   E X I T";
                 final String clickPlea = "       P L E A S E   M O V E   T H E   M O U S E   B A C K    ";
                 final GraphicsCommand[] mouseEntered =
                   {new GraphicsCommand.SetColor (Color.cyan),
                    new GraphicsCommand.FillRect (0, 0, 600, 400),
                    new GraphicsCommand.SetColor (Color.black),
                    new GraphicsCommand.DrawString (clickMessage, 140, 200)};
                 final GraphicsCommand[] mouseExited =
                   {new GraphicsCommand.SetColor (Color.pink),
                    new GraphicsCommand.FillRect (0, 0, 600, 400),
                    new GraphicsCommand.SetColor (Color.black),
                    new GraphicsCommand.DrawString (clickPlea, 140, 200)};
                 final GraphicsCommand mousePressed =
                   new GraphicsCommand.DrawString (clickMessage, 160, 220);
                 final GraphicsCommand mouseReleased =
                   new GraphicsCommand.DrawString (clickMessage, 140, 200);
                 displayList.set (mouseExited);
                 boolean running = true;
                 while (running) {
                   final MouseEvent event = (MouseEvent) mouseEvent.in ().read ();
                   switch (event.getID ()) {
                     case MouseEvent.MOUSE_ENTERED:
                       System.out.println ("MOUSE_ENTERED");
                       displayList.set (mouseEntered);
                     break;
                     case MouseEvent.MOUSE_EXITED:
                       System.out.println ("MOUSE_EXITED");
                       displayList.set (mouseExited);
                     break;
                     case MouseEvent.MOUSE_PRESSED:
                       System.out.println ("MOUSE_PRESSED");
                       displayList.change (mousePressed, 3);
                     break;
                     case MouseEvent.MOUSE_RELEASED:
                       System.out.println ("MOUSE_RELEASED");
                       displayList.change (mouseReleased, 3);
                     break;
                     case MouseEvent.MOUSE_CLICKED:
                       if (event.getClickCount() > 1) {
                         System.out.println ("MOUSE_DOUBLE_CLICKED ... goodbye!");
                         running = false;
                       }
                     break;
                   }
                 }
                 frame.setVisible (false);
                 System.exit (0);
               }
             }
           }
         ).run ();
       }

     }

Author:
  P.D. Austin and P.H. Welch
See Also:
  - `DisplayList`
  - `Display`
  - `GraphicsCommand`
  - `Paintable`
  - `GraphicsProtocol`
  - `OverWriteOldestBuffer`
  - `Canvas`
  - `ComponentEvent`
  - `FocusEvent`
  - `KeyEvent`
  - `MouseEvent`
  - Serialized Form

## Nested Class Summary

## Nested classes/interfaces inherited from class java.awt.Canvas

`Canvas.AccessibleAWTCanvas`

## Nested classes/interfaces inherited from class java.awt.Component

`Component.AccessibleAWTComponent, Component.BaselineResizeBehavior, Component.BltBufferStrategy, Component.FlipBufferStrategy`

## Field Summary

### Fields inherited from class java.awt.Component

`accessibleContext, BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENT`

### Fields inherited from interface java.awt.image.ImageObserver

`ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH`

## Constructor Summary

Constructors
Constructor
Description
`ActiveCanvas()`

## Method Summary

Modifier and Type
Method
Description
`void`
`addComponentEventChannel(ChannelOutput componentEvent)`
Add a new channel to this component that will be used to notify that a `ComponentEvent` has occurred.
`void`
`addFocusEventChannel(ChannelOutput focusEvent)`
Add a new channel to this component that will be used to notify that a `FocusEvent` has occurred.
`void`
`addKeyEventChannel(ChannelOutput keyEvent)`
Add a new channel to this component that will be used to notify that a `KeyEvent` has occurred.
`void`
`addMouseEventChannel(ChannelOutput mouseEvent)`
Add a new channel to this component that will be used to notify that a `MouseEvent` has occurred.
`void`
`addMouseMotionEventChannel(ChannelOutput mouseMotionEvent)`
Add a new channel to this component that will be used to notify that a `MouseMotionEvent` has occurred.
`Dimension`
`getMinimumSize()`
This method is used by system classes -- it is not really for public consumption!
`Dimension`
`getPreferredSize()`
This method is used by system classes -- it is not really for public consumption!
`void`
`paint(Graphics g)`
This method is used by the JVM event thread -- it is not really for public consumption.
`void`
`run()`
The main body of this process.
`void`
`setGraphicsChannels(ChannelInput toGraphics, ChannelOutput fromGraphics)`
Set the `toGraphics`/`fromGraphics` channels for configuring and/or examining this component.
`void`
`setPaintable(Paintable paintable)`
Set the ``Paintable`` object that will be used by the `paint` and `update` methods of this canvas.
`void`
`setSize(int requestedWidth, int requestedHeight)`
Request that the canvas takes the size given by the parameters.
`void`
`update(Graphics g)`
This method is used by the JVM event thread -- it is not really for public consumption.

### Methods inherited from class java.awt.Canvas

`addNotify, createBufferStrategy, createBufferStrategy, getAccessibleContext, getBufferStrategy`

### Methods inherited from class java.awt.Component

`action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent, doLayout, enable, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getAlignmentX, getAlignmentY, getBackground, getBaseline, getBaselineResizeBehavior, getBounds, getBounds, getColorModel, getComponentAt, getComponentAt, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeys, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getListeners, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusCycleRoot, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isOpaque, isPreferredSizeSet, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, paramString, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, processComponentEvent, processEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removeNotify, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, requestFocus, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, requestFocusInWindow, reshape, resize, resize, revalidate, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeys, setFocusTraversalKeysEnabled, setFont, setForeground, setIgnoreRepaint, setLocale, setLocation, setLocation, setMaximumSize, setMinimumSize, setMixingCutoutShape, setName, setPreferredSize, setSize, setVisible, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle, validate`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

## Constructor Details

### ActiveCanvas

public ActiveCanvas()

## Method Details

### setGraphicsChannels

public void setGraphicsChannels(ChannelInput toGraphics, ChannelOutput fromGraphics)
Set the `toGraphics`/`fromGraphics` channels for configuring and/or examining this component. A ``org.jcsp.awt.GraphicsProtocol`` object sent down the `toGraphics` channel generates the appropriate configuration or enquiry action. A reply object is always returned down the `fromGraphics` channel.

NOTE: This method must be called before this process is run.

Parameters:
  `toGraphics` - the channel down which GraphicsProtocol objects are sent.
  `fromGraphics` - the reply/acknowledgement channel responding to the GraphicsProtocol object.

### setPaintable

public void setPaintable(Paintable paintable)
Set the ``Paintable`` object that will be used by the `paint` and `update` methods of this canvas. If `paintable` is null, the `paint`/`update` methods will not be overriden.

JCSP provides a `DisplayList` as an example `Paintable` class. This can be thought of as a special form of channel. A user process at the other end writes to it by setting up and/or editing an ordered list of `GraphicsCommand`s. This method may be used to connect the `DisplayList` to this `ActiveCanvas`. For example:

       final ActiveCanvas myActiveCanvas = new ActiveCanvas ();

       final DisplayList draw = new DisplayList ();
       myActiveCanvas.setPaintable (draw);

       ...  connect other channels (toGraphics, fromGraphics, mouseEvent, etc.)

       // myActiveCanvas is now ready to run

NOTE: If `setPaintable` is going to be invoked, this must happen before this process is run.

Alternatively, the ``Paintable`` object may be set dynamically by sending an appropriate `GraphicsProtocol.SetPaintable` object down the `toGraphics` channel.

Parameters:
  `paintable` - the object to be used for painting/updating the canvas.

### paint

public void paint(Graphics g)
This method is used by the JVM event thread -- it is not really for public consumption. If `setPaintable` has been invoked on this canvas or a `GraphicsProtocol.SetPaintable` object has been sent down the `toGraphics` channel, this method uses the supplied ``Paintable`` object to do the painting.

Overrides:
  `paint` in class `Canvas`

### update

public void update(Graphics g)
This method is used by the JVM event thread -- it is not really for public consumption. If `setPaintable` has been invoked on this canvas or a `GraphicsProtocol.SetPaintable` object has been sent down the `toGraphics` channel, this method uses the supplied ``Paintable`` object to do the updating.

Overrides:
  `update` in class `Canvas`

### addComponentEventChannel

public void addComponentEventChannel(ChannelOutput componentEvent)
Add a new channel to this component that will be used to notify that a `ComponentEvent` has occurred. This should be used instead of registering a ComponentListener with the component. It is possible to add more than one Channel by calling this method multiple times If the channel passed is `null`, no action will be taken.

NOTE: This method must be called before this process is run.

Parameters:
  `componentEvent` - the channel down which to send ComponentEvents.

### addFocusEventChannel

public void addFocusEventChannel(ChannelOutput focusEvent)
Add a new channel to this component that will be used to notify that a `FocusEvent` has occurred. This should be used instead of registering a FocusListener with the component. It is possible to add more than one Channel by calling this method multiple times If the channel passed is `null`, no action will be taken.

NOTE: This method must be called before this process is run.

Parameters:
  `focusEvent` - the channel down which to send FocusEvents.

### addKeyEventChannel

public void addKeyEventChannel(ChannelOutput keyEvent)
Add a new channel to this component that will be used to notify that a `KeyEvent` has occurred. This should be used instead of registering a KeyListener with the component. It is possible to add more than one Channel by calling this method multiple times If the channel passed is `null`, no action will be taken.

NOTE: This method must be called before this process is run.

Parameters:
  `keyEvent` - the channel down which to send KeyEvents.

### addMouseEventChannel

public void addMouseEventChannel(ChannelOutput mouseEvent)
Add a new channel to this component that will be used to notify that a `MouseEvent` has occurred. This should be used instead of registering a MouseListener with the component. It is possible to add more than one Channel by calling this method multiple times If the channel passed is `null`, no action will be taken.

NOTE: This method must be called before this process is run.

Parameters:
  `mouseEvent` - the channel down which to send MouseEvents.

### addMouseMotionEventChannel

public void addMouseMotionEventChannel(ChannelOutput mouseMotionEvent)
Add a new channel to this component that will be used to notify that a `MouseMotionEvent` has occurred. This should be used instead of registering a MouseMotionListener with the component. It is possible to add more than one Channel by calling this method multiple times If the channel passed is `null`, no action will be taken.

NOTE: This method must be called before this process is run.

Parameters:
  `mouseMotionEvent` - the channel down which to send MouseMotionEvents.

### setSize

public void setSize(int requestedWidth, int requestedHeight)
Request that the canvas takes the size given by the parameters. The methods ``getPreferredSize`` and ``getMinimumSize`` are overridden to return these dimensions.

NOTE: This method must be called before this process is run.

Overrides:
  `setSize` in class `Component`
Parameters:
  `requestedWidth` - the requested width for the canvas.
  `requestedHeight` - the requested height for the canvas.

### getPreferredSize

public Dimension getPreferredSize()
This method is used by system classes -- it is not really for public consumption!

Overrides:
  `getPreferredSize` in class `Component`

### getMinimumSize

public Dimension getMinimumSize()
This method is used by system classes -- it is not really for public consumption!

Overrides:
  `getMinimumSize` in class `Component`

### run

public void run()
The main body of this process.

Specified by:
  `run` in interface `CSProcess`