Skip to content

Commit

Permalink
Extract Image loading to another util object.
Browse files Browse the repository at this point in the history
  • Loading branch information
brianhsu committed Jul 16, 2012
1 parent 46c5bac commit ce08636
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 81 deletions.
82 changes: 49 additions & 33 deletions src/main/scala/irc/IRCBot.scala
Expand Up @@ -8,11 +8,25 @@ import org.pircbotx.hooks.events._
import scala.collection.JavaConversions._
import I18N.i18n._

/**
* IRC 機器人
*
* @param hostname IRC Server
* @param port IRC Server Port
* @param nickname 要使用的 IRC 暱稱
* @param password IRC Server 密碼
* @param channel 要加入的 IRC 頻道
* @param callback 機器人收到 IRC 來的訊息時的 Callback
* @param onLog 當 IRCBot 進行 log 時的 Callback
* @param onError 當錯誤發生時的 Callback
* @param showJoin 是否顯示加入聊天室訊息
* @param showLeave 是否顯示離開聊天室訊息
*/
class IRCBot(hostname: String, port: Int, nickname: String,
password: Option[String], channel: String,
callback: IRCMessage => Any = IRCBot.doNothing,
onLog: String => Any = IRCBot.doNothing,
onError: Exception => Any = IRCBot.doNothing,
callback: IRCMessage => Any,
onLog: String => Any,
onError: Exception => Any,
showJoin: Boolean = false,
showLeave: Boolean = false) extends PircBotX
{
Expand Down Expand Up @@ -54,7 +68,8 @@ class IRCBot(hostname: String, port: Int, nickname: String,
val sender = event.getUser.getNick

showJoin match {
case true => callback(SystemMessage(tr("[SYS] %s has joined") format(sender)))
case true =>
callback(SystemMessage(tr("[SYS] %s has joined") format(sender)))
case false if (sender == nickname) =>
callback(SystemMessage(tr("[SYS] %s has joined") format(sender)))
case _ =>
Expand All @@ -75,6 +90,9 @@ class IRCBot(hostname: String, port: Int, nickname: String,
onLog(line)
}

/**
* 連線至 IRC Server
*/
private def connect()
{
password match {
Expand All @@ -83,38 +101,45 @@ class IRCBot(hostname: String, port: Int, nickname: String,
}
}

/**
* 停止 IRC 機器人
*/
def stop()
{
val thread = new Thread()
{
override def run()
{
if (IRCBot.this.isConnected) {
IRCBot.this.disconnect()
}
runByThread {
if (IRCBot.this.isConnected) {
IRCBot.this.disconnect()
}
}

thread.start()
}

/**
* 啟動 IRC 機器人
*/
def start()
{
runByThread {
try {
IRCBot.this.setAutoNickChange(true)
IRCBot.this.setVerbose(true)
IRCBot.this.setName(nickname)
IRCBot.this.setEncoding("UTF-8")
IRCBot.this.connect()
IRCBot.this.getListenerManager.addListener(Callbacks)
IRCBot.this.joinChannel(channel)
} catch {
case e: Exception => onError(e)
}
}
}

def runByThread(action: => Any)
{
val thread = new Thread()
{
override def run()
{
try {
IRCBot.this.setAutoNickChange(true)
IRCBot.this.setVerbose(true)
IRCBot.this.setName(nickname)
IRCBot.this.setEncoding("UTF-8")
IRCBot.this.connect()
IRCBot.this.getListenerManager.addListener(Callbacks)
IRCBot.this.joinChannel(channel)
} catch {
case e: Exception => onError(e)
}
action
}
}

Expand All @@ -124,12 +149,3 @@ class IRCBot(hostname: String, port: Int, nickname: String,
}


object IRCBot
{
def doNothing(message: String) {}
def doNothing(message: IRCMessage) {}
def doNothing(exception: Exception) {
println("From IRCBot.doNothing:")
exception.printStackTrace()
}
}
34 changes: 31 additions & 3 deletions src/main/scala/irc/IRCMessage.scala
Expand Up @@ -2,9 +2,7 @@ package org.bone.ircballoon

import I18N.i18n._

sealed trait IRCMessage {
val message: String
}
sealed trait IRCMessage

trait HasUser
{
Expand All @@ -13,18 +11,36 @@ trait HasUser
import Avatar.displayAvatar
import Avatar.onlyAvatar

/**
* 視狀況取代使用者名稱取代為 Twitch 的暱稱
*
*/
def convertedNickname = Avatar.usingTwitchNickname match {
case true => Avatar.getTwitchNicknameCache(nickname).getOrElse(nickname)
case false => nickname
}

/**
* 加入 Avatar 代碼
*
* 如果有開啟 Avatar 功能,而且該使用者有 Avatar,就加
* 入 Avatar 控制碼 [nickname],UI 看到這個控制碼的時
* 候會取代為使用者的 Avatar。
*/
def userDisplay = Avatar(nickname) match {
case Some(image) if displayAvatar && onlyAvatar => "[%s]" format(nickname)
case Some(image) if displayAvatar => "[%s] %s" format(nickname, convertedNickname)
case _ => convertedNickname
}
}

/**
* IRC 聊天訊息
*
* @param nickname 使用者暱稱
* @param isOp 使用者是否為 IRC 頻道管理員
* @param message 訊息
*/
case class ChatMessage(nickname: String, isOp: Boolean,
message: String) extends IRCMessage with HasUser
{
Expand All @@ -34,12 +50,24 @@ case class ChatMessage(nickname: String, isOp: Boolean,
}
}

/**
* IRC 動作訊息
*
* @param nickname 使用者暱稱
* @param isOp 使用者是否為 IRC 頻道管理員
* @param message 使用者的動作
*/
case class ActionMessage(nickname: String, isOp: Boolean,
message: String) extends IRCMessage with HasUser
{
override def toString = tr("[Action] %s %s") format(userDisplay, message)
}

/**
* IRC 系統訊息
*
* @param message 系統訊息
*/
case class SystemMessage(message: String) extends IRCMessage
{
override def toString = message
Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/ui/MainWindow.scala
Expand Up @@ -11,7 +11,9 @@ import org.eclipse.swt.custom.ScrolledComposite
import org.eclipse.swt._
import I18N.i18n._


/**
* 主視窗
*/
object MainWindow extends SWTHelper
{
Display.setAppName("IRCBalloon")
Expand Down
16 changes: 3 additions & 13 deletions src/main/scala/utils/Avatar.scala
Expand Up @@ -2,6 +2,7 @@ package org.bone.ircballoon

import org.eclipse.swt.widgets._
import org.eclipse.swt.graphics._
import ImageUtil._

object Avatar
{
Expand Down Expand Up @@ -52,12 +53,6 @@ object Avatar
def getTwitchAvatar(nickname: String): Option[Image] = {

def isDefault(url: String) = url.contains("404_user")
def getImage(url: String) = {
val inputStream = new URL(url).openStream
val image = new Image(Display.getDefault, inputStream)
inputStream.close()
Some(image)
}

try {
val profileURL = "http://api.justin.tv/api/user/show/" + nickname + ".xml"
Expand All @@ -66,7 +61,7 @@ object Avatar
(twitchUserXML \\ "image_url_tiny").map(_.text).filterNot(isDefault)

val avatarImage = imageURLTiny match {
case imageURL :: Nil => getImage(imageURL)
case imageURL :: Nil => loadFromURL(imageURL)
case _ => None
}

Expand All @@ -89,14 +84,9 @@ object Avatar

}

def getImageFile(filePath: String) =
{
new Image(Display.getDefault, filePath)
}

def addAvatar(nickname: String, imagePath: String)
{
customAvatars += (nickname -> (imagePath, getImageFile(imagePath)))
customAvatars += (nickname -> (imagePath, loadFromFile(imagePath).get))
}

def removeAvatar(nickname: String)
Expand Down
32 changes: 14 additions & 18 deletions src/main/scala/utils/Emotes.scala
Expand Up @@ -3,6 +3,8 @@ package org.bone.ircballoon
import org.eclipse.swt.widgets._
import org.eclipse.swt.graphics._

import ImageUtil._

object Emotes
{
var useDefault: Boolean = true
Expand All @@ -15,7 +17,10 @@ object Emotes
def addEmote(emotes: EmoteIcon)
{
customEmotes = customEmotes.updated(emotes.targetText, emotes.imagePath)
customIcons = customIcons.updated(emotes.targetText, getImageFile(emotes.imagePath))
customIcons = customIcons.updated(
emotes.targetText,
loadFromFile(emotes.imagePath).get
)
}

def removeEmote(targetText: String)
Expand All @@ -25,15 +30,6 @@ object Emotes
customIcons -= targetText
}

def getImageFile(filePath: String) =
{
new Image(Display.getDefault, filePath)
}

def getImage(path: String) = {
new Image(Display.getDefault, getClass().getResourceAsStream(path))
}

def getEmotes: Map[String, Image] = {

useDefault match {
Expand All @@ -43,13 +39,13 @@ object Emotes
}

val default = Map(
":)" -> getImage("/emotes/face-smile.png"),
":D" -> getImage("/emotes/face-laugh.png"),
":o" -> getImage("/emotes/face-surprise.png"),
":(" -> getImage("/emotes/face-sad.png"),
":p" -> getImage("/emotes/face-raspberry.png"),
"8)" -> getImage("/emotes/face-cool.png"),
":X" -> getImage("/emotes/face-angry.png"),
";)" -> getImage("/emotes/face-wink.png")
":)" -> loadFromResource("/emotes/face-smile.png").get,
":D" -> loadFromResource("/emotes/face-laugh.png").get,
":o" -> loadFromResource("/emotes/face-surprise.png").get,
":(" -> loadFromResource("/emotes/face-sad.png").get,
":p" -> loadFromResource("/emotes/face-raspberry.png").get,
"8)" -> loadFromResource("/emotes/face-cool.png").get,
":X" -> loadFromResource("/emotes/face-angry.png").get,
";)" -> loadFromResource("/emotes/face-wink.png").get
)
}
51 changes: 51 additions & 0 deletions src/main/scala/utils/ImageUtil.scala
@@ -0,0 +1,51 @@
package org.bone.ircballoon

import org.eclipse.swt.SWT
import org.eclipse.swt.widgets.Display
import org.eclipse.swt.graphics.Image
import org.eclipse.swt.graphics.GC

import scala.util.control.Exception._

object ImageUtil
{
import java.net.URL

lazy val display = Display.getDefault

def loadFromResource(path: String) = allCatch.opt {
new Image(display, getClass().getResourceAsStream(path))
}

def loadFromFile(filePath: String) = allCatch.opt {
new Image(display, filePath)
}

def loadFromURL(url: String) = allCatch.opt {
val inputStream = new URL(url).openStream
val image = new Image(Display.getDefault, inputStream)
inputStream.close()
image
}

def resize(image: Image, size: (Int, Int)) =
{
val (width, height) = size
val scaled = new Image(display, width, height)
val gc = new GC(scaled)

gc.setAntialias(SWT.ON)
gc.setInterpolation(SWT.HIGH)
gc.drawImage(
image, 0, 0,
image.getBounds().width, image.getBounds().height,
0, 0, width, height
)

gc.dispose()
image.dispose()

scaled
}
}

0 comments on commit ce08636

Please sign in to comment.