home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / JBuilder8.iso / Solaris / resource / jre / demo / applets / ImageMap / ImageMap.java < prev    next >
Encoding:
Java Source  |  2002-09-06  |  14.0 KB  |  500 lines

  1. /*
  2.  * Copyright (c) 2002 Sun Microsystems, Inc. All  Rights Reserved.
  3.  * 
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 
  8.  * -Redistributions of source code must retain the above copyright
  9.  *  notice, this list of conditions and the following disclaimer.
  10.  * 
  11.  * -Redistribution in binary form must reproduct the above copyright
  12.  *  notice, this list of conditions and the following disclaimer in
  13.  *  the documentation and/or other materials provided with the distribution.
  14.  * 
  15.  * Neither the name of Sun Microsystems, Inc. or the names of contributors
  16.  * may be used to endorse or promote products derived from this software
  17.  * without specific prior written permission.
  18.  * 
  19.  * This software is provided "AS IS," without a warranty of any kind. ALL
  20.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
  21.  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
  22.  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
  23.  * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
  24.  * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
  25.  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
  26.  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
  27.  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
  28.  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
  29.  * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  30.  * 
  31.  * You acknowledge that Software is not designed, licensed or intended for
  32.  * use in the design, construction, operation or maintenance of any nuclear
  33.  * facility.
  34.  */
  35.  
  36. /*
  37.  * @(#)ImageMap.java    1.17 02/06/13
  38.  */
  39.  
  40. import java.applet.Applet;
  41. import java.awt.Image;
  42. import java.awt.Graphics;
  43. import java.awt.Rectangle;
  44. import java.awt.MediaTracker;
  45. import java.awt.event.*;
  46. import java.util.StringTokenizer;
  47. import java.util.Vector;
  48. import java.util.Hashtable;
  49. import java.net.URL;
  50. import java.awt.image.ImageProducer;
  51. import java.awt.image.ImageFilter;
  52. import java.awt.image.CropImageFilter;
  53. import java.awt.image.FilteredImageSource;
  54. import java.net.MalformedURLException;
  55.  
  56. /**
  57.  * An extensible ImageMap applet class.
  58.  * The active areas on the image are controlled by ImageArea classes
  59.  * that can be dynamically loaded over the net.
  60.  *
  61.  * @author     Jim Graham
  62.  * @version     1.17, 06/13/02
  63.  */
  64. public class ImageMap
  65.     extends Applet
  66.     implements Runnable, MouseListener, MouseMotionListener {
  67.     /**
  68.      * The unhighlighted image being mapped.
  69.      */
  70.     Image baseImage;
  71.  
  72.     /**
  73.      * The list of image area handling objects;
  74.      */
  75.     ImageMapArea areas[];
  76.  
  77.     /**
  78.      * The primary highlight mode to be used.
  79.      */
  80.     static final int BRIGHTER = 0;
  81.     static final int DARKER = 1;
  82.  
  83.     int hlmode = BRIGHTER;
  84.  
  85.     /**
  86.      * The percentage of highlight to apply for the primary highlight mode.
  87.      */
  88.     int hlpercent = 50;
  89.  
  90.     /**
  91.      * The MediaTracker for loading and constructing the various images.
  92.      */
  93.     MediaTracker tracker;
  94.  
  95.     /**
  96.      * Get a rectangular region of the baseImage highlighted according to
  97.      * the primary highlight specification.
  98.      */
  99.     Image getHighlight(int x, int y, int w, int h) {
  100.     return getHighlight(x, y, w, h, hlmode, hlpercent);
  101.     }
  102.  
  103.     /**
  104.      * Get a rectangular region of the baseImage with a specific highlight.
  105.      */
  106.     Image getHighlight(int x, int y, int w, int h, int mode, int percent) {
  107.     return getHighlight(x, y, w, h, new HighlightFilter(mode == BRIGHTER,
  108.                                 percent));
  109.     }
  110.  
  111.     /**
  112.      * Get a rectangular region of the baseImage modified by an image filter.
  113.      */
  114.     Image getHighlight(int x, int y, int w, int h, ImageFilter filter) {
  115.     ImageFilter cropfilter = new CropImageFilter(x, y, w, h);
  116.     ImageProducer prod = new FilteredImageSource(baseImage.getSource(),
  117.                              cropfilter);
  118.     return makeImage(prod, filter, 0);
  119.     }
  120.  
  121.     /**
  122.      * Make a filtered image based on another image.
  123.      */
  124.     Image makeImage(Image orig, ImageFilter filter) {
  125.     return makeImage(orig.getSource(), filter);
  126.     }
  127.  
  128.     /**
  129.      * Make a filtered image based on another ImageProducer.
  130.      */
  131.     Image makeImage(ImageProducer prod, ImageFilter filter) {
  132.     return makeImage(prod, filter,
  133.              (prod == baseImage.getSource()) ? 1 : 0);
  134.     }
  135.  
  136.     /**
  137.      * Make a filtered image based on another ImageProducer.
  138.      * Add it to the media tracker using the indicated ID.
  139.      */
  140.     Image makeImage(ImageProducer prod, ImageFilter filter, int ID) {
  141.     Image filtered = createImage(new FilteredImageSource(prod, filter));
  142.     tracker.addImage(filtered, ID);
  143.     return filtered;
  144.     }
  145.  
  146.     /**
  147.      * Add an image to the list of images to be tracked.
  148.      */
  149.     void addImage(Image img) {
  150.     tracker.addImage(img, 1);
  151.     }
  152.  
  153.     /**
  154.      * Parse a string representing the desired highlight to be applied.
  155.      */
  156.     void parseHighlight(String s) {
  157.     if (s == null) {
  158.         return;
  159.     }
  160.     if (s.startsWith("brighter") || s.startsWith("BRIGHTER")) {
  161.         hlmode = BRIGHTER;
  162.         if (s.length() > "brighter".length()) {
  163.         hlpercent = Integer.parseInt(s.substring("brighter".length()));
  164.         }
  165.     } else if (s.startsWith("darker") || s.startsWith("DARKER")) {
  166.         hlmode = DARKER;
  167.         if (s.length() > "darker".length()) {
  168.         hlpercent = Integer.parseInt(s.substring("darker".length()));
  169.         }
  170.     }
  171.     }
  172.  
  173.     /**
  174.      * Initialize the applet. Get attributes.
  175.      *
  176.      * Initialize the ImageAreas.
  177.      * Each ImageArea is a subclass of the class ImageArea, and is
  178.      * specified with an attribute of the form:
  179.      *         areaN=ImageAreaClassName,arguments...
  180.      * The ImageAreaClassName is parsed off and a new instance of that
  181.      * class is created.  The initializer for that class is passed a
  182.      * reference to the applet and the remainder of the attribute
  183.      * string, from which the class should retrieve any information it
  184.      * needs about the area it controls and the actions it needs to
  185.      * take within that area.
  186.      */
  187.     public void init() {
  188.     String s;
  189.  
  190.     tracker = new MediaTracker(this);
  191.     parseHighlight(getParameter("highlight"));
  192.     introTune = getParameter("startsound");
  193.     baseImage = getImage(getDocumentBase(), getParameter("img"));
  194.     Vector areaVec = new Vector();
  195.     int num = 1;
  196.     while (true) {
  197.         ImageMapArea newArea;
  198.         s = getParameter("area"+num);
  199.         if (s == null) {
  200.         // Try rect for backwards compatibility.
  201.         s = getParameter("rect"+num);
  202.         if (s == null) {
  203.             break;
  204.         }
  205.         try {
  206.             newArea = new HighlightArea();
  207.             newArea.init(this, s);
  208.             areaVec.addElement(newArea);
  209.             String url = getParameter("href"+num);
  210.             if (url != null) {
  211.             s += "," + url;
  212.             newArea = new LinkArea();
  213.             newArea.init(this, s);
  214.             areaVec.addElement(newArea);
  215.             }
  216.         } catch (Exception e) {
  217.             System.out.println("error processing: "+s);
  218.             e.printStackTrace();
  219.             break;
  220.         }
  221.         } else {
  222.         try {
  223.             int classend = s.indexOf(",");
  224.             String name = s.substring(0, classend);
  225.             newArea = (ImageMapArea) Class.forName(name).newInstance();
  226.             s = s.substring(classend+1);
  227.             newArea.init(this, s);
  228.             areaVec.addElement(newArea);
  229.         } catch (Exception e) {
  230.             System.out.println("error processing: "+s);
  231.             e.printStackTrace();
  232.             break;
  233.         }
  234.         }
  235.         num++;
  236.     }
  237.     areas = new ImageMapArea[areaVec.size()];
  238.     areaVec.copyInto(areas);
  239.     checkSize();
  240.     addMouseListener(this);
  241.     addMouseMotionListener(this);
  242.     }
  243.  
  244.     public void destroy() {
  245.         removeMouseListener(this);
  246.         removeMouseMotionListener(this);
  247.     }
  248.  
  249.     Thread aniThread = null;
  250.     String introTune = null;
  251.  
  252.     public void start() {
  253.     if (introTune != null)
  254.         try {
  255.         play(new URL(getDocumentBase(), introTune));
  256.         } catch (MalformedURLException e) {}
  257.     if (aniThread == null) {
  258.             aniThread = new Thread(this);
  259.             aniThread.setName("ImageMap Animator");
  260.             aniThread.start();
  261.     }
  262.     }
  263.  
  264.     public void run() {
  265.     Thread me = Thread.currentThread();
  266.     tracker.checkAll(true);
  267.     for (int i = areas.length; --i >= 0; ) {
  268.         areas[i].getMedia();
  269.     }
  270.     me.setPriority(Thread.MIN_PRIORITY);
  271.     while (aniThread == me) {
  272.         boolean animating = false;
  273.         for (int i = areas.length; --i >= 0; ) {
  274.         animating = areas[i].animate() || animating;
  275.         }
  276.         try {
  277.         synchronized(this) {
  278.             wait(animating ? 100 : 0);
  279.         }
  280.         } catch (InterruptedException e) {
  281.         break;
  282.         }
  283.     }
  284.     }
  285.  
  286.     public synchronized void startAnimation() {
  287.     notify();
  288.     }
  289.  
  290.     public synchronized void stop() {
  291.     aniThread = null;
  292.     notify();
  293.     for (int i = 0; i < areas.length; i++) {
  294.         areas[i].exit();
  295.     }
  296.     }
  297.  
  298.     /**
  299.      * Check the size of this applet while the image is being loaded.
  300.      */
  301.     void checkSize() {
  302.     int w = baseImage.getWidth(this);
  303.     int h = baseImage.getHeight(this);
  304.     if (w > 0 && h > 0) {
  305.         resize(w, h);
  306.         synchronized(this) {
  307.         fullrepaint = true;
  308.         }
  309.         repaint(0, 0, w, h);
  310.     }
  311.     }
  312.  
  313.     private boolean fullrepaint = false;
  314.     private final static long UPDATERATE = 100;
  315.  
  316.     /**
  317.      * Handle updates from images being loaded.
  318.      */
  319.     public boolean imageUpdate(Image img, int infoflags,
  320.                    int x, int y, int width, int height) {
  321.     if ((infoflags & (WIDTH | HEIGHT)) != 0) {
  322.         checkSize();
  323.     }
  324.     if ((infoflags & (SOMEBITS | FRAMEBITS | ALLBITS)) != 0) {
  325.         synchronized(this) {
  326.         fullrepaint = true;
  327.         }
  328.         repaint(((infoflags & (FRAMEBITS | ALLBITS)) != 0)
  329.             ? 0 : UPDATERATE,
  330.             x, y, width, height);
  331.     }
  332.     return (infoflags & (ALLBITS | ERROR)) == 0;
  333.     }
  334.  
  335.     /**
  336.      * Paint the image and all active highlights.
  337.      */
  338.     public void paint(Graphics g) {
  339.     synchronized(this) {
  340.         fullrepaint = false;
  341.     }
  342.     if (baseImage == null) {
  343.         return;
  344.     }
  345.     g.drawImage(baseImage, 0, 0, this);
  346.     if (areas != null) {
  347.         for (int i = areas.length; --i >= 0; ) {
  348.         areas[i].highlight(g);
  349.         }
  350.     }
  351.     }
  352.  
  353.     /**
  354.      * Update the active highlights on the image.
  355.      */
  356.     public void update(Graphics g) {
  357.     boolean full;
  358.     synchronized(this) {
  359.         full = fullrepaint;
  360.     }
  361.     if (full) {
  362.         paint(g);
  363.         return;
  364.     }
  365.     if (baseImage == null) {
  366.         return;
  367.     }
  368.     g.drawImage(baseImage, 0, 0, this);
  369.     if (areas == null) {
  370.         return;
  371.     }
  372.     // First unhighlight all of the deactivated areas
  373.     for (int i = areas.length; --i >= 0; ) {
  374.         areas[i].highlight(g);
  375.     }
  376.     }
  377.  
  378.       int pressX;
  379.       int pressY;
  380.  
  381.   public void mouseClicked(MouseEvent e)
  382.   {}
  383.  
  384.       /**
  385.        * Inform all active ImageAreas of a mouse press.
  386.        */
  387.   public void mousePressed(MouseEvent e)
  388.   {
  389.     pressX = e.getX();
  390.     pressY = e.getY();
  391.  
  392.     for (int i = 0; i < areas.length; i++) {
  393.       if (areas[i].inside(pressX, pressY)) {
  394.     if (areas[i].press(pressX, pressY)) {
  395.       break;
  396.     }
  397.       }
  398.     }
  399.     e.consume();
  400.   }
  401.  
  402.       /**
  403.        * Inform all active ImageAreas of a mouse release.
  404.        * Only those areas that were inside the original mousePressed()
  405.        * are informed of the mouseReleased.
  406.        */
  407.   public void mouseReleased(MouseEvent e)
  408.   {
  409.     for (int i = 0; i < areas.length; i++) {
  410.       if (areas[i].inside(pressX, pressY)) {
  411.     if (areas[i].lift(e.getX(), e.getY())) {
  412.       break;
  413.     }
  414.       }
  415.     }
  416.     e.consume();
  417.   }
  418.  
  419.   public void mouseEntered(MouseEvent e)
  420.   {}
  421.  
  422.       /**
  423.        * Make sure that no ImageAreas are highlighted.
  424.        */
  425.   public void mouseExited(MouseEvent e) {
  426.     for (int i = 0; i < areas.length; i++) {
  427.       areas[i].checkExit();
  428.     }
  429.     e.consume();
  430.   }
  431.  
  432.  
  433.       /**
  434.        * Inform all active ImageAreas of a mouse drag.
  435.        * Only those areas that were inside the original mouseDown()
  436.        * are informed of the mouseUp.
  437.        */
  438.  
  439.   public void mouseDragged(MouseEvent e)
  440.   {
  441.     mouseMoved(e);
  442.     for (int i = 0; i < areas.length; i++) {
  443.       if (areas[i].inside(pressX, pressY)) {
  444.     if (areas[i].drag(e.getX(), e.getY())) {
  445.       break;
  446.     }
  447.       }
  448.     }
  449.     e.consume();
  450.   }
  451.  
  452.       /**
  453.        * Find the ImageAreas that the mouse is in.
  454.        */
  455.   public void mouseMoved(MouseEvent e) {
  456.     boolean eaten = false;
  457.  
  458.     for (int i = 0; i < areas.length; i++) {
  459.       if (!eaten && areas[i].inside(e.getX(), e.getY())) {
  460.     eaten = areas[i].checkEnter(e.getX(), e.getY());
  461.       } else {
  462.     areas[i].checkExit();
  463.       }
  464.     }
  465.     e.consume();
  466.   }
  467.  
  468.     /**
  469.      * Scan all areas looking for the topmost status string.
  470.      */
  471.     public void newStatus() {
  472.     String msg = null;
  473.     for (int i = 0; i < areas.length; i++) {
  474.         msg = areas[i].getStatus(msg);
  475.     }
  476.     showStatus(msg);
  477.     }
  478.  
  479.   public String getAppletInfo() {
  480.     return "Title: ImageMap \nAuthor: Jim Graham \nAn extensible ImageMap applet class. \nThe active areas on the image are controlled by ImageArea \nclasses that can be dynamically loaded over the net.";
  481.   }
  482.  
  483.   public String[][] getParameterInfo() {
  484.     String[][] info = {
  485.       {"area[n]", "delimited string",
  486. "This parameter takes the form of <ImageAreaClassName>, <ul>, <ur>, <ll>, <lr>, <action> where ImageAreaClassName is the name of the class from which this feedback area is controlled, the next four arguments are the four corners of the "
  487. + " feedback zone, and the final argument is that action that should be taken on click or mouseover.  That action can be 1) display text in the status bar (if you provide a string argument), 2) play a sound (if you provide the path to a sound file), or 3) load a page (if you provide a URL)."},
  488.       {"rect[n]", "delimited string", "Deprecated: use area[n]"},
  489.       {"href[n]", "URL string", "Pass in a URL to create a LinkArea which will point to this URL.  Not used in these examples."},
  490.       {"highlight", "string/int", "Pass the word 'brighter' followed by an integer 'n' to change the highlight mode to brighter and the hightlight percentage to n.  Pass the word 'darker' followed by an integer 'm' to change the highlight mode to darker and the highlight percentage to m.  Anything else will be ignored.  The default highlight mode is BRIGHTER and the default highlight percentage is 50."},
  491.       {"startsound", "path string", "The path of a soundclip to play when the image is first displayed."},
  492.       {"img", "path string", "The path to the image to be displayed as a live feedback image map."}
  493.     };
  494.     return info;
  495.   }
  496. }
  497.  
  498.  
  499.  
  500.