home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Internet / Javadraw / DATA.Z / javex.java < prev    next >
Text File  |  1995-10-08  |  18KB  |  543 lines

  1. /*
  2.  * javex.java - 19 Jan 1996 - Version 1.03
  3.  *
  4.  * Note: This source code is subject to perpetual refinement!
  5.  *
  6.  * Copyright 1996 by Bill Giel
  7.  *
  8.  * E-mail: rvdi@usa.nai.net
  9.  * WWW: http://www.nai.net/~rvdi/home.htm
  10.  *
  11.  *
  12.  * Revision 1.01 - revised hms class to calculate GMT. This permits the clock
  13.  * 10 Feb 96       to be used to display the time at any location by supplying
  14.  *                 a TIMEZONE parameter in the HTML call.
  15.  *
  16.  * Revision 1.02 - revised timezone to accept real numbers, for places like
  17.  * 11 Feb 96       India, with a 5.5 hour time difference. I learn something
  18.  *                 new everyday!
  19.  *
  20.  * Revision 1.03 - fixed loop in run() to exit if clockThread==null, rather
  21.  *                 than simple for(;;)
  22.  *
  23.  * Usage:
  24.  *
  25.  *
  26.  * Permission to use, copy, modify, and distribute this software
  27.  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
  28.  * without fee is hereby granted, provided that any use properly credits
  29.  * the author, i.e. "Javex Clock courtesy of <A HREF="mailto:rvdi@usa.nai.net">
  30.  * Bill Giel</A>.
  31.  * 
  32.  * 
  33.  * THE AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
  34.  * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  35.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  36.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHOR SHALL NOT BE LIABLE
  37.  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  38.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  39.  * 
  40.  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
  41.  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
  42.  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
  43.  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
  44.  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
  45.  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
  46.  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). YOU WOULD
  47.  * HAVE TO BE OUT OF YOUR MIND TO USE THIS SOFTWARE IN A HIGH-RISK ENVIRONMENT
  48.  * AND, AS SUCH MAY BE THE CASE,  THE AUTHOR SPECIFICALLY DISCLAIMS ANY EXPRESS
  49.  * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES, INCLUDING BUT NOT
  50.  * LIMITED TO USE OR MISUSE OF THIS SOFTWARE RESULTING IN NUCLEAR EXPLOSIONS,
  51.  * GLOBAL WARMING OR OZONE-LAYER DEPLETION.
  52.  */
  53.  
  54.  
  55.  
  56. import java.awt.*;
  57. import java.applet.*;
  58. import java.lang.*;
  59. import java.util.*;
  60. import java.net.*;
  61.  
  62. class hms extends Date
  63. {
  64.     //Note that localOffset is hours difference from GMT
  65.     //west of Greenwich meridian is positive, east is negative.
  66.     //i.e. New York City (Eastern Standard Time) is +5
  67.     //     Eastern Daylight Time is +4
  68.     
  69.     public hms(double localOffset){
  70.         super();
  71.         long tzOffset=getTimezoneOffset()*60L*1000L;
  72.         setTime(getTime() + tzOffset - (long)(localOffset*3600.0*1000.0));
  73.     }
  74.  
  75.     public double get_hours()
  76.     {
  77.         return (double)super.getHours()+(double)getMinutes()/60.0;
  78.     }
  79. }
  80.  
  81. abstract class clockHand
  82. {
  83.     protected int baseX[], baseY[];
  84.     protected int transX[],transY[];
  85.     protected int numberOfPoints;
  86.  
  87.     public clockHand(int originX, int originY, int length,int thickness,int points){
  88.         baseX= new int[points]; baseY=new int[points];
  89.         transX= new int[points]; transY=new int[points];
  90.         initiallizePoints(originX,originY,length,thickness);
  91.         numberOfPoints=points;
  92.     }
  93.  
  94.     abstract protected void initiallizePoints(  int originX,
  95.                                                 int originY,
  96.                                                 int length,
  97.                                                 int thickness);
  98.                                                 
  99.     abstract public void draw(Color color, double angle, Graphics g);
  100.  
  101.     protected void transform(double angle)
  102.     {
  103.         for(int i=0;i<numberOfPoints;i++){
  104.             transX[i]=(int)(    (baseX[0]-baseX[i]) * Math.cos(angle) -
  105.                                 (baseY[0]-baseY[i]) * Math.sin(angle) +
  106.                                  baseX[0]);
  107.                                  
  108.             transY[i]=(int)(    (baseX[0]-baseX[i]) * Math.sin(angle) +
  109.                                 (baseY[0]-baseY[i]) * Math.cos(angle) +
  110.                                  baseY[0]);
  111.         }
  112.     }
  113. }
  114.  
  115. class sweepHand extends clockHand
  116. {
  117.     public sweepHand(int originX,int originY, int length, int points)
  118.     {
  119.         super(originX,originY,length,0,points);
  120.     }
  121.  
  122.     protected void initiallizePoints(int originX,int originY, int length, int unused)
  123.     {
  124.         unused=unused;  //We don't use the thickness parameter in this class
  125.                         //This comes from habit to prevent compiler warning
  126.                         //concerning unused arguments.
  127.         
  128.         baseX[0]=originX; baseY[0]=originY;
  129.         baseX[1]=originX; baseY[1]=originY-length/5;
  130.         baseX[2]=originX; baseY[2]=originY+length;
  131.     }
  132.  
  133.     public void draw(Color color, double angle, Graphics g)
  134.     {
  135.         transform(angle);
  136.         g.setColor(color);
  137.         g.drawLine(transX[1],transY[1],transX[2],transY[2]);
  138.     }    
  139. }
  140.  
  141. class hmHand extends clockHand
  142. {
  143.     public hmHand(int originX,int originY, int length,int thickness, int points){
  144.         super(originX,originY,length,thickness,points);
  145.     }    
  146.  
  147.     protected void initiallizePoints(   int originX,
  148.                                         int originY,
  149.                                         int length,
  150.                                         int thickness)
  151.     {
  152.         baseX[0]=originX;
  153.         baseY[0]=originY;
  154.         
  155.         baseX[1]=baseX[0]-thickness/2;
  156.         baseY[1]=baseY[0]+thickness/2;
  157.         
  158.         baseX[2]=baseX[1];
  159.         baseY[2]=baseY[0]+length- thickness;
  160.         
  161.         baseX[3]=baseX[0];
  162.         baseY[3]=baseY[0]+length;
  163.         
  164.         baseX[4]=baseX[0]+thickness/2;
  165.         baseY[4]=baseY[2];
  166.         
  167.         baseX[5]=baseX[4];
  168.         baseY[5]=baseY[1];
  169.     }
  170.  
  171.     public void draw(Color color,double angle, Graphics g)
  172.     {
  173.         transform(angle);
  174.         g.setColor(color);
  175.         g.fillPolygon(transX,transY,numberOfPoints);
  176.     }
  177. }
  178.  
  179. public class Javex extends Applet implements Runnable
  180. {
  181. //JAVADRAW Wizard.Cut.Start
  182. String AText = "SFS Software";
  183. Font AFont = new Font ("TimesRoman", Font.PLAIN, 10);
  184. Color ABackgroundcolor = Color.black;
  185. Color AFacecolor = Color.green;
  186. Color ASweepcolor = Color.white;
  187. Color AMinutecolor = Color.red;
  188. Color AHourcolor = Color.magenta;
  189. Color ATextcolor = Color.black;
  190. Color ACasecolor = Color.gray;
  191. Color ATrimcolor = Color.pink;
  192. int width = 100;
  193. int height = 100;
  194. //JAVADRAW Wizard.Cut.End
  195.     static final int BACKGROUND=0;              //Background image index
  196.     static final int LOGO=1;                    //Logo image index
  197.     static final double MINSEC=0.104719755;     //Radians per minute or second
  198.     static final double HOUR=0.523598776;       //Radians per hour
  199.  
  200.     Thread clockThread = null;
  201.  
  202.     //User options, see getParameterInfo(), below.
  203.     
  204.    
  205.     String logoString=null;
  206.     
  207.     Image images[] = new Image[2]; //Array to hold optional images
  208.  
  209.     boolean isPainted=false; //Force painting on first update, if not painted
  210.  
  211.     //Center point of clock
  212.     int x1,y1;
  213.  
  214.     //Array of points for triangular icon at 12:00
  215.     int xPoints[]=new int[3], yPoints[]=new int[3];
  216.  
  217.     //Class to hold time, with method to return (double)(hours + minutes/60)
  218.     hms cur_time;
  219.  
  220.     //The clock's seconds, minutes, and hours hands.
  221.     sweepHand sweep;
  222.     hmHand  minuteHand,
  223.             hourHand;
  224.  
  225.     //The last parameters used to draw the hands.
  226.     double lastHour;
  227.     int lastMinute,lastSecond;
  228.  
  229.     
  230.     //Offscreen image and device context, for buffered output.
  231.     Image offScrImage;
  232.     Graphics offScrGC;
  233.  
  234.     // Use to test background image, if any.
  235.     MediaTracker tracker;
  236.  
  237.    
  238.     int minDimension;   // Ensure a round clock if applet is not square.
  239.     int originX;        // Upper left corner of a square enclosing the clock
  240.     int originY;        // with respect to applet area.
  241.  
  242.     double tzDifference=0;
  243.     
  244.  
  245.     //Users' parameters - self-explanatory?
  246.     public String[][] getParameterInfo()
  247.     {
  248.         String[][] info = {
  249.             {"bgImageURL",  "string",   "URL of background image, if any <null>"},
  250.             {"logoString",  "string",   "Name to display on watch face <JAVEX>"},
  251.             {"logoImageURL","string",   "URL of logo image to display on watch face <null>"},
  252.             {"timezone",    "real",      "Timezone difference from GMT (decimal hours,+ West/- East)<0>"},    
  253.         };
  254.         return info;
  255.     }
  256.  
  257.     //Applet name, author and info lines
  258.     public String getAppletInfo()
  259.     {
  260.         return "JAVEX 1.03 - analog clock applet by Bill Giel, 2 Mar 96\nhttp://www.nai.net/~rvdi/home.htm  or  rvdi@usa.nai.net";
  261.     }
  262.  
  263.     void showURLerror(Exception e)
  264.     {
  265.         String errorMsg = "JAVEX URL error: "+e;
  266.         showStatus(errorMsg);
  267.         System.err.println(errorMsg);
  268.     }
  269.  
  270.     // This lets us create clocks of various sizes, but with the same
  271.     // proportions.
  272.     private int size(int percent)
  273.     {
  274.         return (int)((double)percent/100.0 * (double)minDimension);
  275.     }
  276.  
  277.     public void init()
  278.     {
  279.         URL imagesURL[] = new URL[2];
  280.         String szImagesURL[] = new String[2];
  281.         tracker = new MediaTracker(this);
  282.                 
  283.         String paramString    = getParameter( "WIDTH"  );
  284.         if( paramString != null )
  285.             width = Integer.valueOf(paramString).intValue();
  286.             
  287.         paramString   = getParameter( "HEIGHT" );
  288.         if( paramString != null )
  289.             height = Integer.valueOf(paramString).intValue();
  290.  
  291.        paramString   = getParameter( "TIMEZONE" );
  292.         if( paramString != null )
  293.             tzDifference = Double.valueOf(paramString).doubleValue();            
  294.             
  295.         logoString  = getParameter( "LOGOSTRING");
  296.         if( logoString == null )
  297.             logoString=AText;
  298.         else if(logoString.length() > 8)
  299.             logoString= logoString.substring(0,8); //Max 8 characters!
  300.         
  301.         szImagesURL[BACKGROUND]  = getParameter("BGIMAGEURL");
  302.         szImagesURL[LOGO] = getParameter("LOGOIMAGEURL");
  303.  
  304.         for(int i=0; i<2; i++){
  305.             if(szImagesURL[i] != null){
  306.                 try{
  307.                     imagesURL[i]=new URL(getDocumentBase(),szImagesURL[i]);
  308.                 } catch (MalformedURLException e)
  309.                     {
  310.                         showURLerror(e);
  311.                         imagesURL[i]=null;
  312.                         images[i]=null;
  313.                     }
  314.                 if(imagesURL[i] != null){
  315.                     showStatus("Javex loading image: " + imagesURL[i].toString());
  316.                     images[i]=getImage(imagesURL[i]);
  317.                     if(images[i] != null)
  318.                         tracker.addImage(images[i],i);    
  319.                     showStatus("");                        
  320.                 }
  321.                 if(images[i] != null)
  322.                     try{
  323.                         tracker.waitForID(i);
  324.                     }catch (InterruptedException e)
  325.                         {
  326.                             images[i]=null;
  327.                         }
  328.             }
  329.             else images[i]=null;
  330.         }
  331.         
  332.         cur_time=new hms(tzDifference);
  333.         lastHour=-1.0;
  334.         lastMinute=-1;
  335.         lastSecond=-1;
  336.  
  337.         x1=width/2;
  338.         y1=height/2;
  339.  
  340.         minDimension= Math.min(width, height);
  341.         originX=(width-minDimension)/2;
  342.         originY=(height-minDimension)/2;
  343.  
  344.         xPoints[1]=x1-size(3); xPoints[2]=x1+size(3); xPoints[0]=x1;
  345.         yPoints[1]=y1-size(38);yPoints[2]=y1-size(38); yPoints[0]=y1-size(27);
  346.  
  347.         sweep=new sweepHand(x1,y1,size(40),3);
  348.         minuteHand=new hmHand(x1,y1,size(40),size(6),6);
  349.         hourHand=new hmHand(x1,y1,size(25),size(8),6);
  350.  
  351.      
  352.  
  353.         offScrImage = createImage(width,height);
  354.         offScrGC = offScrImage.getGraphics();
  355.     }
  356.  
  357.     public void start()
  358.     {
  359.         if(clockThread == null){
  360.             clockThread = new Thread(this);
  361.             clockThread.start();
  362.         }
  363.     }
  364.  
  365.     public void stop()
  366.     {
  367.         if(null != clockThread){
  368.             clockThread.stop();
  369.             clockThread=null;
  370.         }
  371.     }
  372.     
  373.     private void drawHands(Graphics g)
  374.     {
  375.     
  376.         double angle;
  377.         int i,j;
  378.         int x,y;
  379.     
  380.         angle=MINSEC * lastSecond;
  381.         sweep.draw(AFacecolor, angle, g);
  382.  
  383.         if(cur_time.getMinutes() != lastMinute){
  384.             minuteHand.draw(AFacecolor,MINSEC*lastMinute,g);
  385.             if(cur_time.get_hours() != lastHour)
  386.                 hourHand.draw(AFacecolor,HOUR*lastHour,g);
  387.         }
  388.  
  389.         g.setColor(ATextcolor);
  390.         g.fillRect(originX+size(12),y1-size(2),size(10),size(4));
  391.         g.fillRect(x1-size(2),originY + minDimension-size(22),size(4),size(10));
  392.         g.fillPolygon( xPoints, yPoints, 3);
  393.         for(i=1;i<12;i+=3)
  394.             for(j=i;j<i+2;j++){
  395.                 x=(int)(x1+Math.sin(HOUR*j)*size(35));
  396.                 y=(int)(y1-Math.cos(HOUR*j)*size(35));
  397.                 g.fillOval(x-size(3),y-size(3),size(6),size(6));
  398.             }
  399.  
  400.         //Set the font and get font info...
  401.         g.setFont(AFont);
  402.         FontMetrics fm=g.getFontMetrics();
  403.  
  404.         //Paint our logo...
  405.         g.drawString(logoString,x1-fm.stringWidth(logoString)/2,y1-size(12));
  406.  
  407.         //Get the day of the month...
  408.         String day=Integer.toString(cur_time.getDate(),10);
  409.         
  410.         //Paint it...
  411.         g.drawString(   day,
  412.                         originX + minDimension-size(14)-fm.stringWidth(day),
  413.                         y1+size(5));
  414.  
  415.         //and put a box around it.                        
  416.         g.drawRect( originX + minDimension-size(14)-fm.stringWidth(day)-size(2),
  417.                     y1-size(5)-size(2),
  418.                     fm.stringWidth(day)+size(4),
  419.                     size(10)+size(4));
  420.  
  421.         if(images[LOGO] != null){
  422.             x = originX + (minDimension-images[LOGO].getWidth(this))/2;
  423.             y = y1 + (minDimension/2 - size(22) - images[LOGO].getHeight(this))/2;
  424.             if(x > 0 && y > 0)
  425.                 offScrGC.drawImage(images[LOGO], x, y, this);
  426.         }
  427.  
  428.         lastHour=cur_time.get_hours();
  429.         hourHand.draw(AHourcolor,HOUR*lastHour,g);
  430.         
  431.         lastMinute=cur_time.getMinutes();
  432.         minuteHand.draw(AMinutecolor,MINSEC*lastMinute,g);        
  433.  
  434.         g.setColor(AMinutecolor);
  435.         g.fillOval(x1-size(4),y1-size(4),size(8),size(8));
  436.         g.setColor(ASweepcolor);
  437.         g.fillOval(x1-size(3),y1-size(3),size(6),size(6));
  438.  
  439.         lastSecond=cur_time.getSeconds();        
  440.         angle=MINSEC*lastSecond;
  441.         sweep.draw(ASweepcolor, angle,g);
  442.  
  443.         g.setColor(ATrimcolor);
  444.         g.fillOval(x1-size(1),y1-size(1),size(2),size(2));        
  445.     }
  446.  
  447.     private Color parseColorString(String colorString)
  448.     {
  449.         if(colorString.length()==6){
  450.             int R = Integer.valueOf(colorString.substring(0,2),16).intValue();
  451.             int G = Integer.valueOf(colorString.substring(2,4),16).intValue();
  452.             int B = Integer.valueOf(colorString.substring(4,6),16).intValue();
  453.             return new Color(R,G,B);
  454.         }
  455.         else return Color.lightGray;
  456.     }
  457.     
  458.     public void run()
  459.     {
  460.         //Let's not hog the system, now...
  461.         Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
  462.         
  463.         repaint();
  464.         while(null != clockThread){
  465.             cur_time=new hms(tzDifference);
  466.             repaint();
  467.             try{
  468.                 Thread.sleep(1000);
  469.             } catch (InterruptedException e) {}            
  470.         }
  471.         System.exit(0);
  472.     }
  473.  
  474.     public void paint(Graphics g)
  475.     {
  476.         int i,x0,y0,x2,y2;
  477.  
  478.         if(images[BACKGROUND] == null){
  479.             offScrGC.setColor(ABackgroundcolor);
  480.             offScrGC.fillRect(0,0,width,height);
  481.         }
  482.         else
  483.             offScrGC.drawImage(images[BACKGROUND], 0, 0, this);
  484.  
  485.         offScrGC.setColor(ACasecolor);
  486.  
  487.         //Shrink one pixel so we don't clip anything off...
  488.         offScrGC.fillOval(  originX+1,
  489.                             originY+1,
  490.                             minDimension-2,
  491.                             minDimension-2);
  492.         
  493.         offScrGC.setColor(AFacecolor);
  494.         offScrGC.fillOval(  originX + size(5),
  495.                             originY + size(5),
  496.                             minDimension - size(10),
  497.                             minDimension - size(10));
  498.                             
  499.         offScrGC.setColor(ATrimcolor);
  500.         offScrGC.drawOval(  originX+1,
  501.                             originY+1,
  502.                             minDimension-2,
  503.                             minDimension-2);
  504.                             
  505.         offScrGC.drawOval(  originX + size(5),
  506.                             originY + size(5),
  507.                             minDimension - size(10),
  508.                             minDimension - size(10));
  509.                             
  510.         offScrGC.setColor(ATextcolor);
  511.  
  512.         //Draw graduations, a longer index every fifth mark...
  513.         for(i=0;i<60;i++){
  514.             if(i==0 || (i>=5 && i%5 == 0)){
  515.                 x0=(int)(x1+size(40)*Math.sin(MINSEC*i));
  516.                 y0=(int)(y1+size(40)*Math.cos(MINSEC*i));
  517.             }
  518.             else{
  519.                 x0=(int)(x1+size(42)*Math.sin(MINSEC*i));
  520.                 y0=(int)(y1+size(42)*Math.cos(MINSEC*i));
  521.             }
  522.             x2=(int)(x1+size(44)*Math.sin(MINSEC*i));
  523.             y2=(int)(y1+size(44)*Math.cos(MINSEC*i));
  524.             offScrGC.drawLine(x0,y0,x2,y2);
  525.         }
  526.         
  527.         drawHands(offScrGC);
  528.         g.drawImage(offScrImage,0,0,this);
  529.  
  530.         isPainted=true;
  531.     }
  532.  
  533.     public synchronized void update(Graphics g)
  534.     {
  535.         if(!isPainted)
  536.             paint(g);
  537.         else{
  538.             drawHands(offScrGC);
  539.             g.drawImage(offScrImage,0,0,this);
  540.         }
  541.     }
  542. }
  543.