なんじゃくにっき

プログラミングの話題中心。

Scalaでメモ帳

 実用的で簡単なウィンドウアプリケーションっていったらメモ帳(テキストエディタ)ですよね!
ってことでScalaで書いてみた。
うらがみさんの記事を参考にしてみた。
http://d.hatena.ne.jp/backpaper0/20091210/1260485413
 
 メニューの項目の登録の仕方が色々あって悩んだ。
Javaでもいくつかやり方があるのにScalaだと更に沢山あってこんがらがりそう。
面倒だったのでファイルの入出力処理はapacheのcommons-ioで済ませた。
 
 scala.swingパッケージのコンポーネントはjavax.swingパッケージのコンポーネントのラッパーだけど、
javaのswingコンポーネント全てを網羅してるわけではないので、
scala.swingにないものは自分でラッパークラスを作らないと駄目。
本格的にscalaで開発するならライブラリ作った方がよさげ。
将来的に全部カバーするのか、どうなんだろう?

 無名クラス多用してコードの量は減ったけど、ネストが深い。
まだまだ上手に書けない。精進、精進。
 
以下、ソース

package main

import java.io.{File, IOException}
import java.awt.event.{ ActionEvent, KeyEvent, InputEvent }

import javax.swing.{ AbstractAction, InputMap, JTextPane, KeyStroke }
import javax.swing.filechooser.FileNameExtensionFilter
import javax.swing.undo.{ CannotRedoException, CannotUndoException, UndoManager }

import org.apache.commons.io.FileUtils

import io._
import swing._
import event.Key
import FileChooser.Result._

object ScalaTextEditor extends SimpleSwingApplication {

class TextPane extends Component {
override lazy val peer = new JTextPane
}

var currentFile: File = null
val textPane = new TextPane

def getFileChooser = {
new FileChooser {
fileFilter = new FileNameExtensionFilter("テキストファイル(*.txt)", "txt")
}
}

def top = new MainFrame {

val newFileAction = new Action("新規(N)") {
accelerator = Some(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK))
mnemonic = KeyEvent.VK_N
def apply() {
currentFile = null
textPane.peer.setText("")
}
}

val openFileAction = new Action("開く(O)") {
accelerator = Some(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK))
mnemonic = KeyEvent.VK_O
def apply() {
val chooser = getFileChooser
chooser.showOpenDialog(null) match {
case Approve => {
currentFile = chooser.selectedFile
textPane.peer.setText(FileUtils.readFileToString(currentFile))
}
case _ =>
}
}
}

val saveAsAction = new Action("名前を付けて保存(A)") {
mnemonic = KeyEvent.VK_A
def apply() {
val chooser = getFileChooser
chooser.showSaveDialog(null) match {
case Approve => {
val file = chooser.selectedFile
if ( file.exists ) {
Dialog.showConfirmation(null,
"ファイル「%s」は存在します\n上書きしますか?".format(file.getName),
"ファイル保存") match {
case Dialog.Result.No => return
case _ =>
}
}

try {
FileUtils.writeStringToFile(file, textPane.peer.getText)
currentFile = file
} catch {
case ex: IOException => Dialog.showMessage(null, "書き込み失敗")
}
}
case _ =>
}
}
}

val saveAction = new Action("上書き保存(S)") {
accelerator = Some(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK))
mnemonic = KeyEvent.VK_S
def apply() {
try {
if ( currentFile != null )
FileUtils.writeStringToFile(currentFile, textPane.peer.getText)
} catch {
case ex: IOException => Dialog.showMessage(null, "書き込み失敗")
}
}
}

val exitAction = new Action("終了(X)") {
mnemonic = KeyEvent.VK_X
def apply() { exit(0) }
}

menuBar = new MenuBar {
contents += new Menu("ファイル(F)") {
mnemonic = Key.F
contents += new MenuItem(newFileAction)
contents += new MenuItem(openFileAction)
contents += new MenuItem(saveAsAction)
contents += new MenuItem(saveAction)
contents += new MenuItem(exitAction)
}
}

contents = new ScrollPane{
contents = textPane
}

title = "memo"
size = new Dimension(300, 300)
}
}