//****************************************************************************** // quotes.java: Applet // // Display a series of quotes read from a file on a colored background // "blackboard style". A quote will be copied over and over until it // cannot fit any more, then the "board" is erased and a different quote // is drawn. The quotes are supplied by a text file. // The user can set the speed, colors, font size, and whether or not to // begin each quote on a new line ("Bart Simpson style", instead of // immediately following the previous quote "Jason Fox style") and/or // to select the quotes randomly from the list (instead of using them in // order). // // Copyright © 1998 by Don Del Grande. All rights reserved (whatever that // means). // Permission is granted to use this code for your applets and to make // modifications to this applet itself, PROVIDED: // (a) You do not charge ANY sort of fee, including "costs", for this // applet, any modified version of this applet, or any applet you // develop which derives significantly from this code ("borrowing" // one or two basic concepts from this code, like "how to read // strings of text from a file without getting a SecurityException", // is OK - how else do you learn except from working examples?); // (b) If you modify this applet, you add your name (and, preferably, when // and how you modified it) to the comments and not remove any existing // names or otherwise make it appear as if you were the sole author; // (c) You do not own any bootleg "Calvin and Hobbes" or "The Simpsons" // merchandise. (Note that, except for the books, copies of the strips // themselves, and one calendar, ALL "Calvin and Hobbes" merchandise is // bootlegged. C&H author Bill Watterson owns all merchandising rights // to the characters, and refuses to merchandise them (see "The Calvin // and Hobbes Tentn Anniversary Book" for an explanation why). If you // have a T-shirt that features Calvin (in his pajamas and wearing // sunglasses) and Hobbes dancing, you are in fact in possession of // stolen property.) I'll overlook bootlegged "King of the Hill" stuff // because of this stupid "let's move the show to California" idea... // // Violators will be subject to anything from a not particularly cheerful // E-mail to branding on all appropriate newsgroups and, in severe cases, // having to listen to me drone on and on about "in my day, we didn't have // luxuries like HACK and color monitors and 300 MB PCs with 64MB of RAM; // it was ROGUE and ADM3A terminals and either waiting for a terminal in // Cory or connecting with a 300 baud modem (because even the directly // connected terminals couldn't handle anything faster than 9600)" // //****************************************************************************** import java.applet.*; import java.awt.*; import java.io.*; import java.net.*; //============================================================================== // Main Class for applet quotes // //============================================================================== public class quotes extends Applet implements Runnable { // THREAD SUPPORT: // m_quotes is the Thread object for the applet //-------------------------------------------------------------------------- private Thread m_quotes = null; // Parameters private boolean OneQuotePerLine; // (true) new line is needed after each quote? private boolean RandomQuote; // (true) quotes shown out of sequence? private int Delay; // (100) minimum delay between letters in milliseconds private int FontSize; // (24) font size (limited to 8-48) private String QuoteFileName; // ("quotes.txt") name of the quote file // note the parameter name is "File" private int BoardColor; // (0x008000) the color of the "chalkboard' // note the parameter name is "Color" private int TextColor; // (0xFFFFFF) the color of the text // Local variables private StringBuffer QuoteArray[]; private int NumQuotes; private Font F; private int Q; // current quote number private int c; // pointer to letter in current quote private boolean DrawBackground; private int TextHeight; private int MaxLines; // lines that will fit private StringBuffer Chalkboard[]; private int CurrentLine; private int AppWidth, AppHeight; // quotes Class Constructor //-------------------------------------------------------------------------- public quotes() { } // APPLET INFO SUPPORT: // The getAppletInfo() method returns a string describing the applet's // author, copyright date, or miscellaneous information. //-------------------------------------------------------------------------- public String getAppletInfo() { return "What the hell are YOU staring at?"; } // The init() method is called by the AWT when an applet is first loaded or // reloaded. Override this method to perform whatever initialization your // applet needs, such as initializing data structures, loading images or // fonts, creating frame windows, setting the layout manager, or adding UI // components. //-------------------------------------------------------------------------- public void init() { int i; String S; // If you use a ResourceWizard-generated "control creator" class to // arrange controls in your applet, you may want to call its // CreateControls() method from within this method. Remove the following // call to resize() before adding the call to CreateControls(); // CreateControls() does its own resizing. //---------------------------------------------------------------------- // get parameters QuoteFileName = "quotes.txt"; OneQuotePerLine = true; RandomQuote = true; Delay = 100; FontSize = 24; BoardColor = 0x8000; TextColor = 0xFFFFFF; if ((S = getParameter("File")) != null) QuoteFileName = S.trim(); if ((S = getParameter("OneQuotePerLine")) != null) OneQuotePerLine = new Boolean(S).booleanValue(); if ((S = getParameter("RandomQuote")) != null) RandomQuote = new Boolean(S).booleanValue(); if ((S = getParameter("Delay")) != null) { try { Delay = new Integer(S).intValue(); } catch (NumberFormatException E) { Delay = 100; } } if ((S = getParameter("FontSize")) != null) { try { FontSize = new Integer(S).intValue(); } catch (NumberFormatException E) { FontSize = 24; } } if (FontSize < 8) FontSize = 8; if (FontSize > 48) FontSize = 48; if ((S = getParameter("Color")) != null) { try { i = 0; if (S.charAt(0) == '#') i = 1; int BoardR = Integer.valueOf(S.substring(i, i+2), 16).intValue(); int BoardG = Integer.valueOf(S.substring(i+2, i+4), 16).intValue(); int BoardB = Integer.valueOf(S.substring(i+4, i+6), 16).intValue(); BoardColor = BoardR * 65536 + BoardG * 256 + BoardB; } catch (NumberFormatException E) { BoardColor = 0x8000; } } if ((S = getParameter("TextColor")) != null) { try { i = 0; if (S.charAt(0) == '#') i = 1; int TextR = Integer.valueOf(S.substring(i, i+2), 16).intValue(); int TextG = Integer.valueOf(S.substring(i+2, i+4), 16).intValue(); int TextB = Integer.valueOf(S.substring(i+4, i+6), 16).intValue(); TextColor = TextR * 65536 + TextG * 256 + TextB; } catch (NumberFormatException E) { TextColor = 0xFFFFFF; } } NumQuotes = 0; try { URL U = new URL(getDocumentBase(), QuoteFileName); DataInputStream FS = new DataInputStream(U.openStream()); while (FS.readLine() != null) NumQuotes++; FS.close(); QuoteArray = new StringBuffer[NumQuotes]; FS = new DataInputStream(U.openStream()); for (i = 0; i < NumQuotes; i++) { S = FS.readLine(); QuoteArray[i] = new StringBuffer(S.trim()); } FS.close(); } catch (MalformedURLException E) { QuoteArray = new StringBuffer[1]; NumQuotes = 0; QuoteArray[0] = new StringBuffer("Malformed URL Exception"); } catch (IOException E) { QuoteArray = new StringBuffer[1]; NumQuotes = 0; QuoteArray[0] = new StringBuffer("I/O Exception or File Does Not Exist"); } catch (SecurityException E) { QuoteArray = new StringBuffer[1]; NumQuotes = 0; QuoteArray[0] = new StringBuffer("Security Exception"); } Q = 0; if (RandomQuote && NumQuotes > 1) Q = new Double(Math.random() * NumQuotes).intValue(); c = 0; CurrentLine = 1; MaxLines = 0; // force refresh F = new Font("Helvetica", Font.PLAIN, FontSize); //***** component.size() is deprecated in 1.1 - use getSize() //***** (as soon as Netscape supports 1.1) AppWidth = this.size().width; AppHeight = this.size().height; DrawBackground = true; } // Place additional applet clean up code here. destroy() is called when // when you applet is terminating and being unloaded. //------------------------------------------------------------------------- public void destroy() { } // overrides default paint(), which clears the applet area (and // causes flickering) first public void update(Graphics g) { paint(g); } // quotes Paint Handler //-------------------------------------------------------------------------- public void paint(Graphics g) { int i; StringBuffer WriteLine; StringBuffer NextWord; char NextChar; int TextBase; FontMetrics FM; boolean EndOfQuote; // For the start of a new string, draw a dark green rectangle // (erasing any previous string) FM = g.getFontMetrics(F); TextBase = FM.getMaxAscent() + 10; // if there was an error (NumQuotes < 1), display the error // message (in QuoteArray[0]) and exit if (NumQuotes < 1) { if (NumQuotes == 0) { g.setColor(Color.red); g.fillRect(5, 5, AppWidth - 10, AppHeight - 10); g.setFont(F); g.setColor(Color.white); TextHeight = FM.getMaxAscent() + FM.getMaxDescent() + FM.getLeading(); g.drawString(QuoteArray[0].toString(), 10, TextHeight); NumQuotes = -1; // only do this once } return; } // If the screen is full (or at the start of the program), // clear the screen, build the entire screen one line at a time, // and get the next quote ready if (CurrentLine >= MaxLines) { TextHeight = FM.getMaxAscent() + FM.getMaxDescent() + FM.getLeading(); MaxLines = (180 + FM.getLeading()) / TextHeight; DrawBackground = true; // redraw background, erasing existing quote Chalkboard = new StringBuffer[MaxLines]; for (i = 0; i < MaxLines; i++) Chalkboard[i] = new StringBuffer(""); c = 0; NextWord = new StringBuffer(""); CurrentLine = 0; while (CurrentLine < MaxLines) { // if the end of the quote is reached, put a space // before the start of the next copy of the quote // (if OneQuotePerLine is true, go to the start of the // next line instead of inserting a space) EndOfQuote = false; if (c >= QuoteArray[Q].length()) { if (OneQuotePerLine) EndOfQuote = true; NextChar = ' '; c = 0; } else { NextChar = QuoteArray[Q].charAt(c); c++; } // if a space is read, check to see if the previous // word fits on the end of the line; if not, start // a new line if (NextChar == ' ') { if (NextWord.length() > 0) { if (FM.stringWidth(Chalkboard[CurrentLine].toString() + NextWord.toString()) < 620) Chalkboard[CurrentLine].append(NextWord).append(' '); else { CurrentLine++; if (CurrentLine < MaxLines) Chalkboard[CurrentLine].append(NextWord).append(' '); } } if (EndOfQuote) CurrentLine++; NextWord = new StringBuffer(""); } else NextWord.append(NextChar); } if (RandomQuote) Q = (Q + new Double(Math.random() * NumQuotes - 2).intValue() + 1) % NumQuotes; else Q = (Q + 1) % NumQuotes; CurrentLine = 0; c = 0; // start with beginning of string } if (DrawBackground) { g.setColor(new Color(BoardColor)); g.fillRect(5, 5, AppWidth - 10, AppHeight - 10); DrawBackground = false; } g.setFont(F); g.setColor(new Color(TextColor)); for (i = 0; i < CurrentLine; i++) { g.drawString(Chalkboard[i].toString(), 10, TextBase + i * TextHeight); } g.drawString(Chalkboard[CurrentLine].toString().substring(0, c+1), 10, TextBase + CurrentLine * TextHeight); c++; if (c >= Chalkboard[CurrentLine].length()) { c = 0; CurrentLine++; } } // The start() method is called when the page containing the applet // first appears on the screen. The AppletWizard's initial implementation // of this method starts execution of the applet's thread. //-------------------------------------------------------------------------- public void start() { if (m_quotes == null) { m_quotes = new Thread(this); m_quotes.start(); } DrawBackground = true; } // The stop() method is called when the page containing the applet is // no longer on the screen. The AppletWizard's initial implementation of // this method stops execution of the applet's thread. //-------------------------------------------------------------------------- public void stop() { if (m_quotes != null) { m_quotes.stop(); m_quotes = null; } } // THREAD SUPPORT // The run() method is called when the applet's thread is started. If // your applet performs any ongoing activities without waiting for user // input, the code for implementing that behavior typically goes here. For // example, for an applet that performs animation, the run() method controls // the display of images. //-------------------------------------------------------------------------- public void run() { while (true) { try { repaint(); Thread.sleep(Delay); } catch (InterruptedException e) { stop(); } } } }