/* * DigitalClock.java V2.0 10/20/96 * * Copyright (c) 1996-7 H.J. Tsai, Inc. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for any purposes and without * fee is hereby granted provided that this copyright notice * appears in all copies. * * H.J. Tsai 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. H.J. Tsai SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * * Author: H.J. Tsai hjtsai@cargobay.com * * Version 2.1a Feb 21, 1999 * Modified the parameter names match the document * * Version 2.1 Sep 9, 1997 * Added option to disable copyright * Added work around for NS 4.0 date string problem * Added support to not display seconds * * Version 2.0 Oct 20, 1996 * Added many new options * - a real, useful clock now * * Version 1.0 Sep 08, 1996 * Initial Version * - just for fun */ import java.util.*; import java.awt.*; import java.applet.*; public class DigitalClock extends Clock { // Date position when displayed protected String clockname = "DigitalClock 97"; protected String clocksmith = "Copyright 1997 The Java ClockShop"; // Date position when displayed private static final int DP_DATETIME = 1; private static final int DP_TIMEDATE = 2; private static final int DP_TIMEOVERDATE = 3; private static final int DP_DATEOVERTIME = 4; // Fields for program parameters protected int radix = 10; protected boolean show24Hours = false; protected boolean showSeconds = true; protected String clockFontName = "TimesRoman"; protected int clockFontStyle = Font.PLAIN; protected int clockFontSize = 14; protected Color clrClockForeground = Color.black; protected Color clrClockBackground = Color.lightGray; protected boolean showFrame = true; protected Color clrFrame = Color.lightGray; protected int frameThickness = 5; protected int frameStyle = Rect.RS_NORMAL; private int outBevel = 0; private int outBevelStyle = Rect.RS_NORMAL; private int inBevel = 0; private int inBevelStyle = Rect.RS_NORMAL; protected boolean showDate = true; protected Color clrDate = Color.green; protected int dateposition = DP_DATETIME; protected String dateFontName = "Helvetic"; protected int dateFontStyle = Font.ITALIC; protected int dateFontSize = 12; // program options protected boolean showZoneTime = true; /// false; protected long tzdiff = 0L; // diff between local and target zone in ms protected int tztarget; // diff between GMT and target zone in minutes // clock dependent variables - vary with the radices // derived class should provide its own values protected int maxHourlen; protected int maxMinlen; protected int maxSeclen; protected String colon; // internal runtime variables private String sHours = null; private String sMinutes = null; private String sSeconds = null; private Font fontClock; private Font fontDate; private boolean showCopyright = true; private RectFrame rectFrame; private Rect rectClock; private Image memImage; private int lasts = -1; private int lastm = -1; private int lasth = -1; /* * Applet entry point */ public void init() { // call Clock.init() super.init(); // get program options getProgramParams(); Rectangle r = bounds(); memImage = createImage(r.width, r.height); if (showFrame) { rectFrame = new RectFrame(r, outBevel, outBevelStyle, frameThickness, frameStyle, clrFrame, inBevel, inBevelStyle); rectClock = rectFrame.getInsideRect(); } else { rectClock = new Rect(r); } // get the fonts to be used fontClock = new Font(clockFontName, clockFontStyle, clockFontSize); fontDate = new Font(dateFontName, dateFontStyle, dateFontSize); // set the digits related values for the clock, since the clock can // be a binary, a ternary,...clock setDigitsForClock(radix); if (showZoneTime) { super.setTimezoneDiff(tztarget); } } /* * Applet starts running */ public void start() { show(); super.start(); } /* * Applet stops running */ public void stop() { super.stop(); } public void tick() { repaint(); } public void update(Graphics g) { // update the clock in offscreen memory image Graphics memg = memImage.getGraphics(); paint(memg); // copy the offscreen image to the real screen g.drawImage(memImage, 0, 0, null); } /* * Paints the clock * painting is done by erasing the whole clock and * repaint everything even when only the 'seconds' needs * to be updated. If you change this, change update() too. */ public void paint(Graphics g) { if (showCopyright) { showCopyright(g, clockname, clocksmith); showCopyright = false; return; } int s = getDisplaySeconds(); int m = getDisplayMinutes(); int h = getDisplayHours(); //System.err.println("h="+h + " m="+m + " s="+s); sSeconds = i2a(s, maxSeclen, '0'); if (lastm != m) { lastm = m; sMinutes = i2a(m, maxMinlen, '0'); } if (lasth != h) { lasth = h; if ((h > 12) && (show24Hours == false)) h -= 12; sHours = i2a(h, maxHourlen, ' '); } // now paint // erase the old time Dimension d = size(); g.setColor(clrClockBackground); g.fillRect(0, 0, d.width, d.height); drawFrame(g); String hhmmss = sHours + colon + sMinutes; if (showSeconds) hhmmss += colon + sSeconds; if (showDate) { int yy = getDisplayYear(); int mm = getDisplayMonth(); int dd = getDisplayDay(); String yymmdd = getLocaleDateString(yy,mm,dd); if (dateposition == DP_DATETIME || dateposition == DP_TIMEDATE) drawDateTimeOnSameLine(g, yymmdd, hhmmss); else drawDateTime(g, yymmdd, hhmmss); } else { drawTime(g, hhmmss); } } /* * Draws current time: hhmmss */ public void drawTime(Graphics g, String hhmmss) { g.setFont(fontClock); FontMetrics fm = g.getFontMetrics(); int sWidth = fm.stringWidth(hhmmss); int sHeight = fm.getAscent(); g.setColor(clrClockForeground); g.drawString(hhmmss, rectClock.x + (rectClock.width - sWidth)/2, rectClock.y + (rectClock.height + sHeight)/2); } /* * Draw the locale dependent date string yymmdd and Time string: hhmmss on the * same line. The date and time may use different font */ public void drawDateTimeOnSameLine(Graphics g, String yymmdd, String hhmmss) { g.setFont(fontDate); FontMetrics fm = g.getFontMetrics(); int ymdWidth = fm.stringWidth(yymmdd); int ymdHeight = fm.getAscent(); g.setFont(fontClock); fm = g.getFontMetrics(); int hmsWidth = fm.stringWidth(hhmmss); int hmsHeight = fm.getAscent(); int width = ymdWidth + hmsWidth + 10; // 10 pixels to separate the two int x1; // x1 is x coordinate for date int x2; // x2 is x coordinate for time if (dateposition == DP_DATETIME) { x1 = rectClock.x + (rectClock.width - width)/2; x2 = x1 + ymdWidth + 10; } else { x2 = rectClock.x + (rectClock.width - width)/2; x1 = x2 + hmsWidth + 10; } // draw date g.setColor(clrDate); g.setFont(fontDate); g.drawString(yymmdd, x1, rectClock.y + (rectClock.height + ymdHeight)/2); // draw time g.setColor(clrClockForeground); g.setFont(fontClock); g.drawString(hhmmss, x2, rectClock.y + (rectClock.height + hmsHeight)/2); } /* * Draws the locale dependent date string: yymmdd and * time string: hhmmss on separate lines. */ public void drawDateTime(Graphics g, String yymmdd, String hhmmss) { g.setFont(fontDate); FontMetrics fm = g.getFontMetrics(); int ymdWidth = fm.stringWidth(yymmdd); int ymdHeight = fm.getAscent(); g.setFont(fontClock); fm = g.getFontMetrics(); int hmsWidth = fm.stringWidth(hhmmss); int hmsHeight = fm.getAscent(); // draw date over time or time over date int y1; // y1 is y coordinate for date int y2; // y2 is y coordinate for time if (dateposition == DP_DATEOVERTIME) { y1 = rectClock.y + rectClock.height/2; y2 = rectClock.y + rectClock.height/2 + hmsHeight + 2; // 2 pixels vertical space } else { // Time over Date y1 = rectClock.y + rectClock.height/2 + ymdHeight + 2; y2 = rectClock.y + rectClock.height/2; } // draw date g.setColor(clrDate); g.setFont(fontDate); g.drawString(yymmdd, rectClock.x + (rectClock.width - ymdWidth)/2, y1); // draw time g.setColor(clrClockForeground); g.setFont(fontClock); g.drawString(hhmmss, rectClock.x + (rectClock.width - hmsWidth)/2, y2); } public void drawFrame(Graphics g) { if (showFrame) rectFrame.paint(g); } /* * returns the Locale dependent Date string * -- may need a better way to build the locale date string */ public String getLocaleDateString(int y, int m, int d) { String datestring = (new Date(y,m,d)).toLocaleString(); int i = datestring.lastIndexOf(' '); if (i < 0) return datestring; String datestring2 = datestring.substring(0, i); int j = datestring2.lastIndexOf(' '); if (j < 0) return datestring2; else return datestring2.substring(0, j); } /* * Gets program pamameters */ protected void getProgramParams() { // get program parameters String arg; // get digit radix radix = getNumParam("DigitRadix", 10); if (radix > Character.MAX_RADIX) radix = Character.MAX_RADIX; else if (radix < Character.MIN_RADIX) radix = Character.MIN_RADIX; arg = getParameter("Author"); if (arg != null && arg.equalsIgnoreCase("hjtsai@cargobay.com")) showCopyright = false; else showCopyright = true; // TimeZone desired in minutes arg = getParameter("TimeZone"); if (arg == null) showZoneTime = false; else { try { tztarget = Integer.parseInt(arg); //System.err.println("param timezone=" + tztarget); showZoneTime = true; } catch (NumberFormatException e) { showZoneTime = false; } } // show 24 hours format arg = getParameter("Show24Hours"); if (arg != null) show24Hours = arg.equalsIgnoreCase("yes") || arg.equalsIgnoreCase("true"); // show second arg = getParameter("ShowSeconds"); if (arg != null) showSeconds = arg.equalsIgnoreCase("yes") || arg.equalsIgnoreCase("true"); // ForegroundColor arg = getParameter("ForegroundColor"); if (arg != null) clrClockForeground = ColorValue.s2color(arg, Color.black); // BackgroundColor arg = getParameter("BackgroundColor"); if (arg != null) clrClockBackground = ColorValue.s2color(arg, Color.lightGray); // get clock font arg = getParameter("ClockFontName"); if (arg != null) clockFontName = arg; // get clock font style clockFontStyle = getfontStyleClockParam("ClockFontStyle", Font.BOLD); // get clock font pointsize clockFontSize = getNumParam("ClockFontSize", 14); if (clockFontSize < 3) clockFontSize = 3; // show clock frame arg = getParameter("ShowFrame"); if (arg != null) showFrame = arg.equalsIgnoreCase("yes") || arg.equalsIgnoreCase("true"); // clock frame color arg = getParameter("FrameColor"); if (arg != null) clrFrame = ColorValue.s2color(arg, Color.lightGray); // get clock frame thickness frameThickness = getNumParam("FrameThickness", 3); if (frameThickness < 1) frameThickness = 1; // get clock frame style frameStyle = getRectStyleParam("FrameStyle", Rect.RS_NORMAL); // get outer bevel params outBevel = getNumParam("OutBevel", 0); outBevelStyle = getRectStyleParam("OutBevelStyle", Rect.RS_NORMAL); // get in-bevel params inBevel = getNumParam("InBevel", 0); inBevelStyle = getRectStyleParam("InBevelStyle", Rect.RS_NORMAL); // show date arg = getParameter("ShowDate"); if (arg != null) showDate = arg.equalsIgnoreCase("yes") || arg.equalsIgnoreCase("true"); // Color for Date arg = getParameter("DateColor"); if (arg != null) clrDate = ColorValue.s2color(arg, clrClockForeground); // date position dateposition = getNumParam("DatePosition", DP_DATETIME); if (dateposition > 4 || dateposition < 1) dateposition = DP_DATETIME; // get font for 'date' arg = getParameter("DateFontName"); if (arg != null) dateFontName = arg; // get Date font style dateFontStyle = getfontStyleClockParam("DateFontStyle", Font.ITALIC); // get Date font pointsize dateFontSize = getNumParam("DateFontSize", 10); if (dateFontSize < 3) dateFontSize = 3; } /* * get the specified numeric programeter param, negative number now allowed */ public int getNumParam(String param, int defaultvalue) { String arg = getParameter(param); int i = 0; if (arg == null) i = defaultvalue; else { try { i = Integer.parseInt(arg); } catch (NumberFormatException e) { i = defaultvalue; } } if (i < 0) i = 0; return i; } /* * Gets the specified Font style program parameter */ public int getfontStyleClockParam(String param, int defaultvalue) { String arg = getParameter(param); int fs; if (arg == null) fs = defaultvalue; else if (arg.equalsIgnoreCase("bold")) fs = Font.BOLD; else if (arg.equalsIgnoreCase("Plain")) fs = Font.PLAIN; else if (arg.equalsIgnoreCase("Italic")) fs = Font.ITALIC; else if (arg.equalsIgnoreCase("boldItalic")) fs = Font.BOLD + Font.ITALIC; else fs = defaultvalue; return fs; } /* * Gets the specified Rect style parameter */ public int getRectStyleParam(String param, int defaultstyle) { String arg = getParameter(param); int rs; if (arg == null) rs = defaultstyle; else if (arg.equalsIgnoreCase("etchedin")) rs = Rect.RS_ETCHEDIN; else if (arg.equalsIgnoreCase("etchedout")) rs = Rect.RS_ETCHEDOUT; else if (arg.equalsIgnoreCase("raised")) rs = Rect.RS_3DRAISED; else if (arg.equalsIgnoreCase("inset")) rs = Rect.RS_3DINSET; else if (arg.equalsIgnoreCase("normal")) rs = Rect.RS_NORMAL; else rs = defaultstyle; return rs; } /* * Sets the digits to be used for the clock. The digits * are used to calc the maximum size it will occupy on the screen. * Note: the digits are assumed to be separated by ':'s */ protected void setDigitsForClock(int radix) { colon = ":"; switch (radix) { case 2: // 10111.111011:111011 maxHourlen = 5; maxMinlen = 6; maxSeclen = 6; break; case 3: // 212:2012:2012 maxHourlen = 3; maxMinlen = 4; maxSeclen = 4; break; case 4: // 113:323:323 maxHourlen =3; maxMinlen = 3; maxSeclen = 3; break; case 5: // 43:214:214 case 6: // 35:135;135 case 7: // 32:113:113 maxHourlen = 2; maxMinlen = 3; maxSeclen = 3; break; case 8: // 27:73:73 default: maxHourlen = 2; maxMinlen = 2; maxSeclen = 2; } } /* * Converts an integer n into a string of length len with * leading padding char padch applied if the length of the converted * integer is shorter then len */ protected String i2a(int n, int len, char padch) { String s = Integer.toString(n, radix); if (s.length() >= len) return s.toUpperCase(); // pad in front of the string StringBuffer sbuf = new StringBuffer(len); sbuf.setLength(len); // init to pad for (int i=0; i < len; i++) { sbuf.setCharAt(i, padch); } // insert the string s to the right place so // the last char is at the end of the buffer try { for (int i=0; i < s.length(); i++) { sbuf.setCharAt(len-s.length()+i, s.charAt(i)); } } catch (StringIndexOutOfBoundsException e) { } return sbuf.toString().toUpperCase(); } /* * Displays a copyright statement */ public void showCopyright(Graphics g, String clockname, String author) { Rectangle r = bounds(); // clear background Color c = Color.lightGray; g.setColor(c); g.fillRect(r.x, r.y, r.width, r.height); // draw a frame RectFrame rectFrame = new RectFrame(r, 2, Rect.RS_3DRAISED, 3, Rect.RS_NORMAL, Color.lightGray, 2, Rect.RS_ETCHEDIN); rectFrame.paint(g); // create the marquee for displaying copyright Rectangle newr = new Rectangle(r.x+7,r.y+7, r.width-14, r.height-14); g.clipRect(newr.x, newr.y, newr.width, newr.height); // the amount=1 and delay=5 generate fast and smooth scrolling // unfortuntely, Netscape Navigator V3.0 Java VM seems unable // to handle short delay (delay=4 is too fast) Marquee marquee = new Marquee( newr, 1, // loop 5, // 1, // amount 100, // 5, // delay Marquee.LEFT, // direction Marquee.SCROLL, // behavior clockname+" "+author, Color.lightGray, // background Color.darkGray, // foreground this); Thread mthread = new Thread(marquee); mthread.start(); // wait until the marquee thread ends while (mthread.isAlive()) { try { Thread.sleep(100); } catch (InterruptedException e) { } } mthread.stop(); mthread = null; } public String getAppletInfo() { String info = clockname + " " + clocksmith; return info; } public String [][] getParamterInfo() { String info[][] = { {"DigitRadix", "integer", "the number radix for the digits"}, {"show24Hours", "boolean", "use 24 hours format"}, {"ForegroundColor", "String", "foreground color"}, {"BackgroundColor", "String", "background color"}, {"ClockFontName", "String", "font name for the clock digits"}, {"ClockFontStyle", "String", "font style for the clock digits"}, {"ClockFontSize", "integer", "font size for the clock digits"}, {"ShowFrame", "boolean", "option to display the frame"}, {"FrameThickness", "integer", "the thickness of the clock frame"}, {"FrameStyle", "String", "various styles for the frame"}, {"FrameColor", "String", "color for the clock frame"}, {"ShowDate", "boolean", "option to display the date"}, {"DatePosition", "integer", "date position"}, {"DateColor", "String", "color for the date"}, {"DateFontName", "String", "font name for the date"}, {"DateFontStyle", "String", "style name for the date"}, {"DateFontSize", "String", "font size for the date"}, }; return info; } }