home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / awt / displayitemwindow.java < prev    next >
Text File  |  1995-08-11  |  15KB  |  625 lines

  1. /*
  2.  * @(#)DisplayItemWindow.java    1.45 95/08/06 Jonathan Payne
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package awt;
  21.  
  22. import java.util.*;
  23.  
  24. /**
  25.  * DisplayItemWindow is a subclass of Window that can display embedded
  26.  * DisplayItem's. This task involves mainly distributing input to the
  27.  * right DisplayItem and causing the appropriate items to be displayed
  28.  * in response to damage or scrolling events.
  29.  * @version 1.45 06 Aug 1995
  30.  * @author Jonathan Payne
  31.  */
  32. public class DisplayItemWindow extends Window {
  33.     DIWUpdaterThread    updater = null;
  34.     Vector        nativeItems;
  35.     Scrollbar        sb = null;
  36.     DisplayItem        items[] = new DisplayItem[0];
  37.     int            used = 0;
  38.     protected int    logicalWidth;
  39.     protected int    logicalHeight;
  40.     protected DisplayItem   currentInputItem;
  41.     protected boolean        stickyTracking = true;
  42.     Event        tEvent = new Event();        /* translated event */
  43.     protected boolean     valid = false;
  44.     protected int    scrollX;
  45.     protected int       scrollY;
  46.     public FocusManager fm = new FocusManager(this);
  47.  
  48.     /** Creates a DisplayItemWindow that is contained inside a Frame. */
  49.     public DisplayItemWindow(Frame f, String name) {
  50.     super(f,name, Color.lightGray, 600,600);
  51.     nativeItems = new Vector();
  52.     setLayout(null);
  53.     }
  54.  
  55.     /** Creates a DisplayItemWindow that is contained inside a Window */
  56.     public DisplayItemWindow(Window parent, String client) {
  57.     super(parent, client, Color.lightGray, 150, 150);
  58.     setMargin(2);
  59.     nativeItems = new Vector();
  60.     setLayout(null);
  61.     }
  62.  
  63.     /** Set the scrollbar for this DisplayItemWindow to s */
  64.     public void setScrollbar(Scrollbar s) {
  65.     sb = s;
  66.     invalidate();
  67.     }
  68.  
  69.     /** Indicates that this DisplayItemWindow needs updating. */
  70.     public void invalidate() {
  71.     valid = false;
  72.     }
  73.  
  74.     /** Updates the scrollbar to reflect the current size of the
  75.      *  window.
  76.      */
  77.     public void updateScrollbar() {
  78.     if (sb != null && height > 0 && logicalHeight > 0) {
  79.         sb.setValues(-scrollY, height, 0, logicalHeight);
  80.     }
  81.     }
  82.  
  83.     /** Marks this window as valid (not in need of repainting) */
  84.     public void validate() {
  85.     updateScrollbar();
  86.     valid = true;
  87.     }
  88.  
  89.     public synchronized void handleExpose(int x, int y, int w, int h) {
  90.     graphics.clipRect(x, y, w, h);
  91. //    graphics.setForeground(Color.red);
  92. //    graphics.fillRect(x, y, w, h);
  93. //    update();
  94. //    System.out.println("Expose: " + x + ", " + y + ", " + w + ", " + h);
  95. //    Thread.sleep(500);
  96.     paintRange(y, y + h);
  97.     graphics.clearClip();
  98.     }
  99.  
  100.     /** Called in response to a resize action by the user. Redoes the
  101.      * window layout and marks the window as invalid.
  102.      */
  103.     public void handleResize() {
  104.     if (theLayout != null)
  105.         theLayout.layout(this);
  106.     invalidate();
  107.     }
  108.  
  109.  
  110.     /** Adds an named DisplayItem to the window. */
  111.     public synchronized void addItem(DisplayItem di, String name) {
  112.     if (name != null) {
  113.         addChild(di, name);
  114.     }
  115.     addItem(di);
  116.     }
  117.  
  118.  
  119.     /** Adds an unnamed DisplayItem to the window. */
  120.     public synchronized void addItem(DisplayItem di) {
  121.     di.setParent(this);
  122.     if (di instanceof NativeDisplayItem) {
  123.         addNativeItem((NativeDisplayItem)di);
  124.     }
  125.     if (used == items.length) {
  126.         int    amt = (used == 0) ? 40 : (int)(used * 1.5);
  127.         
  128.         DisplayItem    newItems[] = new DisplayItem[amt];
  129.         System.arraycopy(items, 0, newItems, 0, items.length);
  130.         items = newItems;
  131.     }
  132.     items[used++] = di;
  133.     invalidate();
  134.     }
  135.  
  136.     /** Returns the array of items in this window. */
  137.     public DisplayItem getItems()[] {
  138.     return items;
  139.     }
  140.  
  141.     /** Adds a DisplayItem that is a subclass of NativeDisplayItem.
  142.      * This method is needed because DisplayItem's that are native
  143.      * gui components require special treatment.
  144.      * @see awt.NativeDisplayItem
  145.      */
  146.     protected synchronized void addNativeItem(NativeDisplayItem di) {
  147.     int i = nativeItems.size();
  148.  
  149.     while (--i >= 0) {
  150.         if ((NativeDisplayItem)nativeItems.elementAt(i) == di) {
  151.         break;
  152.         }
  153.     }
  154.     if (i < 0) {
  155.         nativeItems.addElement(di);
  156.     }
  157.     }
  158.  
  159.     /**
  160.      * Clears the list of native display items.
  161.      */
  162.     protected synchronized void clearNativeItems() {
  163.     nativeItems.removeAllElements();
  164.     }
  165.  
  166.  
  167.     /**
  168.      * Notifies this window that the dimensions of a DisplayItem have
  169.      * changed.
  170.      */
  171.     void childChanged(DisplayItem child) {
  172. //    if (logicalWidth < child.x + child.width) {
  173. //        logicalWidth = child.x + child.width;
  174. //    }
  175. //    if (logicalHeight < child.y + child.height) {
  176. //        logicalHeight = child.y + child.height;
  177. //    }
  178.     }
  179.  
  180.     /**
  181.      * Returns the item at the given index.
  182.      */
  183.     public DisplayItem nthItem(int n) {
  184.     if (n >= used) {
  185.         throw new ArrayIndexOutOfBoundsException(n + " >= " + used);
  186.     }
  187.     return items[n];
  188.     }
  189.  
  190.     /**
  191.      * Clears the list of DisplayItems for this window. The deactivate
  192.      * method is called on each item before being removed from the list.
  193.      *
  194.      * @see awt.DisplayItem#deactivate
  195.      */
  196.     public synchronized void clearItems() {
  197.     stopUpdater();
  198.     currentInputItem = null;
  199.     for (int i = used; --i >= 0; ) {
  200.         items[i].deactivate();
  201.         items[i] = null;
  202.     }
  203.     clearNativeItems();
  204.     used = 0;
  205.     items = new DisplayItem[0];
  206.     logicalWidth = logicalHeight = 0;
  207.     invalidate();
  208.     startUpdater();
  209.     }
  210.  
  211.     /**
  212.      * Returns the number of DisplayItem's contained in this window.
  213.      */
  214.     public int count() {
  215.     return used;
  216.     }
  217.  
  218.     /**
  219.      * Paints all of the DisplayItems contained between y0 and y1.
  220.      */
  221.     synchronized void paintRange(int y0, int y1) {
  222.     if (y1 < 0 || y0 > height)
  223.         return;
  224.  
  225.     setForeground(background);
  226.     fillRect(0, y0, width, y1 - y0);
  227.     y0 -= scrollY;
  228.     y1 -= scrollY;
  229.  
  230.     int cnt = count();
  231.     int i = 0;
  232.  
  233.     while (--cnt >= 0) {
  234.         DisplayItem    di = items[i++];
  235.  
  236.         if (di.y + di.height < y0 || di.y > y1) {
  237.         continue;
  238.         }
  239.         di.paint(this, di.x + scrollX, di.y + scrollY);
  240.     }
  241.     update();
  242.     }
  243.  
  244.     public void setScrolling(int x, int y) {
  245.     scrollX = x;
  246.     scrollY = y;
  247.     }
  248.  
  249.     /** Paints all of the DisplayItems in this window. */
  250.     public void paint() {
  251.     if (!valid)
  252.         validate();
  253.     paintRange(0, height);
  254.     }
  255.  
  256.  
  257.     /** Starts the child updater thread responsible for causing
  258.      * repaints.
  259.      */
  260.     synchronized void startUpdater() {
  261.     if (updater == null) {
  262.         updater = new DIWUpdaterThread(this);
  263.         updater.start();
  264.     }
  265.     }
  266.  
  267.     /** Kill updater in its tracks, because we are doing something
  268.     which could cause the updater to display a display item that
  269.     is no longer in this window!  Stopping it in its tracks takes
  270.     care of that race condition. */
  271.     synchronized void stopUpdater() {
  272.     if (updater != null) {
  273.         updater.die();
  274.         updater = null;
  275.     }
  276.     }
  277.  
  278.     /** Shows this window. */
  279.     public void map() {
  280.     super.map();
  281.     startUpdater();
  282.     }
  283.  
  284.     /** Hides this window. */
  285.     public void unMap() {
  286.     super.unMap();
  287.     stopUpdater();
  288.     }
  289.  
  290.     /** Requests that the given DisplayItem be repainted. */
  291.     public void paintChild(DisplayItem di, boolean clear) {
  292.     if (updater != null) {
  293.         updater.addRequest(di, clear);
  294.     }
  295.     }
  296.  
  297.     /** Updates the given DisplayItem. */
  298.     public void updateChild(DisplayItem di, boolean clear) {
  299.     int x, y;
  300.  
  301.     x = di.x + scrollX;
  302.     y = di.y + scrollY;
  303.     if (y + di.height < 0 || y > height) {
  304.         return;
  305.     }
  306.     if (clear) {
  307.         clearRect(x, y, di.width + 1, di.height + 1);
  308.         di.paint(this, x, y);
  309.     } else {
  310.         di.update(this, x, y);
  311.     }
  312.     update();
  313.     }
  314.  
  315.     public void addUpdateRequest(DIWUpdateRequest r) {
  316.     if (updater != null) {
  317.         updater.addRequest(r);
  318.     }
  319.     }
  320.  
  321.     /** Returns the DisplayItem which contains x,y. */
  322.     /*
  323.     There is a very nasty deadlock situation with this module on 
  324.     win32 due to differences in the win32 implementation of the 
  325.     WServer thread.  By removing "synchronized", we introduce
  326.     a race condition but reduce the likelyhood of deadlock.
  327.     We need to fix this soon.  -chan
  328.  
  329.     public synchronized DisplayItem locateItem(int x, int y) {
  330.     */
  331.     public DisplayItem locateItem(int x, int y) {
  332.     int i = count();
  333.  
  334.     x -= scrollX;
  335.     y -= scrollY;
  336.     while (--i >= 0) {
  337.         DisplayItem    di = items[i];
  338.  
  339.             if (di != null) {  
  340.         if (di.containsPoint(x, y)) {
  341.             return di;
  342.         }
  343.             }
  344.     }
  345.     return null;
  346.     }
  347.  
  348.  
  349.     /** Translates the given event to correspond to the given
  350.      * DisplayItem's coordinate system.
  351.      */
  352.     Event translate(Event e, DisplayItem di) {
  353.     tEvent.copy(e);
  354.     tEvent.x = e.x - (di.x + scrollX);
  355.     tEvent.y = e.y - (di.y + scrollY);
  356.  
  357.     return tEvent;
  358.     }
  359.  
  360.     /**
  361.      * Forwards a mouseDown event to the DisplayItem that contains the
  362.      * current mouse coordinates.
  363.      */
  364.     public void mouseDown(Event e) {
  365.     currentInputItem = locateItem(e.x, e.y);
  366.     if (currentInputItem != null) {
  367.         currentInputItem.trackStart(translate(e, currentInputItem));
  368.     }
  369.     }
  370.  
  371.     /**
  372.      * Forwards a mouse drag event to the DisplayItem that contains the
  373.      * current mouse coordinates.
  374.      */
  375.     public void mouseDrag(Event e) {
  376.     DisplayItem   di;
  377.  
  378.     if (stickyTracking)
  379.         di = currentInputItem;
  380.     else {
  381.         di = locateItem(e.x, e.y);
  382.  
  383.         if (di != currentInputItem) {
  384.         if (currentInputItem != null) {
  385.             currentInputItem.trackExit(translate(e, currentInputItem));
  386.         }
  387.         currentInputItem = di;
  388.         if (di != null) {
  389.             di.trackEnter(translate(e, di));
  390.         }
  391.         }
  392.     }
  393.     if (di != null) {
  394.         di.trackMotion(translate(e, di));
  395.     }
  396.     }
  397.  
  398.     /** Forwards a mouse motion event to the DisplayItem that contains the
  399.      * current mouse coordinates.
  400.      */
  401.     public void mouseMoved(Event e) {
  402.     mouseDrag(e);
  403.     }
  404.  
  405.     public void mouseUp(Event e) {
  406.     if (currentInputItem != null) {
  407.         currentInputItem.trackStop(translate(e, currentInputItem));
  408.     }
  409.     currentInputItem = null;
  410.     }
  411.  
  412.     public void setSticky(boolean on) {
  413.     stickyTracking = on;
  414.     }
  415.  
  416.     public int getScrollY() {
  417.     return scrollY;
  418.     }
  419.  
  420.     public void scrollAbsolute(int x, int y) {
  421.     if (y != -scrollY) {
  422.         scrollVertically(-scrollY - y);
  423.     }
  424.     }
  425.  
  426.     /* Scrolling support. */
  427.  
  428.     synchronized public boolean scrollHorizontally(int dx) {
  429.     return true;
  430.     }
  431.  
  432.     synchronized public boolean scrollVertically(int dy) {
  433.     int    sy = scrollY;
  434.     boolean    hitLimit = false;
  435.  
  436.     if ((-sy - dy) > (logicalHeight - height)) {
  437.         dy = -logicalHeight + height - sy;
  438.         hitLimit = true;
  439.     }
  440.     scrollY += dy;
  441.     if (scrollY > 0) {
  442.         scrollY = 0;
  443.         hitLimit = true;
  444.     }
  445.     updateScrollbar();
  446.     if ((dy = sy - scrollY) != 0) {
  447.         scrollWindow(0, dy);
  448. //        paintRange(top, bottom);
  449.     }
  450.     return hitLimit;
  451.     }
  452.  
  453.     /* Scrollbarable implementation */
  454.  
  455.     int lineScrollY = 20;
  456.  
  457.     public void lineUp() {
  458.     scrollVertically(lineScrollY);
  459.     }
  460.  
  461.     public void lineDown() {
  462.     scrollVertically(-lineScrollY);
  463.     }
  464.  
  465.     public void pageUp() {
  466.     scrollVertically(height);
  467.     }
  468.  
  469.     public void pageDown() {
  470.     scrollVertically(-height);
  471.     }
  472.  
  473.     public void dragAbsolute(int value) {
  474.     scrollVertically(-scrollY - value);
  475.     }
  476.  
  477.     SmoothScroller  scroller = null;
  478.  
  479.     void thrust(boolean forward) {
  480.     if (scroller == null) {
  481.         scroller = new SmoothScroller(this);
  482.         Thread.currentThread().yield();
  483.     }
  484.     scroller.setThrust(forward ? 2000 : -2000, 50);
  485.     }
  486.  
  487.     public void keyPressed(Event event) {
  488.  
  489.     //System.out.println("DisplayItemWindow.keyPressed:  event.key is " +
  490.     //event.key + ", keyIsAscii is " + event.keyIsAscii);
  491.  
  492.     // If event.keyIsAscii is FALSE, that means this is
  493.     //   a modifier key, like leftshift or rightshift or ctrl.
  494.     //   We might need to keep track of *some* state here
  495.     //   eventually, but for now ignore these events.
  496.     // NOTE we'll need to manually keep track of the SHIFT state
  497.     //   here if we want to be able to tell TAB and shift-TAB apart!
  498.     if (!event.keyIsAscii)
  499.         return;
  500.  
  501.     switch (event.key) {
  502.     // Intercept keyboard-focus changing keys:
  503.  
  504.     case '\t':        // TAB
  505.         fm.nextFocus();
  506.         break;
  507. //  Also need two more cases, but we'll have to use a smarter input
  508. //  model to identify these!
  509. //    case 'YOW':        // Shift-TAB
  510. //        fm.prevFocus();
  511. //        break;
  512. //    case 'YOW':        // HOME
  513. //        fm.resetFocus();
  514. //        break;
  515.  
  516.     // Anything else is a key we want to pass through to 
  517.     //  whoever has the input focus:
  518.     default:
  519.         DisplayItem fitem = fm.currentFocusItem();
  520.         if (fitem != null) {
  521.         fitem.keyPressed(event.key);
  522.         }
  523.         break;
  524.     }
  525.     }
  526. }
  527.  
  528. class DisplayItemUpdateRequest extends DIWUpdateRequest {
  529.     DisplayItem    di;
  530.  
  531.     DisplayItemUpdateRequest(DisplayItem di, boolean clear) {
  532.     this.di = di;
  533.     this.clear = clear;
  534.     }
  535.  
  536.     void execute(DisplayItemWindow w) {
  537.     w.updateChild(di, clear);
  538.     }
  539.     public boolean equals(Object obj) {
  540.     if ((obj != null) && (obj instanceof DisplayItemUpdateRequest)) {
  541.         return ((DisplayItemUpdateRequest)obj).di == di;
  542.     }
  543.     return false;
  544.     }
  545. }
  546.  
  547. class DIWUpdaterThread extends Thread {
  548.     DisplayItemWindow    diw;
  549.     Vector  clients = new Vector();
  550.  
  551.     DIWUpdaterThread(DisplayItemWindow diw) {
  552.     setPriority(NORM_PRIORITY - 1);
  553.     this.diw = diw;
  554.     }
  555.  
  556.     public synchronized void addRequest(DIWUpdateRequest r) {
  557.     int i = clients.indexOf(r);
  558.     if (i < 0) {
  559.         clients.addElement(r);
  560.         notify();
  561.     } else {
  562.         DIWUpdateRequest r2 = (DIWUpdateRequest)clients.elementAt(i);
  563.         if (r.clear && !r2.clear) {
  564.         r2.clear = true;
  565.         }
  566.     }
  567.     }
  568.  
  569.     public void addRequest(DisplayItem di, boolean clear) {
  570.     addRequest(new DisplayItemUpdateRequest(di, clear));
  571.     }
  572.  
  573.     synchronized DIWUpdateRequest getRequest() {
  574.     while (clients.size() == 0 && !stop) {
  575.         wait();
  576.     }
  577.  
  578.     DIWUpdateRequest    r = null;
  579.  
  580.     if (!stop) {
  581.         r = (DIWUpdateRequest) clients.elementAt(0);
  582.         clients.removeElementAt(0);
  583.     }
  584.     return r;
  585.     }
  586.  
  587.     synchronized void clear() {
  588.     clients.setSize(0);
  589.     }
  590.  
  591.     boolean stop = false;
  592.  
  593.     synchronized void die() {
  594.     stop = true;
  595.     notify();
  596.     }
  597.  
  598.     public void run() {
  599.     while (!stop) {
  600.         DIWUpdateRequest r = getRequest();
  601.  
  602.         /* r == null if die() was called and it woke up
  603.            getNextClient() */
  604.         if (r != null) {
  605.         /* This is done this way for the following
  606.            reason.  It is possible we have been told to
  607.            stop between the time we call diw.updateChild,
  608.            and the time we actually get the monitor.
  609.            updateChild is a synchronized method on diw.
  610.            If stop is called, we don't want to update the
  611.            child.  So, we enter diw's monitor ahead of
  612.            time, and then once we get it, we check to see
  613.            if we've stopped.  If we have, then we don't
  614.            paint the child, and essentially, break from
  615.            the loop. */
  616.         synchronize (diw) {
  617.             if (!stop) {
  618.             r.execute(diw);
  619.             }
  620.         }
  621.         }
  622.     }
  623.     }
  624. }
  625.