Created
September 16, 2008 09:07
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.{ImageIcon, JWindow, JLabel} | |
import java.net.URL | |
import scala.xml.XML | |
import scala.collection.mutable.Queue | |
import scala.actors.Actor | |
import scala.actors.Actor.loop | |
import scala.concurrent.ops.spawn | |
object ViewImagesInFeed extends Application { | |
/** | |
* messages to be delivered to actors. | |
*/ | |
sealed abstract class MESSAGE | |
case object GETIMAGE extends MESSAGE | |
case object FEEDIMAGE extends MESSAGE | |
case class UPDATEIMAGE(url:String) extends MESSAGE | |
/** | |
* This actor will retrieve the URLs of recent images on Flickr | |
* via friendfeed.com, and then send each of them to ViewUpdater actor with | |
* the UPDATEIMAGE message. | |
*/ | |
private object FeedReceiver extends Actor { | |
val images = new Queue[String]() | |
/** | |
* Thanks to the XML support on Scala, it is really easy to extract URLs | |
* for thumbnails. The URLs will be kept in "images". | |
*/ | |
def getImages() = { | |
val url = "http://friendfeed.com/api/feed/public?format=xml&service=flickr&num=100" | |
val xml = XML.load(new URL(url).openStream) | |
(xml \ "entry" \ "media" \ "thumbnail" \ "url").foldLeft(images){ | |
(i, u) => i += u.text; i | |
} | |
} | |
/** | |
* The interval to delay to send messaes to actors. | |
*/ | |
val interval=1000 | |
def act { | |
getImages() | |
this ! FEEDIMAGE | |
loop { | |
react { | |
case FEEDIMAGE => images.isEmpty match { | |
case true => ping(interval, GETIMAGE) | |
case false => { | |
ViewUpdater ! UPDATEIMAGE(images.dequeue) | |
ping(interval*10, FEEDIMAGE) | |
} | |
} | |
case GETIMAGE => getImages.isEmpty match { | |
case true => ping(interval, GETIMAGE) | |
case false => ping(interval, FEEDIMAGE) | |
} | |
} | |
} | |
} | |
/** | |
* Send a message to myself after some interval in the forked thread. | |
*/ | |
def ping(sleep:Int, m:MESSAGE) { | |
spawn { Thread.sleep(sleep); this ! m } | |
} | |
} | |
/** | |
* This actor will update the view according to the given message; UPDATEIMAGE. | |
* The update operation will be delegated to "w" object via its "<<" method. | |
*/ | |
private object ViewUpdater extends Actor { | |
def act { | |
loop { | |
react { | |
case UPDATEIMAGE(url) => w << url | |
} | |
} | |
} | |
} | |
/** | |
* The main window to show thumbnails. | |
* Please note that we don't have to invent the class name for "w"! | |
* In java, we can not invoke "<<" method in "ViewUpdater" object without | |
* doing that. | |
*/ | |
private val w = new JWindow { | |
import java.awt.Toolkit | |
import java.awt.event._ | |
val icon = new ImageIcon | |
addMouseListener(new MouseAdapter(){ | |
override def mouseClicked(e:MouseEvent){ System.exit(0) } | |
}) | |
getContentPane.add(new JLabel(icon)) | |
setSize(75, 75) | |
setVisible(true) | |
// switch image with the given URL | |
def << (url:String) { | |
// release resource in the image if required. | |
icon.getImage match { | |
case i => if(i!=null){ i.flush } | |
} | |
val image=Toolkit.getDefaultToolkit.createImage(new URL(url)) | |
icon.setImage(image) | |
repaint | |
} | |
} | |
// start actors | |
ViewUpdater.start() | |
FeedReceiver.start() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment