home *** CD-ROM | disk | FTP | other *** search
Java Source | 1995-05-15 | 14.5 KB | 614 lines |
- /*
- * @(#)DisplayItemWindow.java 1.43 95/04/10 Jonathan Payne
- *
- * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL purposes and without
- * fee is hereby granted provided that this copyright notice
- * appears in all copies. Please refer to the file "copyright.html"
- * for further important copyright and licensing information.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- */
-
- package awt;
-
- import java.util.*;
-
- /**
- * DisplayItemWindow is a subclass of Window that can display embedded
- * DisplayItem's. This task involves mainly distributing input to the
- * right DisplayItem and causing the appropriate items to be displayed
- * in response to damage or scrolling events.
- * @version 1.43 10 Apr 1995
- * @author Jonathan Payne
- */
- public class DisplayItemWindow extends Window {
- DIWUpdaterThread updater = null;
- Vector nativeItems;
- Scrollbar sb = null;
- DisplayItem items[] = new DisplayItem[0];
- int used = 0;
- protected int logicalWidth;
- protected int logicalHeight;
- protected DisplayItem currentInputItem;
- protected boolean stickyTracking = true;
- Event tEvent = new Event(); /* translated event */
- protected boolean valid = false;
- protected int scrollX;
- protected int scrollY;
- public FocusManager fm = new FocusManager(this);
-
- /** Creates a DisplayItemWindow that is contained inside a Frame. */
- public DisplayItemWindow(Frame f, String name) {
- super(f,name, Color.lightGray, 600,600);
- nativeItems = new Vector();
- setLayout(null);
- }
-
- /** Creates a DisplayItemWindow that is contained inside a Window */
- public DisplayItemWindow(Window parent, String client) {
- super(parent, client, Color.lightGray, 150, 150);
- setMargin(2);
- nativeItems = new Vector();
- setLayout(null);
- }
-
- /** Set the scrollbar for this DisplayItemWindow to s */
- public void setScrollbar(Scrollbar s) {
- sb = s;
- invalidate();
- }
-
- /** Indicates that this DisplayItemWindow needs updating. */
- public void invalidate() {
- valid = false;
- }
-
- /** Updates the scrollbar to reflect the current size of the
- * window.
- */
- public void updateScrollbar() {
- if (sb != null && height > 0 && logicalHeight > 0) {
- sb.setValues(-scrollY, height, 0, logicalHeight);
- }
- }
-
- /** Marks this window as valid (not in need of repainting) */
- public void validate() {
- updateScrollbar();
- valid = true;
- }
-
- public synchronized void handleExpose(int x, int y, int w, int h) {
- graphics.clipRect(x, y, w, h);
- // graphics.setForeground(Color.red);
- // graphics.fillRect(x, y, w, h);
- // update();
- // System.out.println("Expose: " + x + ", " + y + ", " + w + ", " + h);
- // Thread.sleep(500);
- paintRange(y, y + h);
- graphics.clearClip();
- }
-
- /** Called in response to a resize action by the user. Redoes the
- * window layout and marks the window as invalid.
- */
- public void handleResize() {
- if (theLayout != null)
- theLayout.layout(this);
- invalidate();
- }
-
-
- /** Adds an named DisplayItem to the window. */
- public synchronized void addItem(DisplayItem di, String name) {
- if (name != null) {
- addChild(di, name);
- }
- addItem(di);
- }
-
-
- /** Adds an unnamed DisplayItem to the window. */
- public synchronized void addItem(DisplayItem di) {
- di.setParent(this);
- if (di instanceof NativeDisplayItem) {
- addNativeItem((NativeDisplayItem)di);
- }
- if (used == items.length) {
- int amt = (used == 0) ? 40 : (int)(used * 1.5);
-
- DisplayItem newItems[] = new DisplayItem[amt];
- System.arraycopy(items, 0, newItems, 0, items.length);
- items = newItems;
- }
- items[used++] = di;
- invalidate();
- }
-
- /** Returns the array of items in this window. */
- public DisplayItem getItems()[] {
- return items;
- }
-
- /** Adds a DisplayItem that is a subclass of NativeDisplayItem.
- * This method is needed because DisplayItem's that are native
- * gui components require special treatment.
- * @see awt.NativeDisplayItem
- */
- protected synchronized void addNativeItem(NativeDisplayItem di) {
- int i = nativeItems.size();
-
- while (--i >= 0) {
- if ((NativeDisplayItem)nativeItems.elementAt(i) == di) {
- break;
- }
- }
- if (i < 0) {
- nativeItems.addElement(di);
- }
- }
-
- /**
- * Clears the list of native display items.
- */
- protected synchronized void clearNativeItems() {
- nativeItems.removeAllElements();
- }
-
-
- /**
- * Notifies this window that the dimensions of a DisplayItem have
- * changed.
- */
- void childChanged(DisplayItem child) {
- // if (logicalWidth < child.x + child.width) {
- // logicalWidth = child.x + child.width;
- // }
- // if (logicalHeight < child.y + child.height) {
- // logicalHeight = child.y + child.height;
- // }
- }
-
- /**
- * Returns the item at the given index.
- */
- public DisplayItem nthItem(int n) {
- if (n >= used) {
- throw new ArrayIndexOutOfBoundsException(n + " >= " + used);
- }
- return items[n];
- }
-
- /**
- * Clears the list of DisplayItems for this window. The deactivate
- * method is called on each item before being removed from the list.
- *
- * @see awt.DisplayItem#deactivate
- */
- public synchronized void clearItems() {
- stopUpdater();
- currentInputItem = null;
- for (int i = used; --i >= 0; ) {
- items[i].deactivate();
- items[i] = null;
- }
- clearNativeItems();
- used = 0;
- items = new DisplayItem[0];
- logicalWidth = logicalHeight = 0;
- invalidate();
- startUpdater();
- }
-
- /**
- * Returns the number of DisplayItem's contained in this window.
- */
- public int count() {
- return used;
- }
-
- /**
- * Paints all of the DisplayItems contained between y0 and y1.
- */
- synchronized void paintRange(int y0, int y1) {
- if (y1 < 0 || y0 > height)
- return;
-
- setForeground(background);
- fillRect(0, y0, width, y1 - y0);
- y0 -= scrollY;
- y1 -= scrollY;
-
- int cnt = count();
- int i = 0;
-
- while (--cnt >= 0) {
- DisplayItem di = items[i++];
-
- if (di.y + di.height < y0 || di.y > y1) {
- continue;
- }
- di.paint(this, di.x + scrollX, di.y + scrollY);
- }
- update();
- }
-
- public void setScrolling(int x, int y) {
- scrollX = x;
- scrollY = y;
- }
-
- /** Paints all of the DisplayItems in this window. */
- public void paint() {
- if (!valid)
- validate();
- paintRange(0, height);
- }
-
-
- /** Starts the child updater thread responsible for causing
- * repaints.
- */
- synchronized void startUpdater() {
- if (updater == null) {
- updater = new DIWUpdaterThread(this);
- updater.start();
- }
- }
-
- /** Kill updater in its tracks, because we are doing something
- which could cause the updater to display a display item that
- is no longer in this window! Stopping it in its tracks takes
- care of that race condition. */
- synchronized void stopUpdater() {
- if (updater != null) {
- updater.die();
- updater = null;
- }
- }
-
- /** Shows this window. */
- public void map() {
- super.map();
- startUpdater();
- }
-
- /** Hides this window. */
- public void unMap() {
- super.unMap();
- stopUpdater();
- }
-
- /** Requests that the given DisplayItem be repainted. */
- public void paintChild(DisplayItem di, boolean clear) {
- if (updater != null) {
- updater.addRequest(di, clear);
- }
- }
-
- /** Updates the given DisplayItem. */
- public void updateChild(DisplayItem di, boolean clear) {
- int x, y;
-
- x = di.x + scrollX;
- y = di.y + scrollY;
- if (y + di.height < 0 || y > height) {
- return;
- }
- if (clear) {
- clearRect(x, y, di.width + 1, di.height + 1);
- di.paint(this, x, y);
- } else {
- di.update(this, x, y);
- }
- update();
- }
-
- public void addUpdateRequest(DIWUpdateRequest r) {
- if (updater != null) {
- updater.addRequest(r);
- }
- }
-
- /** Returns the DisplayItem which contains x,y. */
- public synchronized DisplayItem locateItem(int x, int y) {
- int i = count();
-
- x -= scrollX;
- y -= scrollY;
- while (--i >= 0) {
- DisplayItem di = items[i];
-
- if (di.containsPoint(x, y)) {
- return di;
- }
- }
- return null;
- }
-
-
- /** Translates the given event to correspond to the given
- * DisplayItem's coordinate system.
- */
- Event translate(Event e, DisplayItem di) {
- tEvent.copy(e);
- tEvent.x = e.x - (di.x + scrollX);
- tEvent.y = e.y - (di.y + scrollY);
-
- return tEvent;
- }
-
- /**
- * Forwards a mouseDown event to the DisplayItem that contains the
- * current mouse coordinates.
- */
- public void mouseDown(Event e) {
- currentInputItem = locateItem(e.x, e.y);
- if (currentInputItem != null) {
- currentInputItem.trackStart(translate(e, currentInputItem));
- }
- }
-
- /**
- * Forwards a mouse drag event to the DisplayItem that contains the
- * current mouse coordinates.
- */
- public void mouseDrag(Event e) {
- DisplayItem di;
-
- if (stickyTracking)
- di = currentInputItem;
- else {
- di = locateItem(e.x, e.y);
-
- if (di != currentInputItem) {
- if (currentInputItem != null) {
- currentInputItem.trackExit(translate(e, currentInputItem));
- }
- currentInputItem = di;
- if (di != null) {
- di.trackEnter(translate(e, di));
- }
- }
- }
- if (di != null) {
- di.trackMotion(translate(e, di));
- }
- }
-
- /** Forwards a mouse motion event to the DisplayItem that contains the
- * current mouse coordinates.
- */
- public void mouseMoved(Event e) {
- mouseDrag(e);
- }
-
- public void mouseUp(Event e) {
- if (currentInputItem != null) {
- currentInputItem.trackStop(translate(e, currentInputItem));
- }
- currentInputItem = null;
- }
-
- public void setSticky(boolean on) {
- stickyTracking = on;
- }
-
- public int getScrollY() {
- return scrollY;
- }
-
- public void scrollAbsolute(int x, int y) {
- if (y != -scrollY) {
- scrollVertically(-scrollY - y);
- }
- }
-
- /* Scrolling support. */
-
- synchronized public boolean scrollHorizontally(int dx) {
- return true;
- }
-
- synchronized public boolean scrollVertically(int dy) {
- int sy = scrollY;
- boolean hitLimit = false;
-
- if ((-sy - dy) > (logicalHeight - height)) {
- dy = -logicalHeight + height - sy;
- hitLimit = true;
- }
- scrollY += dy;
- if (scrollY > 0) {
- scrollY = 0;
- hitLimit = true;
- }
- updateScrollbar();
- if ((dy = sy - scrollY) != 0) {
- scrollWindow(0, dy);
- // paintRange(top, bottom);
- }
- return hitLimit;
- }
-
- /* Scrollbarable implementation */
-
- int lineScrollY = 20;
-
- public void lineUp() {
- scrollVertically(lineScrollY);
- }
-
- public void lineDown() {
- scrollVertically(-lineScrollY);
- }
-
- public void pageUp() {
- scrollVertically(height);
- }
-
- public void pageDown() {
- scrollVertically(-height);
- }
-
- public void dragAbsolute(int value) {
- scrollVertically(-scrollY - value);
- }
-
- SmoothScroller scroller = null;
-
- void thrust(boolean forward) {
- if (scroller == null) {
- scroller = new SmoothScroller(this);
- Thread.currentThread().yield();
- }
- scroller.setThrust(forward ? 2000 : -2000, 50);
- }
-
- public void keyPressed(Event event) {
-
- //System.out.println("DisplayItemWindow.keyPressed: event.key is " +
- //event.key + ", keyIsAscii is " + event.keyIsAscii);
-
- // If event.keyIsAscii is FALSE, that means this is
- // a modifier key, like leftshift or rightshift or ctrl.
- // We might need to keep track of *some* state here
- // eventually, but for now ignore these events.
- // NOTE we'll need to manually keep track of the SHIFT state
- // here if we want to be able to tell TAB and shift-TAB apart!
- if (!event.keyIsAscii)
- return;
-
- switch (event.key) {
- // Intercept keyboard-focus changing keys:
-
- case '\t': // TAB
- fm.nextFocus();
- break;
- // Also need two more cases, but we'll have to use a smarter input
- // model to identify these!
- // case 'YOW': // Shift-TAB
- // fm.prevFocus();
- // break;
- // case 'YOW': // HOME
- // fm.resetFocus();
- // break;
-
- // Anything else is a key we want to pass through to
- // whoever has the input focus:
- default:
- DisplayItem fitem = fm.currentFocusItem();
- if (fitem != null) {
- fitem.keyPressed(event.key);
- }
- break;
- }
- }
- }
-
- class DisplayItemUpdateRequest extends DIWUpdateRequest {
- DisplayItem di;
-
- DisplayItemUpdateRequest(DisplayItem di, boolean clear) {
- this.di = di;
- this.clear = clear;
- }
-
- void execute(DisplayItemWindow w) {
- w.updateChild(di, clear);
- }
- public boolean equals(Object obj) {
- if ((obj != null) && (obj instanceof DisplayItemUpdateRequest)) {
- return ((DisplayItemUpdateRequest)obj).di == di;
- }
- return false;
- }
- }
-
- class DIWUpdaterThread extends Thread {
- DisplayItemWindow diw;
- Vector clients = new Vector();
-
- DIWUpdaterThread(DisplayItemWindow diw) {
- setPriority(NORM_PRIORITY - 1);
- this.diw = diw;
- }
-
- public synchronized void addRequest(DIWUpdateRequest r) {
- int i = clients.indexOf(r);
- if (i < 0) {
- clients.addElement(r);
- notify();
- } else {
- DIWUpdateRequest r2 = (DIWUpdateRequest)clients.elementAt(i);
- if (r.clear && !r2.clear) {
- r2.clear = true;
- }
- }
- }
-
- public void addRequest(DisplayItem di, boolean clear) {
- addRequest(new DisplayItemUpdateRequest(di, clear));
- }
-
- synchronized DIWUpdateRequest getRequest() {
- while (clients.size() == 0 && !stop) {
- wait();
- }
-
- DIWUpdateRequest r = null;
-
- if (!stop) {
- r = (DIWUpdateRequest) clients.elementAt(0);
- clients.removeElementAt(0);
- }
- return r;
- }
-
- synchronized void clear() {
- clients.setSize(0);
- }
-
- boolean stop = false;
-
- synchronized void die() {
- stop = true;
- notify();
- }
-
- public void run() {
- while (!stop) {
- DIWUpdateRequest r = getRequest();
-
- /* r == null if die() was called and it woke up
- getNextClient() */
- if (r != null) {
- /* This is done this way for the following
- reason. It is possible we have been told to
- stop between the time we call diw.updateChild,
- and the time we actually get the monitor.
- updateChild is a synchronized method on diw.
- If stop is called, we don't want to update the
- child. So, we enter diw's monitor ahead of
- time, and then once we get it, we check to see
- if we've stopped. If we have, then we don't
- paint the child, and essentially, break from
- the loop. */
- synchronize (diw) {
- if (!stop) {
- r.execute(diw);
- }
- }
- }
- }
- }
- }
-