// WeatherMan.java // Copyright (c) 2005 // Jon Lin // // Permission to use, copy, modify, distribute, and sell this software and its // documentation for any purpose is hereby granted without fee, provided that // the above copyright notice appear in all copies and that both that // copyright notice and this permission notice appear in supporting // documentation. No representations are made about the suitability of this // software for any purpose. It is provided "as is" without express or // implied warranty. // package org.jonlin; import java.net.*; import java.io.*; import java.awt.*; import java.util.*; public class WeatherMan extends Frame { public static int checkInterval; public static int zipcode; public static int initialWidth = 168; public static int initialHeight = 114; public static int xOffset; public static int yOffset; // This is just a guess at the font metrics public static int textXoffset = 5; public static int textYoffset = 25; public static boolean dontResize = true; public static boolean dontMerge; public static boolean scaleImage = false; public static boolean dontShowBig = true; public static boolean dontShowDetail = true; public static int bigWidth = 278; public static int bigHeight = 188; public static int bigXoffset; public static int bigYoffset; public static int detailWidth = 530; public static int detailHeight = 340; public static int detailXoffset = 5; public static int detailYoffset = 25; public static final String usMapSmall = "http://image.weather.com/images/maps/current/curwx_167x113.jpg"; public static final String usMapLarge = "http://image.weather.com/images/maps/current/curwx_277x187.jpg"; public static final String neMapSmall = "http://image.weather.com/images/maps/current/cur_ne_167x113.jpg"; public static final String neMapLarge = "http://image.weather.com/images/maps/current/cur_ne_277x187.jpg"; public static final String nwMapSmall = "http://image.weather.com/images/maps/current/cur_nw_167x113.jpg"; public static final String nwMapLarge = "http://image.weather.com/images/maps/current/cur_nw_277x187.jpg"; public static final String swMapSmall = "http://image.weather.com/images/maps/current/cur_sw_167x113.jpg"; public static final String swMapLarge = "http://image.weather.com/images/maps/current/cur_sw_277x187.jpg"; public static final String seMapSmall = "http://image.weather.com/images/maps/current/cur_se_167x113.jpg"; public static final String seMapLarge = "http://image.weather.com/images/maps/current/cur_se_277x187.jpg"; public static final String mwMapSmall = "http://image.weather.com/images/maps/current/cur_mw_167x113.jpg"; public static final String mwMapLarge = "http://image.weather.com/images/maps/current/cur_mw_277x187.jpg"; public static String currentImageURL; public static String currentBigImageURL; public static int fontSize = 11; public static int fontAttrib = Font.PLAIN; public static Color bg; public static Color fg; WeatherThread weatherThread; Image currentImage; Image currentBigImage; PicturePanel picture; TextPanel text; BigPicturePanel bigPicture; DetailedTextPanel detailText; public static void main(String[] args) { currentImageURL = usMapSmall; currentBigImageURL = usMapLarge; fg = Color.white; bg = Color.black; try { for(int x=0;x5) { System.err.println("Invalid zipcode: "+args[x]); return; } if(args[x].trim().length()<5) { System.err.println("Invalid zipcode: "+args[x]); return; } zipcode = Integer.parseInt(args[x].trim()); } } if(WeatherMan.checkInterval <= 0) { WeatherMan.checkInterval = 15000 * 60; } if(WeatherMan.initialWidth <= 0) { WeatherMan.initialWidth = 110; } if(WeatherMan.initialHeight <= 0) { WeatherMan.initialHeight = 167; } // if(!dontMerge) { // if(xOffset==0) { // xOffset = 10; // } // if(yOffset==0) { // yOffset = 30; // } // } if(zipcode <= 0) { System.err.println("Must provide a zipcode."); throw(new Exception()); } new WeatherMan(); } catch(Exception e) { e.printStackTrace(System.err); System.err.println("Usage: java org.jonlin.WeatherMan "); System.err.println(" "); System.err.println(" -t The number of minutes the WeatherMan updates the weather information."); System.err.println(" -x The initial width of the window."); System.err.println(" -y The initial height of the window."); System.err.println(" -off_x The main x offset."); System.err.println(" -off_y The main y offset."); System.err.println(" -text_off_x The weather text x offset."); System.err.println(" -text_off_y The weather text y offset."); System.err.println(" -rv Inverse the video (white is black and black is white)."); System.err.println(" -fg The Red, Green, and Blue values for the foreground color."); System.err.println(" -bg The Red, Green, and Blue values for the background color."); System.err.println(" -fontSize The font size, in points, to use."); System.err.println(" -boldFont Use bold type font."); System.err.println(" -showBigPicture Show the large weather map window."); System.err.println(" -big_x The initial width of the large weather map window."); System.err.println(" -big_y The initial height of the large weather map window."); System.err.println(" -big_off_x The large weather map x offset."); System.err.println(" -big_off_y The large weather map y offset."); System.err.println(" -showDetails Show the detailed local weather window."); System.err.println(" -detail_x The initial width of the detialed weather window."); System.err.println(" -detail_y The initial height of the detailed weather window."); System.err.println(" -detail_off_x The detailed weather window x offset."); System.err.println(" -detail_off_y The detailed weather window y offset."); System.err.println(" -mapType Use the following detailed map: us = US Map"); System.err.println(" ne = NE US Map"); System.err.println(" se = SE US Map"); System.err.println(" mw = MidWest US Map"); System.err.println(" nw = NW US Map"); System.err.println(" sw = SW US Map"); System.err.println(" or URL of image to use"); // System.err.println(" -dontAutoResize This flag keeps the WeatherMan from resizing the window automatically."); System.err.println(" -dontMerge This flag prevents Weatherman from overlaying the text on top of the picture."); System.err.println("\n"); } } public WeatherMan() { super("Weather"); setTitle("Weather"); setResizable(true); setFont(new Font("Monospaced",fontAttrib,fontSize)); if(bg!=null) { setBackground(bg); } picture = new PicturePanel(); text = new TextPanel(); if(!dontShowBig) { bigPicture = new BigPicturePanel(); } if(!dontShowDetail) { detailText = new DetailedTextPanel(); } setSize(initialWidth,initialHeight); if(dontMerge) { setLayout(new GridLayout(2,1)); // layout.setConstraints(picture, constraints); add(picture); // layout.setConstraints(text, constraints); add(text); pack(); setSize(initialWidth,initialHeight); } weatherThread = new WeatherThread(); show(); if(!dontShowBig) { bigPicture.show(); bigPicture.setSize(bigWidth,bigHeight); bigPicture.show(); } if(!dontShowDetail) { detailText.show(); detailText.setSize(detailWidth,detailHeight); detailText.show(); } setSize(initialWidth,initialHeight); } public Dimension getPreferredSize() { Dimension d = new Dimension(); if(dontResize) { d = getSize(); } else { if(dontMerge) { Dimension textSize = text.getPreferredSize(); Dimension pictureSize = picture.getPreferredSize(); d.width = pictureSize.width; d.height = pictureSize.height + textSize.height; //print("Pref Size: ("+d.width+","+d.height+")"); } else { d = picture.getPreferredSize(); } } if(d.width<=10) { d.width=initialWidth; } if(d.height<=10) { d.height=initialHeight; } return(d); } public void setSize() { //print("Setting size to "+getPreferredSize()); setSize(getPreferredSize()); } public void update() { repaint(); } public void paint(Graphics g) { //print("paint()"); if(dontMerge && bg!=null) { g.setColor(bg); g.fillRect(-500,-500,7500,7500); } if(scaleImage) { Dimension currentSize = getSize(); if(picture.getPreferredSize().width!=currentSize.width) { // picture.rescaleImage(); } } if(!dontMerge) { picture.paint(g); text.paint(g); } else { picture.repaint(); text.repaint(); } } public class BigPicturePanel extends Frame { public BigPicturePanel() { super(); setTitle("Large Current Weather"); setBackground(bg); } public void paint(Graphics g) { try { if(currentBigImage!=null) { g.clearRect(0,0,1000,1000); g.drawImage(currentBigImage,bigXoffset,bigYoffset,currentBigImage.getWidth(null),currentBigImage.getHeight(null),BigPicturePanel.this); //System.out.println("paint()"); } } catch(Exception e) { error("Could not draw current large weather image.",e); } } public Dimension getPreferredSize() { Dimension d = new Dimension(); if(dontResize) { d = getSize(); } else { if(currentBigImage!=null) { d.width = currentBigImage.getWidth(null)+(2*xOffset); d.height = currentBigImage.getHeight(null)+(2*yOffset); //WeatherMan.this.print("Picture Pref Size: ("+d.width+","+d.height+")"); } else { d = getSize(); } } return(d); } } public class PicturePanel extends Panel implements java.awt.image.ImageObserver { // public Image currentImage = null; public void update() { repaint(); } public void paint(Graphics g) { //WeatherMan.this.print("PictureCanvas.paint()"); int startTextY = yOffset; try { if(currentImage!=null) { g.clearRect(0,0,1000,1000); //System.out.println("drawing"); //WeatherMan.this.print("image.x="+currentImage.getWidth(null)+", image.y="+currentImage.getHeight(null)); g.drawImage(currentImage,xOffset,yOffset,currentImage.getWidth(null),currentImage.getHeight(null),PicturePanel.this); startTextY = startTextY+currentImage.getHeight(null)+15; } if(!dontResize) { PicturePanel.this.setSize(PicturePanel.this.getPreferredSize()); } } catch(Exception e) { error("Could not draw current weather image.",e); } } public void rescaleImage() { if(currentImage!=null) { int size = WeatherMan.this.getSize().width - (2*yOffset); if(size<=0) { size = 1; } currentImage = currentImage.getScaledInstance(size,size,Image.SCALE_SMOOTH); } } public Dimension getPreferredSize() { Dimension d = new Dimension(); if(dontResize) { d = getSize(); } else { if(currentImage!=null) { d.width = currentImage.getWidth(null)+(2*xOffset); d.height = currentImage.getHeight(null)+(2*yOffset); //WeatherMan.this.print("Picture Pref Size: ("+d.width+","+d.height+")"); } else { d = getSize(); } } return(d); } public boolean imageUpdate(Image image, int a, int b, int c, int d, int e) { if(!dontResize) { PicturePanel.this.setSize(image.getWidth(null)+(2*xOffset),image.getHeight(null)+(2*yOffset)); } // rescaleImage(); WeatherMan.this.setSize(); WeatherMan.this.repaint(); return(true); } } public class DetailedTextPanel extends Frame { int fontHeight; public DetailedTextPanel() { super(); setTitle("Detailed Weather Frame"); setBackground(bg); } // public void update() // { // repaint(); // } public void paint(Graphics g) { try { if(fg!=null) { g.setColor(fg); } FontMetrics fm = g.getFontMetrics(); fontHeight = fm.getHeight(); int currentY = detailYoffset+fontHeight; if(weatherThread.detailedWeather.size()>0) { for(int x=0;x"))) { page.append(line); page.append("\n"); line = in.readLine(); } } catch(Exception e) {;} rval = page.toString(); } } catch(Exception e) { error("Error opening \"http://www.weather.com/weather/local/"+zipcode+"\".",e); } if(in!=null) { try { in.close(); } catch(Exception e1) {;} } if(out!=null) { try { out.close(); } catch(Exception e1) {;} } if(socket!=null) { try { socket.close(); } catch(Exception e1) {;} } return(rval); } void parseDetailPage(String html) { try { int index = html.indexOf("36-Hour Forecast"); index = html.indexOf("
",index); index = html.indexOf(">",index); if(index!=-1) { String tmp = html.substring(index+1,html.indexOf("<",index)); // System.out.println("TMP="+tmp); detailedWeather = new Vector(); detailedWeather.addElement(tmp); } } catch(Exception e) { error("Could not parse detailed weather page.",e); } } void parsePage(String html) { try { int index = -1; // look for the current temperature. index = html.indexOf(""); if(index>0) { html = html.substring(index); index = html.indexOf(">"); html = html.substring(index+1); index = html.indexOf("°"); String tmpString = html.substring(0,index).trim(); if(tmpString.startsWith("-")) { tmpString = tmpString.substring(1); currentTemp = Integer.parseInt(tmpString)*-1; } else { currentTemp = Integer.parseInt(html.substring(0,index).trim()); } // print("Current Temp: "+currentTemp); } // look for the Relative Humidity. index = html.indexOf("Humidity:"); if(index>0) { html = html.substring(index); index = html.indexOf("CLASS=\"obsTextA\">"); index = html.indexOf(">",index); html = html.substring(index+1); index = html.indexOf("%"); String tmpString = html.substring(0,index).trim(); if(tmpString.startsWith("-")) { tmpString = tmpString.substring(1); relativeHumidity = Integer.parseInt(tmpString)*-1; } else { relativeHumidity = Integer.parseInt(html.substring(0,index).trim()); } // relativeHumidity = Integer.parseInt(html.substring(0,index).trim()); } // look for the Barometer. index = html.indexOf("Pressure:"); if(index>0) { html = html.substring(index); index = html.indexOf("CLASS=\"obsTextA\">"); index = html.indexOf(">",index); html = html.substring(index+1); index = html.indexOf(" "); //System.out.println(html.substring(0,index).trim()); barometer = Float.valueOf(html.substring(0,index).trim()).floatValue(); } } catch(Exception e) { error("Error parsing HTML containing the weather information.",e); } } } public void print(String s) { System.out.println("[WeatherMan] "+s); } public void error(String s) { System.err.println("{WeatherMan} "+s); } public void error(String s, Exception e) { System.err.println("{WeatherMan} "+e+" : "+s); e.printStackTrace(System.err); } }