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

  1. /*
  2.  * @(#)WRImageItem.java    1.62 95/04/26 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. package browser;
  20.  
  21. import awt.*;
  22. import net.www.html.*;
  23. import java.util.Hashtable;
  24. import java.io.InputStream;
  25. import java.io.FileOutputStream;
  26.  
  27. /**
  28.  * Class WRImageItem is the display item for all images that appear
  29.  * in HotJava documents.  It handles alignment queries, delayed
  30.  * image loading, image caching and following hypertext links if the
  31.  * image is part of an anchor.
  32.  * Instances of this class are observers of instances of
  33.  * ImageHandle.  That way this display item will get notified
  34.  * when the ImageHandle finishes reading an image across the net.
  35.  * @version 1.62, 26 Apr 1995
  36.  * @author Jonathan Payne
  37.  * @author Chris Warth
  38.  */
  39.  
  40. public class WRImageItem extends ImageDisplayItem implements Alignable, Observer {
  41.     static Hashtable    alignHT = new Hashtable();
  42.  
  43.     /**
  44.      * "Image Delayed" icon.
  45.      */
  46.     static public Image imageDelayedImage = null;
  47.  
  48.     /**
  49.      * "Image Failed" icon.
  50.      */
  51.     static public Image imageFailedImage = null;
  52.  
  53.     /**
  54.      * "Image Loading" icon.
  55.      */
  56.     static public Image imageLoadingImage = null;
  57.  
  58.     /**
  59.      * "Image Ref Delayed" icon.
  60.      */
  61.     static public Image imageRefDelayedImage = null;
  62.  
  63.     /**
  64.      * "Image Ref Failed" icon.
  65.      */
  66.     static public Image imageRefFailedImage = null;
  67.     
  68.     static {
  69.     alignHT.put("top",     new Integer(A_TOP));
  70.     alignHT.put("texttop",     new Integer(A_TEXTTOP));
  71.     alignHT.put("middle",     new Integer(A_MIDDLE));
  72.     alignHT.put("absmiddle",new Integer(A_ABSMIDDLE));
  73.     alignHT.put("bottom",     new Integer(A_BOTTOM));
  74.     alignHT.put("baseline", new Integer(A_BASELINE));
  75.     alignHT.put("absbottom",new Integer(A_ABSBOTTOM));
  76.     }
  77.  
  78.     public static int convertAlign(String align) {
  79.     if (align == null) {
  80.         return A_BOTTOM;
  81.     }
  82.     Integer v = (Integer)alignHT.get(align);
  83.     if (v != null) {
  84.         return v.intValue();
  85.     }
  86.     v = (Integer)alignHT.get(align.toLowerCase());
  87.     return (v != null) ? v.intValue() : A_BASELINE;
  88.     }
  89.  
  90.     Image delayImage;
  91.     int        align;
  92.     Color normalColor;
  93.     Color highlightColor;
  94.     String error;
  95.     protected boolean    paintImage;
  96.     protected TagRef    imgTag;
  97.     protected URL    imageUrl;
  98.     protected URL    anchorUrl;
  99.     protected boolean    ismap;
  100.     protected byte    borderThickness = 0;
  101.     URL            documentURL;
  102.     protected int    tagWidth = -1;
  103.     protected int    tagHeight = -1;
  104.  
  105.     /**
  106.      * Creates a new WRImageItem in the specified WRWindow.  The
  107.      * image source is retrieved from the specified TagRef which
  108.      * must contain a "src" attribute.  If this image contains a
  109.      * reference to another URL, then that is specified by the href
  110.      * argument.
  111.      */
  112.     public WRImageItem (WRWindow w, TagRef imgTag, String href) {
  113.     super(null);
  114.  
  115.     documentURL = w.document().url();
  116.     imageUrl = getImageUrl(documentURL, w, imgTag);
  117.     this.imgTag = imgTag;
  118.     setAnchor(href);
  119.  
  120.     Image    img = null;
  121.     int wd = 38;        // the dimensions of the load-status icons
  122.     int ht = 38;
  123.     String    attr;
  124.  
  125.     if ((attr = imgTag.getAttribute("width")) != null) {
  126.         try {
  127.         tagWidth = wd = Integer.parseInt(attr);
  128.         } catch (NumberFormatException ee) {
  129.         }
  130.     }
  131.     if ((attr = imgTag.getAttribute("height")) != null) {
  132.         try {
  133.         tagHeight = ht = Integer.parseInt(attr);
  134.         } catch (NumberFormatException ee) {
  135.         }
  136.     }
  137.     resizeFromImageSize(wd, ht);
  138.  
  139.     align = convertAlign(imgTag.getAttribute("align"));
  140.     highlightColor = Color.red;
  141.  
  142.     ismap = imgTag.getAttribute("ismap") != null;
  143.  
  144.     checkImage(w);
  145.     }
  146.  
  147.     public void nuke() {
  148.     if (imageUrl != null) {
  149.         ImageCache.flushHandle(imageUrl);
  150.         ImageCache.flushHandle(imageUrl, tagWidth, tagHeight);
  151.     }
  152.     }
  153.  
  154.     public void checkImage(Window w) {
  155.     if (error != null) {
  156.         nuke();
  157.     }
  158.     setImage((Image)null);
  159.     error = null;
  160.     if (imageUrl != null) {
  161.         Object o;
  162.         ImageHandle h = ImageCache.lookupHandle(w, imageUrl,
  163.                             tagWidth, tagHeight);
  164.         if (WRWindow.delayImageLoading) {
  165.         o = h.checkForImage(this);
  166.         } else {
  167.         o = h.getImage(this, false);
  168.         }
  169.         if (o != null) {
  170.         if (o instanceof Image) {
  171.             setImage((Image) o);
  172.         } else if (o != null) {
  173.             error  = (String) o;
  174.         }
  175.         imageSizeKnown = true;
  176.         }
  177.     }
  178.  
  179.     maybeInitLoadIcons(w);
  180.     }
  181.  
  182.     private void maybeInitLoadIcons(Window w) {
  183.     if (imageDelayedImage == null) {
  184.         final String base = "doc:demo/images/";
  185.         
  186.         imageDelayedImage = getLoadIcon(w, base+"image-delayed.gif");
  187.         imageFailedImage = getLoadIcon(w, base+"image-failed.gif");
  188.         imageLoadingImage = getLoadIcon(w, base+"image-loading.gif");
  189.         imageRefDelayedImage = getLoadIcon(w,
  190.                            base+"image-ref-delayed.gif");
  191.         imageRefFailedImage = getLoadIcon(w, base+"image-ref-failed.gif");
  192.     }
  193.     }
  194.  
  195.     public static URL getImageUrl(URL context, WRWindow w, TagRef ref) {
  196.     String    imageSrc = ref.getAttribute("src");
  197.     URL    imageUrl = null;
  198.  
  199.     if (imageSrc != null) {
  200.         try {
  201.         imageUrl = new URL(context, imageSrc);
  202.         } catch (MalformedURLException e) {
  203.         System.out.println("Cannot build url for image " + imageSrc +
  204.                    " in document " + context.toExternalForm());
  205.         }
  206.     }
  207.     return imageUrl;
  208.     }
  209.  
  210.     public static void kickImage(WRWindow w, ImgTagRef ref) {
  211.     URL imageUrl = getImageUrl(w.document().url(), w, ref);
  212.     String    attr;
  213.     int wd = -1, ht = -1;
  214.  
  215.     if ((attr = ref.getAttribute("width")) != null) {
  216.         try {
  217.         wd = Integer.parseInt(attr);
  218.         } catch (NumberFormatException ee) {
  219.         }
  220.     }
  221.     if ((attr = ref.getAttribute("height")) != null) {
  222.         try {
  223.         ht = Integer.parseInt(attr);
  224.         } catch (NumberFormatException ee) {
  225.         }
  226.     }
  227.  
  228.     if (imageUrl != null) {
  229.         ImageHandle    ih = ImageCache.lookupHandle(w, imageUrl, wd, ht);
  230.         if (ref.di != null) {
  231.         ((WRImageItem)ref.di).painted = false;
  232.         }
  233.         Object o = ih.getImage((Observer)ref.di, false);
  234.         if ((o != null) && (ref.di != null)) {
  235.         if (o instanceof Image) {
  236.             ((WRImageItem)ref.di).setImage((Image)o);
  237.         } else {
  238.             ((WRImageItem)ref.di).error = (String)o;
  239.         }
  240.         ((WRImageItem)ref.di).imageSizeKnown = true;
  241.         }
  242.     }
  243.     }
  244.  
  245.     public void setAnchor(String href) {
  246.     /*
  247.      * Now get the URL out of the anchor, if we have one.  This
  248.      * needs to be done before we set the image, because it keys
  249.      * off of anchorUrl to decide in its size (i.e., whether to
  250.      * make room for an anchor border).
  251.      */
  252.     if (href != null) {
  253.         anchorUrl = new URL(documentURL, href);
  254.         setColorFromUrl(anchorUrl);
  255.     } else {
  256.         setColor(Color.black);
  257.     }
  258.     initializeBorderThickness();
  259.     }
  260.  
  261.     boolean setColorFromUrl(URL url) {
  262.     Color    c = fgColor;
  263.  
  264.     if (hotjava.history.seen(url)) {
  265.         setColor(hotjava.visitedAnchorColor);
  266.     } else {
  267.         setColor(hotjava.anchorColor);
  268.     }
  269.     return c != fgColor;
  270.     }
  271.  
  272.     /**
  273.      * Get alignment for formatting.
  274.      */
  275.     public int getAlign() {
  276.     return align;
  277.     }
  278.  
  279.     static private Image getLoadIcon(Window w, String name) {
  280.     URL imgURL = new URL(null, name);
  281.     InputStream iStream = null;
  282.     
  283.     try {
  284.         iStream = imgURL.openStream();
  285.     } catch (Exception e) { }
  286.  
  287.     if (iStream == null) {
  288.         return null;
  289.     } else {
  290.         GifImage gif = new GifImage(iStream, null);
  291.         return w.createImage(gif);
  292.     }
  293.     }
  294.     
  295.     protected void initializeBorderThickness() {
  296.     if (anchorUrl != null) {
  297.         borderThickness = 2;
  298.         try {
  299.         String    border = imgTag.getAttribute("border");
  300.  
  301.         if (border != null) {
  302.             borderThickness = (byte) Integer.parseInt(border);
  303.         }
  304.         if (borderThickness < 0) {
  305.             borderThickness = 0;
  306.         }
  307.         } catch (NumberFormatException e) {
  308.         borderThickness = 2;
  309.         }
  310.     }
  311.     }
  312.  
  313.     public void resizeFromImage(Image img) {
  314.     if (img != null) {
  315.         resizeFromImageSize(img.width, img.height);
  316.     }
  317.     }
  318.  
  319.     public void resizeFromImageSize(int w, int h) {
  320.     int incr = borderThickness * 2;
  321.  
  322.     if (tagWidth > 0)
  323.         w = tagWidth;
  324.     if (tagHeight > 0)
  325.         h = tagHeight;
  326.  
  327.     resize(w + incr, h + incr);
  328.     }
  329.  
  330.     boolean painted = false;
  331.  
  332.     /**
  333.      * Draw the image if it's not null and if more than half its height
  334.      * and width will be visible.
  335.      */
  336.     static private final void maybeDrawImage(Window w, Image i, int x, int y,
  337.                          int inWidth, int inHeight) {
  338.     if (i != null && (i.width / 2) < inWidth && (i.height / 2) < inHeight) {
  339.         w.drawImage(i, x, y);
  340.     }
  341.     }
  342.     
  343.     public synchronized void paint(Window w, int x, int y) {
  344.     try {
  345.         if (pic == null || borderThickness > 0) {
  346.         drawBorder(w, x, y);
  347.         }
  348.  
  349.         if (pic == null) {
  350.         // use drawBorder's own logic against it!
  351.         int offset = (borderThickness == 0) ? 2 : borderThickness;
  352.         w.clipRect(x + offset, y + offset,
  353.                width - 2 * offset, height - 2 * offset);
  354.  
  355.         if (!WRWindow.delayImageLoading && error == null) {
  356.             w.setForeground(Color.lightGray);
  357.             w.fillRect(x + offset, y + offset,
  358.                    width - offset * 2, height - offset * 2);
  359.             maybeDrawImage(w, imageLoadingImage, x + offset, y + offset,
  360.                    width, height);
  361.         } else {
  362.             w.setForeground((error == null) ? Color.yellow : Color.red);
  363.             if (width < offset * 2 || height < offset * 2) {
  364.             w.clearClip();
  365.             w.fillRect(x, y, width, height);
  366.             } else {
  367.             w.fillRect(x + offset, y + offset,
  368.                    width - offset * 2, height - offset * 2);
  369.             }
  370.  
  371.             if ((anchorUrl == null) || ismap) {
  372.             maybeDrawImage(w, (error == null) ? imageDelayedImage :
  373.                        imageFailedImage, x + offset, y + offset,
  374.                        width, height);
  375.             } else {
  376.             maybeDrawImage(w, (error == null) ?
  377.                        imageRefDelayedImage :
  378.                        imageRefFailedImage,
  379.                        x + offset, y + offset, width, height);
  380.             }
  381.         }
  382.         } else {
  383.         super.paint(w, x + borderThickness, y + borderThickness);
  384.         }
  385.         painted = true;
  386.         full = false;
  387.     } finally {
  388.         w.clearClip();
  389.     }
  390.     }
  391.  
  392.     void drawBorder(Window w, int x, int y) {
  393.     if (pic == null && borderThickness == 0) {
  394.         if (width >= 2 && height >= 2) {
  395.         w.paint3DRect(x, y, width, height, false, true);
  396.         }
  397.     } else {
  398.         int b = borderThickness;
  399.  
  400.         w.setForeground(fgColor);
  401.         w.fillRect(x, y, width, b);
  402.         w.fillRect(x, y + height - b, width, b);
  403.         w.fillRect(x, y + b, b, height - b * 2);
  404.         w.fillRect(x + width - b, y + b, b, height - b * 2);
  405.     }
  406.     }
  407.  
  408.     boolean full;
  409.  
  410.     /** Update is called when the mouse is clicked over an image.
  411.     When that occurs, we just repaint the border, if we have
  412.     one. */
  413.     public synchronized void update(Window w, int x, int y) {
  414.     if (full) {
  415.         w.clearRect(x, y, width, height);
  416.         paint(w, x, y);
  417.     } else {
  418.         drawBorder(w, x, y);
  419.     }
  420.     }
  421.  
  422.     public void trackEnter(Event e) {
  423.     if (pic == null && (WRWindow.delayImageLoading || error != null)) {
  424.         trackMotion(e);
  425.     } else if (ismap) {
  426.         ((WRWindow)parent).status("Image map " +
  427.                       anchorUrl.toExternalForm());
  428.     } else if (anchorUrl != null) {
  429.         ((WRWindow)parent).status("Go to " + anchorUrl.toExternalForm());
  430.     } 
  431.     }
  432.  
  433.     // The anchor tab is triangular, edges (0,0) - (0,tabSize) - (tabSize,0)
  434.  
  435.     final int tabSize = 14;
  436.     
  437.     public void trackMotion(Event e) {
  438.     // The ref is a diagonal tab in the upper left corner, accounting for
  439.     // the funny inequality below.
  440.     if (pic == null && (WRWindow.delayImageLoading || error != null)) {
  441.         if ((anchorUrl != null) &&
  442.         ((e.x + e.y) < (2 * borderThickness) + tabSize) && !ismap) {
  443.         ((WRWindow)parent).status("Go to " +
  444.                       anchorUrl.toExternalForm());
  445.         } else if (error != null) {
  446.         ((WRWindow)parent).status(error);
  447.         } else if (ismap) {
  448.         ((WRWindow)parent).status("Image map " +
  449.                       imageUrl.toExternalForm());
  450.         } else {
  451.         ((WRWindow)parent).status("Image " +
  452.                       imageUrl.toExternalForm());
  453.         }
  454.     } 
  455.     }
  456.  
  457.     public void trackExit(Event e) {
  458.     if ((anchorUrl != null) || WRWindow.delayImageLoading ||
  459.         error != null) {
  460.         ((WRWindow)parent).status("");
  461.     }
  462.     }
  463.  
  464.     public void setColor(Color c) {
  465.     if (normalColor == null) {
  466.         normalColor = c;
  467.     }
  468.     super.setColor(c);
  469.     }
  470.  
  471.     public void trackStart(Event e) {
  472.     if (anchorUrl != null) {
  473.         setColor(highlightColor);
  474.         requestUpdate(false);
  475.     }
  476.     }
  477.  
  478.     void requestUpdate(boolean full) {
  479.     if (full) {
  480.         this.full = full;
  481.     }
  482.     super.requestUpdate();
  483.     }
  484.  
  485.     /*
  486.      * The user clicked on the image, either go to the reference or start
  487.      * loading the image!
  488.      */
  489.     public void trackStop(Event e) {
  490.     if (anchorUrl != null) {
  491.         setColor(normalColor);
  492.         requestUpdate(false);
  493.     }
  494.     // The ref is a diagonal tab in the upper left corner, accounting for
  495.     // the funny inequality below.
  496.     if ((pic == null) && WRWindow.delayImageLoading) {
  497.         if ((anchorUrl == null) ||
  498.         ((e.x + e.y) >= (2 * borderThickness) + tabSize) || ismap) {
  499.         Image img = null;
  500.  
  501.         if (imageUrl != null) {
  502.             new DelayedImageFetcher(this).start();
  503.         }
  504.         setImage(img);
  505.         return;
  506.         }
  507.     }
  508.     executeClick(e);
  509.     }
  510.  
  511.     void fetchDelayedImage() {
  512.     int ow = width;
  513.     int oh = height;
  514.  
  515.     ImageHandle h = ImageCache.lookupHandle(parent, imageUrl,
  516.                         tagWidth, tagHeight);
  517.     Object obj = h.getImage(this, true);
  518.  
  519.     if (obj != null) {
  520.         if (obj instanceof Image) {
  521.         setImage((Image)obj);
  522.         } else {
  523.         error = (String)obj;
  524.         }
  525.         imageSizeKnown = true;
  526.         if (ow != width || oh != height) {
  527.         ((WRWindow) parent).relayout();
  528.         } else {
  529.         requestUpdate(true);
  530.         }
  531.     }
  532.     }
  533.  
  534.     protected void executeClick(Event e) {
  535.     if (anchorUrl != null) {
  536.         WRWindow    mw = (WRWindow) parent;
  537.         URL            url;
  538.  
  539.         if (ismap) {
  540.         String    urlName;
  541.  
  542.         urlName = anchorUrl.toExternalForm() + "?" + e.x + "," + e.y;
  543.         url = new URL(null, urlName);
  544.         } else {
  545.         url = anchorUrl;
  546.         }
  547.         hotjava.history.addUrl(url);
  548.         if (setColorFromUrl(url)) {
  549.         requestUpdate();
  550.         }
  551.         mw.pushURL(url);
  552.     }
  553.     }
  554.  
  555.     boolean imageSizeKnown = false;
  556.  
  557.     public synchronized void update(Observable o) {
  558.     ImageHandle h = (ImageHandle) o;
  559.     Object obj;
  560.  
  561.     if (!imageSizeKnown) {
  562.         imageSizeKnown = true;
  563.         resizeFromImageSize(h.width(), h.height());
  564.         notifyAll();
  565.     }
  566.  
  567.     obj = h.getImage(this, false);
  568.     if (obj != null) {
  569.         if (obj instanceof Image) {
  570.         if (getImage() != (Image) obj) {
  571.             setImage((Image) obj);
  572.         }
  573.         } else {
  574.         error = (String) obj;
  575.         if (painted) {
  576.             requestUpdate(true);
  577.         }
  578.         }
  579.         /* we don't care anymore - we already got what we need */
  580.         o.deleteObserver(this);
  581.         notifyAll();
  582.     }
  583.     }
  584.  
  585.     public void deactivate() {
  586.     if ((pic == null) && (error == null)) {
  587.         ImageHandle h = ImageCache.lookupHandle(parent, imageUrl,
  588.                             tagWidth, tagHeight);
  589.         if (h != null) {
  590.         h.deleteObserver(this);
  591.         }
  592.     }
  593.     // Set the image and error to null so that images can be de-cached
  594.     // and so the image will be reloaded if the image cache is flushed.
  595.     setImage((Image) null);
  596.     error = (String) null;
  597.     }
  598.  
  599.     public synchronized void waitForImageSize() {
  600.     while (!imageSizeKnown && !WRWindow.delayImageLoading
  601.            && (tagWidth <= 0 || tagHeight <= 0)) {
  602.         wait(2000);    // wake up every 2 seconds and make sure 
  603.             // we haven't been killed.
  604.     }
  605.     }
  606.  
  607.     public synchronized void waitForImage() {
  608.     while (getImage() == null) {
  609.         wait();
  610.     }
  611.     }
  612.  
  613.     public synchronized void setImage(Image i) {
  614.     super.setImage(i);
  615.     if (i != null) {
  616.         imageSizeKnown = true;
  617.         if (painted) {
  618.         requestUpdate(true);
  619.         }
  620.     }
  621.     }
  622. }
  623.  
  624. class DelayedImageFetcher extends Thread {
  625.     WRImageItem    item;
  626.  
  627.     DelayedImageFetcher(WRImageItem wim) {
  628.     item = wim;
  629.     }
  630.  
  631.     public void run() {
  632.     setName("DelayedImageFetcher");
  633.     item.fetchDelayedImage();
  634.     }
  635. }
  636.