summaryrefslogtreecommitdiff
path: root/src/swing
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-03-13 15:43:11 +0000
committerMartin Odersky <odersky@gmail.com>2008-03-13 15:43:11 +0000
commit954309658261dde811c30f2511d45f622f4b8880 (patch)
treeead2ce36d75d681c2b6ebd46360d9c2215ed684a /src/swing
parentf8a14831d854fd00aaa5cb229fb1eb6c7351ba25 (diff)
downloadscala-954309658261dde811c30f2511d45f622f4b8880.tar.gz
scala-954309658261dde811c30f2511d45f622f4b8880.tar.bz2
scala-954309658261dde811c30f2511d45f622f4b8880.zip
added scala.swing
Diffstat (limited to 'src/swing')
-rw-r--r--src/swing/scala/swing/AWTComponentWrapper.scala3
-rw-r--r--src/swing/scala/swing/Button.scala20
-rw-r--r--src/swing/scala/swing/Caret.scala8
-rw-r--r--src/swing/scala/swing/Color.scala5
-rw-r--r--src/swing/scala/swing/Component.scala26
-rw-r--r--src/swing/scala/swing/ComponentList.scala15
-rw-r--r--src/swing/scala/swing/Container.scala19
-rw-r--r--src/swing/scala/swing/Dimension.scala5
-rw-r--r--src/swing/scala/swing/EmptyBorder.scala11
-rw-r--r--src/swing/scala/swing/FormattedTextField.scala9
-rw-r--r--src/swing/scala/swing/Frame.scala26
-rw-r--r--src/swing/scala/swing/GUIApplication.scala23
-rw-r--r--src/swing/scala/swing/Label.scala14
-rw-r--r--src/swing/scala/swing/MainFrame.scala11
-rw-r--r--src/swing/scala/swing/Orientation.scala11
-rw-r--r--src/swing/scala/swing/Panel.scala15
-rw-r--r--src/swing/scala/swing/Publisher.scala18
-rw-r--r--src/swing/scala/swing/Reactions.scala28
-rw-r--r--src/swing/scala/swing/Reactor.scala7
-rw-r--r--src/swing/scala/swing/ScrollPane.scala18
-rw-r--r--src/swing/scala/swing/SimpleGUIApplication.scala18
-rw-r--r--src/swing/scala/swing/Slider.scala17
-rw-r--r--src/swing/scala/swing/Spreadsheet.scala100
-rw-r--r--src/swing/scala/swing/SwingComponent.scala11
-rw-r--r--src/swing/scala/swing/Table.scala80
-rw-r--r--src/swing/scala/swing/TextComponent.scala23
-rw-r--r--src/swing/scala/swing/TextField.scala22
-rw-r--r--src/swing/scala/swing/event/ButtonPressed.scala3
-rw-r--r--src/swing/scala/swing/event/CaretUpdate.scala3
-rw-r--r--src/swing/scala/swing/event/CellModified.scala3
-rw-r--r--src/swing/scala/swing/event/Event.scala3
-rw-r--r--src/swing/scala/swing/event/TableChanged.scala5
-rw-r--r--src/swing/scala/swing/event/TableResized.scala3
-rw-r--r--src/swing/scala/swing/event/TextModified.scala3
-rw-r--r--src/swing/scala/swing/event/WindowActivated.scala3
-rw-r--r--src/swing/scala/swing/event/WindowClosed.scala3
-rw-r--r--src/swing/scala/swing/event/WindowClosing.scala3
-rw-r--r--src/swing/scala/swing/event/WindowDeactivated.scala3
-rw-r--r--src/swing/scala/swing/event/WindowDeiconified.scala3
-rw-r--r--src/swing/scala/swing/event/WindowEvent.scala5
-rw-r--r--src/swing/scala/swing/event/WindowIconified.scala3
-rw-r--r--src/swing/scala/swing/event/WindowOpened.scala3
-rw-r--r--src/swing/scala/swing/layout.scala12
-rw-r--r--src/swing/scala/swing/model/Matrix.scala108
-rw-r--r--src/swing/scala/swing/test/CelsiusConverter.scala40
-rw-r--r--src/swing/scala/swing/test/CelsiusConverter2.scala30
-rw-r--r--src/swing/scala/swing/test/HelloWorld.scala13
-rw-r--r--src/swing/scala/swing/test/SwingApp.scala30
48 files changed, 845 insertions, 0 deletions
diff --git a/src/swing/scala/swing/AWTComponentWrapper.scala b/src/swing/scala/swing/AWTComponentWrapper.scala
new file mode 100644
index 0000000000..9a140e5506
--- /dev/null
+++ b/src/swing/scala/swing/AWTComponentWrapper.scala
@@ -0,0 +1,3 @@
+package swing;
+
+class AWTComponentWrapper(val acomponent: java.awt.Component) extends Component
diff --git a/src/swing/scala/swing/Button.scala b/src/swing/scala/swing/Button.scala
new file mode 100644
index 0000000000..0f6d8dc056
--- /dev/null
+++ b/src/swing/scala/swing/Button.scala
@@ -0,0 +1,20 @@
+package swing;
+
+import javax.swing._
+import event._
+
+/** A class for buttons; standard constructor wraps around a swing button */
+class Button(val jbutton: JButton) extends Container(jbutton) with SwingComponent with Publisher {
+ def this(txt: String) = this(new JButton(txt))
+ def this() = this(new JButton())
+ def text: String = jbutton.getText()
+ def text_=(s: String) = jbutton.setText(s)
+ def icon: Icon = jbutton.getIcon()
+ def icon_=(i: Icon) = jbutton.setIcon(i)
+ jbutton.addActionListener {
+ new java.awt.event.ActionListener {
+ def actionPerformed(e: java.awt.event.ActionEvent): unit =
+ publish(ButtonPressed(Button.this))
+ }
+ }
+}
diff --git a/src/swing/scala/swing/Caret.scala b/src/swing/scala/swing/Caret.scala
new file mode 100644
index 0000000000..9c3cc903de
--- /dev/null
+++ b/src/swing/scala/swing/Caret.scala
@@ -0,0 +1,8 @@
+package swing;
+
+import javax.swing
+
+class Caret(val jcaret: swing.text.Caret) extends Publisher {
+ def dot: int = jcaret.getDot()
+ def mark: int = jcaret.getMark()
+}
diff --git a/src/swing/scala/swing/Color.scala b/src/swing/scala/swing/Color.scala
new file mode 100644
index 0000000000..fff628d8bd
--- /dev/null
+++ b/src/swing/scala/swing/Color.scala
@@ -0,0 +1,5 @@
+package swing;
+
+case class Color(r: Int, g: Int, b: Int) extends java.awt.Color(r, g, b) {
+ def this(col: java.awt.Color) = this(col.getRed, col.getGreen, col.getBlue)
+}
diff --git a/src/swing/scala/swing/Component.scala b/src/swing/scala/swing/Component.scala
new file mode 100644
index 0000000000..3a5c98d90b
--- /dev/null
+++ b/src/swing/scala/swing/Component.scala
@@ -0,0 +1,26 @@
+package swing;
+
+import javax.swing._;
+import java.awt._;
+
+abstract class Component
+extends Object
+with Reactor
+{
+ val acomponent: java.awt.Component
+
+ def preferredSize = acomponent.getPreferredSize
+ def preferredSize_=(x: Dimension) = acomponent.setPreferredSize(x)
+ def preferredSize_=(xy: (Int, Int)) = acomponent.setPreferredSize(Dimension(xy._1, xy._2))
+
+ def foreground: Color = new Color(acomponent.getForeground)
+ def foreground_=(x: Color) = acomponent.setForeground(x)
+
+ def background: Color = new Color(acomponent.getBackground)
+ def background_=(x: Color) = acomponent.setBackground(x)
+
+ def font: Font = acomponent.getFont
+ def font_=(x: Font) = acomponent.setFont(x)
+
+ def show: this.type = { acomponent.setVisible(true); this }
+}
diff --git a/src/swing/scala/swing/ComponentList.scala b/src/swing/scala/swing/ComponentList.scala
new file mode 100644
index 0000000000..3876c84492
--- /dev/null
+++ b/src/swing/scala/swing/ComponentList.scala
@@ -0,0 +1,15 @@
+package swing
+
+import javax.swing._
+import event._
+
+class ComponentList(val jlist: JList) extends Container(jlist) with SwingComponent with Publisher {
+ def this() = this(new JList())
+ def this(elems: Seq[Object]) = this(new JList(elems.toArray))
+
+ def fixedCellWidth = jlist.getFixedCellWidth
+ def fixedCellWidth_=(x: Int) = jlist.setFixedCellWidth(x)
+
+ def fixedCellHeight = jlist.getFixedCellHeight
+ def fixedCellHeight_=(x: Int) = jlist.setFixedCellHeight(x)
+}
diff --git a/src/swing/scala/swing/Container.scala b/src/swing/scala/swing/Container.scala
new file mode 100644
index 0000000000..12cbf11072
--- /dev/null
+++ b/src/swing/scala/swing/Container.scala
@@ -0,0 +1,19 @@
+package swing;
+
+import javax.swing._
+import scala.collection.mutable.ListBuffer
+
+class Container(val jcontainer: java.awt.Container) extends Component {
+ val acomponent = jcontainer
+ def this() = this(new java.awt.Container())
+ val elems = new ListBuffer[Component]
+ def += (c: Component) = {
+ elems += c
+ jcontainer.add(c.acomponent)
+ }
+ def -= (c: Component) = {
+ elems -= c
+ jcontainer.remove(c.acomponent)
+ }
+}
+
diff --git a/src/swing/scala/swing/Dimension.scala b/src/swing/scala/swing/Dimension.scala
new file mode 100644
index 0000000000..2c1ebde994
--- /dev/null
+++ b/src/swing/scala/swing/Dimension.scala
@@ -0,0 +1,5 @@
+package swing;
+
+case class Dimension(w: Int, h: Int) extends java.awt.Dimension(w, h) {
+ def this(dim: java.awt.Dimension) = this(dim.width, dim.height)
+}
diff --git a/src/swing/scala/swing/EmptyBorder.scala b/src/swing/scala/swing/EmptyBorder.scala
new file mode 100644
index 0000000000..4524f00fe3
--- /dev/null
+++ b/src/swing/scala/swing/EmptyBorder.scala
@@ -0,0 +1,11 @@
+package swing;
+
+import javax.swing._
+
+class EmptyBorder(_top: int, _left: int, _bottom: int, _right: int)
+extends border.EmptyBorder(_top, _left, _bottom, _right) {
+ def this() = this(0, 0, 0, 0)
+}
+
+
+
diff --git a/src/swing/scala/swing/FormattedTextField.scala b/src/swing/scala/swing/FormattedTextField.scala
new file mode 100644
index 0000000000..7b88d1b5e8
--- /dev/null
+++ b/src/swing/scala/swing/FormattedTextField.scala
@@ -0,0 +1,9 @@
+package swing;
+
+import javax.swing._
+import java.awt.event._
+import event._
+
+class FormattedTextField(val jftextfield: JFormattedTextField) extends TextComponent(jftextfield) {
+ def this(format: java.text.Format) = this(new JFormattedTextField(format));
+}
diff --git a/src/swing/scala/swing/Frame.scala b/src/swing/scala/swing/Frame.scala
new file mode 100644
index 0000000000..fadd69d00c
--- /dev/null
+++ b/src/swing/scala/swing/Frame.scala
@@ -0,0 +1,26 @@
+package swing;
+
+import javax.swing._;
+import event._;
+
+class Frame(val jframe: JFrame) extends Container(jframe) with Publisher {
+ def this() = this(new JFrame("Untitled Frame"))
+ def title: String = jframe.getTitle()
+ def title_=(s: String) = jframe.setTitle(s)
+ val contents = new Container(jframe.getContentPane())
+ private var default_button: Button = null
+ def defaultButton = default_button
+ def defaultButton_=(b: Button) = { default_button = b; jframe.getRootPane().setDefaultButton(b.jbutton) }
+ def pack: this.type = { jframe.pack(); this }
+ jframe.addWindowListener {
+ new java.awt.event.WindowListener {
+ def windowActivated(e: java.awt.event.WindowEvent) = publish(WindowActivated(Frame.this))
+ def windowClosed(e: java.awt.event.WindowEvent) = publish(WindowClosed(Frame.this))
+ def windowClosing(e: java.awt.event.WindowEvent) = publish(WindowClosing(Frame.this))
+ def windowDeactivated(e: java.awt.event.WindowEvent) = publish(WindowDeactivated(Frame.this))
+ def windowDeiconified(e: java.awt.event.WindowEvent) = publish(WindowDeiconified(Frame.this))
+ def windowIconified(e: java.awt.event.WindowEvent) = publish(WindowIconified(Frame.this))
+ def windowOpened(e: java.awt.event.WindowEvent) = publish(WindowOpened(Frame.this))
+ }
+ }
+}
diff --git a/src/swing/scala/swing/GUIApplication.scala b/src/swing/scala/swing/GUIApplication.scala
new file mode 100644
index 0000000000..39c2a96561
--- /dev/null
+++ b/src/swing/scala/swing/GUIApplication.scala
@@ -0,0 +1,23 @@
+package swing
+
+import javax.swing._
+import event.Event
+
+class GUIApplication {
+
+ type Reaction = PartialFunction[Event, unit]
+
+ def defaultLookAndFeelDecorated: boolean = true
+
+ def init() = {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
+ JFrame.setDefaultLookAndFeelDecorated(defaultLookAndFeelDecorated)
+ }
+
+ def run(prog: => unit): unit =
+ SwingUtilities.invokeLater {
+ new Runnable() {
+ def run() = { init(); prog }
+ }
+ }
+}
diff --git a/src/swing/scala/swing/Label.scala b/src/swing/scala/swing/Label.scala
new file mode 100644
index 0000000000..622d74d9de
--- /dev/null
+++ b/src/swing/scala/swing/Label.scala
@@ -0,0 +1,14 @@
+package swing;
+
+import javax.swing._;
+
+class Label(val jlabel: JLabel) extends Container(jlabel) with SwingComponent {
+ def this(txt: String) = this(new JLabel(txt))
+ def this() = this("Untitled Label")
+ def text: String = jlabel.getText()
+ def text_=(s: String) = jlabel.setText(s)
+ def halign: Orientation.Value = Orientation(jlabel.getHorizontalAlignment())
+ def halign_=(x: Orientation.Value) = jlabel.setHorizontalAlignment(x.id)
+ def valign: Orientation.Value = Orientation(jlabel.getVerticalAlignment())
+ def valign_=(x: Orientation.Value) = jlabel.setVerticalAlignment(x.id)
+}
diff --git a/src/swing/scala/swing/MainFrame.scala b/src/swing/scala/swing/MainFrame.scala
new file mode 100644
index 0000000000..59701ae5e9
--- /dev/null
+++ b/src/swing/scala/swing/MainFrame.scala
@@ -0,0 +1,11 @@
+package swing;
+
+import javax.swing._;
+import event._;
+
+class MainFrame(jframe: JFrame) extends Frame(jframe) {
+ def this() = this(new JFrame("Untitled Frame"))
+ reactions += {
+ case WindowClosing(_) => System.exit(1)
+ }
+}
diff --git a/src/swing/scala/swing/Orientation.scala b/src/swing/scala/swing/Orientation.scala
new file mode 100644
index 0000000000..4c6bed34ab
--- /dev/null
+++ b/src/swing/scala/swing/Orientation.scala
@@ -0,0 +1,11 @@
+package swing
+
+import javax.swing.SwingConstants._
+
+object Orientation extends Enumeration {
+ val left = Value(LEFT, "left")
+ val right = Value(RIGHT, "right")
+ val bottom = Value(BOTTOM, "bottom")
+ val top = Value(TOP, "top")
+ val center = Value(CENTER, "center")
+}
diff --git a/src/swing/scala/swing/Panel.scala b/src/swing/scala/swing/Panel.scala
new file mode 100644
index 0000000000..e848e1bb7f
--- /dev/null
+++ b/src/swing/scala/swing/Panel.scala
@@ -0,0 +1,15 @@
+package swing;
+
+import javax.swing._
+import java.awt.event._
+
+class Panel(val jpanel: JPanel) extends Container(jpanel) with SwingComponent {
+ def this(layout: java.awt.LayoutManager, elements: Component*) = {
+ this(new JPanel(layout));
+ for (val elem <- elements) this += elem
+ }
+ def this(elements: Component*) = this(new java.awt.FlowLayout, elements: _*)
+
+ def layout: java.awt.LayoutManager = jpanel.getLayout()
+ def layout_=(x: java.awt.LayoutManager) = jpanel.setLayout(x)
+}
diff --git a/src/swing/scala/swing/Publisher.scala b/src/swing/scala/swing/Publisher.scala
new file mode 100644
index 0000000000..09ff2522fe
--- /dev/null
+++ b/src/swing/scala/swing/Publisher.scala
@@ -0,0 +1,18 @@
+package swing;
+
+import scala.collection.mutable.HashSet
+import event.Event
+
+trait Publisher extends Object with Reactor {
+
+ protected var listeners = new HashSet[Reactions];
+
+ def subscribe(listener: Reactions) = { listeners += listener }
+
+ def unsubscribe(listener: Reactions) = { listeners -= listener }
+
+ def publish(e: Event) =
+ for (val l <- listeners) l.send(e)
+
+ listenTo(this)
+}
diff --git a/src/swing/scala/swing/Reactions.scala b/src/swing/scala/swing/Reactions.scala
new file mode 100644
index 0000000000..9322c181a0
--- /dev/null
+++ b/src/swing/scala/swing/Reactions.scala
@@ -0,0 +1,28 @@
+package swing
+
+import event.Event
+
+class Reactions {
+ type Reaction = PartialFunction[Event, unit]
+
+ private var parts: List[Reaction] = List()
+
+ def += (r: Reaction) = { parts = r :: parts }
+
+ def -= (r: Reaction) = {
+ def withoutR(xs: List[Reaction]): List[Reaction] =
+ if (xs.isEmpty) xs
+ else if (xs.head == r) xs.tail
+ else xs.head :: withoutR(xs.tail)
+ parts = withoutR(parts)
+ }
+
+ def send(e: Event) = {
+ def sendTo(ps: List[Reaction]): Unit = ps match {
+ case Nil =>
+ case p :: ps =>
+ if (p isDefinedAt e) p(e) else sendTo(ps)
+ }
+ sendTo(parts)
+ }
+}
diff --git a/src/swing/scala/swing/Reactor.scala b/src/swing/scala/swing/Reactor.scala
new file mode 100644
index 0000000000..0867454f44
--- /dev/null
+++ b/src/swing/scala/swing/Reactor.scala
@@ -0,0 +1,7 @@
+package swing;
+
+trait Reactor {
+ val reactions = new Reactions
+ def listenTo(ps: Publisher*) = for (val p <- ps) p.subscribe(reactions)
+ def deafTo(ps: Publisher*) = for (val p <- ps) p.unsubscribe(reactions)
+}
diff --git a/src/swing/scala/swing/ScrollPane.scala b/src/swing/scala/swing/ScrollPane.scala
new file mode 100644
index 0000000000..d66d590d2e
--- /dev/null
+++ b/src/swing/scala/swing/ScrollPane.scala
@@ -0,0 +1,18 @@
+package swing;
+
+import javax.swing._
+import javax.swing.table._
+import javax.swing.event._
+import event._
+
+class ScrollPane(val jscrollpane: JScrollPane) extends Container(jscrollpane) with SwingComponent with Publisher {
+ def this() = this(new JScrollPane())
+ def this(contents: Component) = this(new JScrollPane(contents.acomponent))
+
+ def rowHeaderView: Component = null
+ def rowHeaderView_=(c: Component) = jscrollpane.setRowHeaderView(c.acomponent)
+
+ def viewportView: Component = null
+ def viewportView_=(c: Component) = jscrollpane.setViewportView(c.acomponent)
+
+}
diff --git a/src/swing/scala/swing/SimpleGUIApplication.scala b/src/swing/scala/swing/SimpleGUIApplication.scala
new file mode 100644
index 0000000000..43708d955a
--- /dev/null
+++ b/src/swing/scala/swing/SimpleGUIApplication.scala
@@ -0,0 +1,18 @@
+package swing
+
+import javax.swing._
+
+abstract class SimpleGUIApplication extends GUIApplication {
+
+ def top: Frame;
+
+ def main(args: Array[String]) = {
+ SwingUtilities.invokeLater {
+ new Runnable() {
+ def run(): unit = { init(); top.pack.show }
+ }
+ }
+ }
+
+ implicit def string2label(s: String): Label = new Label(s)
+}
diff --git a/src/swing/scala/swing/Slider.scala b/src/swing/scala/swing/Slider.scala
new file mode 100644
index 0000000000..18fae3225b
--- /dev/null
+++ b/src/swing/scala/swing/Slider.scala
@@ -0,0 +1,17 @@
+package swing;
+
+import javax.swing._
+import event._
+
+class Slider(val jbutton: JButton) extends Container(jbutton) with Publisher {
+ def this(txt: String) = this(new JButton(txt))
+ def this() = this("Untitled Button")
+ def text: String = jbutton.getText()
+ def text_=(s: String) = jbutton.setText(s)
+ jbutton.addActionListener {
+ new java.awt.event.ActionListener {
+ def actionPerformed(e: java.awt.event.ActionEvent): unit =
+ {}
+ }
+ }
+}
diff --git a/src/swing/scala/swing/Spreadsheet.scala b/src/swing/scala/swing/Spreadsheet.scala
new file mode 100644
index 0000000000..6bd0d4a21e
--- /dev/null
+++ b/src/swing/scala/swing/Spreadsheet.scala
@@ -0,0 +1,100 @@
+package swing
+
+import javax.swing.table.{AbstractTableModel, TableCellRenderer}
+import javax.swing.event.{TableModelListener, TableModelEvent}
+import javax.swing._
+import event._
+
+class Spreadsheet(width: Int, height: Int) extends Component with SwingComponent with Publisher {
+
+
+ def showGrid: Boolean = acomponent.table.getShowHorizontalLines && acomponent.table.getShowVerticalLines
+ def showGrid_=(x: Boolean) = acomponent.table.setShowGrid(x)
+
+ case class SpreadsheetCell(var userData: String, var displayData: String)
+
+ val data = model.Matrix[SpreadsheetCell](SpreadsheetCell("", ""), width, height)
+
+ val acomponent = new JScrollPane {
+ setPreferredSize(new java.awt.Dimension(800, 600))
+ val table = new JTable {
+ setSelectionModel(new DefaultListSelectionModel)
+ setAutoResizeMode(JTable.AUTO_RESIZE_OFF)
+ setRowHeight(25)
+ val model = new AbstractTableModel { model =>
+ class UserDataEvent(col: Int, row: Int) extends TableModelEvent(model, row, row, col)
+ val getRowCount = height
+ val getColumnCount = width
+ def getValueAt(row: Int, col: Int) =
+ data(col, row).userData
+ override def setValueAt(value: AnyRef, row: Int, col: Int) = {
+ data(col, row).userData = value.toString
+ fireTableChanged(new UserDataEvent(col, row))
+ }
+ def setDisplayValueAt(value: AnyRef, row: Int, col: Int) = {
+ data(col, row).displayData = value.toString
+ fireTableCellUpdated(row, col)
+ }
+ override def isCellEditable(row: Int, col: Int) = true
+ addTableModelListener(new TableModelListener {
+ def tableChanged(event: TableModelEvent) = event match {
+ case de:UserDataEvent =>
+ publish(CellModified(event.getColumn, event.getFirstRow, data(event.getColumn, event.getFirstRow).userData))
+ case _ =>
+ }
+ })
+ }
+ setModel(model)
+ setDefaultRenderer(classOf[AnyRef], new TableCellRenderer {
+ def getTableCellRendererComponent(table: JTable, value: AnyRef, selected: Boolean, focus: Boolean, row: Int, col: Int) =
+ if (focus) new JTextField {
+ setText(data(col, row).userData)
+ }
+ else new JLabel {
+ setText(data(col, row).displayData)
+ }
+ })
+ getTableHeader.setReorderingAllowed(false)
+ getTableHeader.setResizingAllowed(false)
+ }
+ setViewportView(table)
+ setColumnHeaderView(table.getTableHeader)
+ setRowHeaderView(new JList {
+ setListData(((1 to height) map (_.toString)).toArray.asInstanceOf[Array[Object]])
+ setFixedCellWidth(50)
+ setCellRenderer(new JLabel with ListCellRenderer {
+ setOpaque(true)
+ setBorder(UIManager.getBorder("TableHeader.cellBorder"))
+ setHorizontalAlignment(SwingConstants.CENTER)
+ setForeground(table.getTableHeader.getForeground)
+ setBackground(table.getTableHeader.getBackground)
+ setFont(table.getTableHeader.getFont)
+ def getListCellRendererComponent(list: JList, value: AnyRef, index: Int, isSelected: Boolean, cellHasFocus: Boolean) = {
+ setPreferredSize(new Dimension(50, table.getRowHeight(index)))
+ setText(value.toString)
+ this
+ }
+ })
+ })
+ def corner = new JLabel{
+ setOpaque(true)
+ setBorder(UIManager.getBorder("TableHeader.cellBorder"))
+ setForeground(table.getTableHeader.getForeground)
+ setBackground(table.getTableHeader.getBackground)
+ }
+ setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, corner)
+ setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, corner)
+ setCorner(ScrollPaneConstants.LOWER_LEFT_CORNER, corner)
+ setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, corner)
+ }
+
+ def update(col: Int, row: Int, value: Any) = {
+ acomponent.table.model.setDisplayValueAt(value.toString, row, col)
+ }
+// SwingUtilities.invokeLater(new Runnable {
+// def run = acomponent.table.model.setDisplayValueAt(value.toString, row, col)
+// })
+
+ def apply(pos: (Int, Int)) = data(pos._1, pos._2).userData
+
+}
diff --git a/src/swing/scala/swing/SwingComponent.scala b/src/swing/scala/swing/SwingComponent.scala
new file mode 100644
index 0000000000..73c7c43aaf
--- /dev/null
+++ b/src/swing/scala/swing/SwingComponent.scala
@@ -0,0 +1,11 @@
+package swing
+
+import javax.swing._
+import java.awt._
+
+trait SwingComponent extends Component {
+ val jcomponent = acomponent.asInstanceOf[JComponent];
+ def border: javax.swing.border.Border = jcomponent.getBorder()
+ def border_=(x: javax.swing.border.Border): unit = jcomponent.setBorder(x)
+}
+
diff --git a/src/swing/scala/swing/Table.scala b/src/swing/scala/swing/Table.scala
new file mode 100644
index 0000000000..17a44797c6
--- /dev/null
+++ b/src/swing/scala/swing/Table.scala
@@ -0,0 +1,80 @@
+package swing
+
+import model.Matrix
+import javax.swing._
+import javax.swing.table._
+import javax.swing.event._
+import event._
+
+object Table {
+ object AutoResizeMode extends Enumeration {
+ import JTable._
+ val Off = Value(AUTO_RESIZE_OFF, "Off")
+ val NextColumn = Value(AUTO_RESIZE_NEXT_COLUMN, "NextColumn")
+ val SubsequentColumns = Value(AUTO_RESIZE_SUBSEQUENT_COLUMNS, "SubsequentColumns")
+ val LastColumn = Value(AUTO_RESIZE_LAST_COLUMN, "LastColumn")
+ val AllColumns = Value(AUTO_RESIZE_ALL_COLUMNS, "AllColumns")
+ }
+}
+
+class Table(val jtable: JTable) extends Container(jtable) with SwingComponent with Publisher {
+ import Table._
+ def this() = this(new JTable())
+ def this(numRows: Int, numColumns: Int) = this(new JTable(numRows, numColumns))
+ def this(rowData: Array[Array[AnyRef]], columnNames: Array[AnyRef]) = this(new JTable(rowData, columnNames))
+ //todo: create constructor with List[List[Any]]
+
+ def this(dm: TableModel) = this(new JTable(dm))
+ def this(dm: TableModel, cm: TableColumnModel) = this(new JTable(dm, cm))
+ def this(dm: TableModel, cm: TableColumnModel, sm: ListSelectionModel) = this(new JTable(dm, cm, sm))
+
+ def rowHeight = jtable.getRowHeight
+ def rowHeight_=(x: Int) = jtable.setRowHeight(x)
+
+ def rowCount = jtable.getRowCount
+
+ def model = jtable.getModel()
+ def model_=(x: TableModel) = jtable.setModel(x)
+
+ def autoResizeMode: AutoResizeMode.Value = AutoResizeMode(jtable.getAutoResizeMode)
+ def autoResizeMode_=(x: Table.AutoResizeMode.Value) = jtable.setAutoResizeMode(x.id)
+
+ def showGrid = jtable.getShowHorizontalLines && jtable.getShowVerticalLines
+ def showGrid_=(grid: Boolean) = jtable.setShowGrid(grid)
+
+ def gridColor = new swing.Color(jtable.getGridColor)
+ def gridColor_=(color: swing.Color) = jtable.setGridColor(color)
+
+ private val initialRenderer = jtable.getDefaultRenderer(classOf[AnyRef])
+
+ protected def render(isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int): Component =
+ new AWTComponentWrapper(
+ initialRenderer.getTableCellRendererComponent(jtable, jtable.getValueAt(row, column), isSelected, hasFocus, row, column))
+
+ jtable.setDefaultRenderer(classOf[AnyRef], new TableCellRenderer {
+ def getTableCellRendererComponent(jtable: JTable, value: AnyRef, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) =
+ render(isSelected, hasFocus, row, column).acomponent
+ })
+
+ def apply(row: Int, column: Int) = jtable.getValueAt(row, column)
+ def update(row: Int, column: Int, value: AnyRef) = jtable.setValueAt(value, row, column)
+
+ def markUpdated(row: Int, column: Int) = update(row, column, apply(row, column))
+
+ /*
+ jtable.addActionListener {
+ new java.awt.event.ActionListener {
+ def actionPerformed(e: java.awt.event.ActionEvent): unit =
+ publish(ButtonPressed(Button.this))
+ }
+ }
+*/
+ model.addTableModelListener(new TableModelListener {
+ def tableChanged(event: TableModelEvent) = publish(
+ if (event.getType == TableModelEvent.UPDATE)
+ TableChanged(Table.this, event.getFirstRow, event.getLastRow, event.getColumn)
+ else
+ TableResized(Table.this)
+ )
+ })
+}
diff --git a/src/swing/scala/swing/TextComponent.scala b/src/swing/scala/swing/TextComponent.scala
new file mode 100644
index 0000000000..353349ffcf
--- /dev/null
+++ b/src/swing/scala/swing/TextComponent.scala
@@ -0,0 +1,23 @@
+package swing
+
+import javax.swing._
+import javax.swing.text.JTextComponent
+import javax.swing.event.{CaretEvent,CaretListener}
+import event.CaretUpdate
+
+class TextComponent(val jtextcomponent: JTextComponent)
+extends Container(jtextcomponent) with SwingComponent with Publisher {
+
+ def text: String = jtextcomponent.getText()
+ def text_=(x: String) = jtextcomponent.setText(x)
+
+ val caret = new Caret(jtextcomponent.getCaret())
+
+ jtextcomponent.addCaretListener {
+ new CaretListener {
+ def caretUpdate(e: CaretEvent) =
+ publish(CaretUpdate(TextComponent.this))
+ }
+ }
+}
+
diff --git a/src/swing/scala/swing/TextField.scala b/src/swing/scala/swing/TextField.scala
new file mode 100644
index 0000000000..5dd781011d
--- /dev/null
+++ b/src/swing/scala/swing/TextField.scala
@@ -0,0 +1,22 @@
+package swing;
+
+import javax.swing._
+import java.awt.event._
+import event._
+
+class TextField(val jtextfield: JTextField) extends TextComponent(jtextfield) {
+ def this(text: String, columns: int) = this(new JTextField(text, columns));
+ def this(text: String) = this(new JTextField(text));
+ def this(columns: int) = this(new JTextField(columns));
+ def this() = this(new JTextField());
+
+ def columns: int = jtextfield.getColumns()
+ def columns_=(x: int) = jtextfield.setColumns(x)
+
+ jtextfield.addActionListener {
+ new ActionListener {
+ def actionPerformed(e: ActionEvent) =
+ publish(TextModified(TextField.this))
+ }
+ }
+}
diff --git a/src/swing/scala/swing/event/ButtonPressed.scala b/src/swing/scala/swing/event/ButtonPressed.scala
new file mode 100644
index 0000000000..fb7850e93d
--- /dev/null
+++ b/src/swing/scala/swing/event/ButtonPressed.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class ButtonPressed(b: Button) extends Event
diff --git a/src/swing/scala/swing/event/CaretUpdate.scala b/src/swing/scala/swing/event/CaretUpdate.scala
new file mode 100644
index 0000000000..98d8b7f27c
--- /dev/null
+++ b/src/swing/scala/swing/event/CaretUpdate.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class CaretUpdate(text: TextComponent) extends Event
diff --git a/src/swing/scala/swing/event/CellModified.scala b/src/swing/scala/swing/event/CellModified.scala
new file mode 100644
index 0000000000..bfaf61013b
--- /dev/null
+++ b/src/swing/scala/swing/event/CellModified.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class CellModified(col: Int, row: int, value: String) extends Event
diff --git a/src/swing/scala/swing/event/Event.scala b/src/swing/scala/swing/event/Event.scala
new file mode 100644
index 0000000000..21306d5b94
--- /dev/null
+++ b/src/swing/scala/swing/event/Event.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+abstract class Event
diff --git a/src/swing/scala/swing/event/TableChanged.scala b/src/swing/scala/swing/event/TableChanged.scala
new file mode 100644
index 0000000000..3e1c6f8f6d
--- /dev/null
+++ b/src/swing/scala/swing/event/TableChanged.scala
@@ -0,0 +1,5 @@
+package swing.event
+
+case class TableChanged(table: Table, firstRow: Int, lastRow: Int, column: Int) extends Event {
+ println("table changed: "+table+"/"+firstRow+"-"+lastRow+":"+column)
+}
diff --git a/src/swing/scala/swing/event/TableResized.scala b/src/swing/scala/swing/event/TableResized.scala
new file mode 100644
index 0000000000..716ae89bf0
--- /dev/null
+++ b/src/swing/scala/swing/event/TableResized.scala
@@ -0,0 +1,3 @@
+package swing.event;
+
+case class TableResized(table: Table) extends Event
diff --git a/src/swing/scala/swing/event/TextModified.scala b/src/swing/scala/swing/event/TextModified.scala
new file mode 100644
index 0000000000..703d7711a0
--- /dev/null
+++ b/src/swing/scala/swing/event/TextModified.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class TextModified(text: TextComponent) extends Event
diff --git a/src/swing/scala/swing/event/WindowActivated.scala b/src/swing/scala/swing/event/WindowActivated.scala
new file mode 100644
index 0000000000..5f4e0b3bbf
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowActivated.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowActivated(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowClosed.scala b/src/swing/scala/swing/event/WindowClosed.scala
new file mode 100644
index 0000000000..5834d69c46
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowClosed.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowClosed(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowClosing.scala b/src/swing/scala/swing/event/WindowClosing.scala
new file mode 100644
index 0000000000..6938590347
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowClosing.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowClosing(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowDeactivated.scala b/src/swing/scala/swing/event/WindowDeactivated.scala
new file mode 100644
index 0000000000..d44214c73d
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowDeactivated.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowDeactivated(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowDeiconified.scala b/src/swing/scala/swing/event/WindowDeiconified.scala
new file mode 100644
index 0000000000..6a956a47d2
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowDeiconified.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowDeiconified(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowEvent.scala b/src/swing/scala/swing/event/WindowEvent.scala
new file mode 100644
index 0000000000..c6c8b6ffca
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowEvent.scala
@@ -0,0 +1,5 @@
+package swing.event
+
+abstract class WindowEvent extends Event {
+ val window: Frame
+}
diff --git a/src/swing/scala/swing/event/WindowIconified.scala b/src/swing/scala/swing/event/WindowIconified.scala
new file mode 100644
index 0000000000..2b6f6378c3
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowIconified.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowIconified(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/event/WindowOpened.scala b/src/swing/scala/swing/event/WindowOpened.scala
new file mode 100644
index 0000000000..952176670a
--- /dev/null
+++ b/src/swing/scala/swing/event/WindowOpened.scala
@@ -0,0 +1,3 @@
+package swing.event
+
+case class WindowOpened(window: Frame) extends WindowEvent;
diff --git a/src/swing/scala/swing/layout.scala b/src/swing/scala/swing/layout.scala
new file mode 100644
index 0000000000..3628b2de3a
--- /dev/null
+++ b/src/swing/scala/swing/layout.scala
@@ -0,0 +1,12 @@
+package swing
+
+import java.awt._
+
+object layout {
+
+ val flex = 0
+
+ def grid(rows: int, columns: int) = new GridLayout(rows, columns)
+ def row = new FlowLayout()
+ def column = grid(flex, 1)
+}
diff --git a/src/swing/scala/swing/model/Matrix.scala b/src/swing/scala/swing/model/Matrix.scala
new file mode 100644
index 0000000000..9bd4c9c4d0
--- /dev/null
+++ b/src/swing/scala/swing/model/Matrix.scala
@@ -0,0 +1,108 @@
+package swing.model
+
+trait Matrix[A]extends Function2[Int, Int, A] {
+
+ val width: Int
+ val height: Int
+
+ assert(width > 0 && height > 0)
+
+ private val delegate = new Array[A](width * height)
+
+ override def apply(col: Int, row: Int): A =
+ delegate(col * height + row)
+
+ def apply(coord: (Int, Int)): A =
+ apply(coord._1, coord._2)
+
+ def col(index: Int): Matrix.FlatSeq[A] =
+ new Matrix.SubArray[A](delegate, index * height, height)
+
+ def row(index: Int): Matrix.FlatSeq[A] =
+ new Matrix.SparseArray[A](delegate, index, height)
+
+ def update(xpos: Int, ypos: Int, elem: A) {
+ delegate(xpos % width * height + ypos % height) = elem
+ }
+
+ def update(coord: (Int, Int), elem: A) {
+ update(coord._1, coord._2, elem)
+ }
+
+ def initializeWith(f: (Int, Int) => A): this.type = {
+ for (index <- 0 until (width * height))
+ delegate(index) = f(index / height, index % height)
+ this
+ }
+
+ def initializeTo(v: => A): this.type = {
+ for (index <- 0 until (width * height))
+ delegate(index) = v
+ this
+ }
+
+ def size: (Int, Int) = (width, height)
+
+ /** A flattened view of the matrix. The flattening is done on columns i.e.
+ * the first values of the flattened sequence are the cells of the first
+ * column. As this is a view of the matrix, any change to the matrix will
+ * also be visible in the flattened array, and vice-versa. */
+ def flat: Array[A] = delegate
+
+}
+
+object Matrix {
+
+ def apply[A](columns: Int, rows: Int) = new Matrix[A] {
+ val width = columns
+ val height = rows
+ }
+
+ def apply[A](default: (Int, Int) => A, columns: Int, rows: Int) = new Matrix[A] {
+ val width = columns
+ val height = rows
+ initializeWith(default)
+ }
+
+ def apply[A](default: => A, columns: Int, rows: Int) = new Matrix[A] {
+ val width = columns
+ val height = rows
+ initializeTo(default)
+ }
+
+ trait FlatSeq[A] extends RandomAccessSeq[A] {
+ def update (index: Int, elem: A): Unit
+ }
+
+ private class SubArray[A](delegate: Array[A], start: Int, val length: Int) extends FlatSeq[A] {
+ def apply(index: Int): A =
+ if (index < length)
+ delegate(index + start)
+ else throw new IndexOutOfBoundsException
+ def update(index: Int, elem: A): Unit =
+ if (index < length)
+ delegate(index + start) = elem
+ else throw new IndexOutOfBoundsException
+ }
+
+ private class SparseArray[A](delegate: Array[A], start: Int, span: Int) extends FlatSeq[A] {
+ def apply(index: Int): A = {
+ if (index < length)
+ delegate((index * span) + start)
+ else throw new IndexOutOfBoundsException
+ }
+ def length: Int = delegate.length / span
+ def update(index: Int, elem: A): Unit =
+ if (index < length)
+ delegate((index * span) + start) = elem
+ else throw new IndexOutOfBoundsException
+ }
+
+ implicit def MatrixToSeqs[A](matrix: Matrix[A]): Seq[Seq[A]] = {
+ val result = new Array[SubArray[A]](matrix.width)
+ for (val col <- 0 until matrix.width)
+ result(col) = new SubArray[A](matrix.delegate, col * matrix.height, matrix.height)
+ result
+ }
+
+}
diff --git a/src/swing/scala/swing/test/CelsiusConverter.scala b/src/swing/scala/swing/test/CelsiusConverter.scala
new file mode 100644
index 0000000000..8d78667aa5
--- /dev/null
+++ b/src/swing/scala/swing/test/CelsiusConverter.scala
@@ -0,0 +1,40 @@
+package swing.test;
+
+import swing._
+import layout._
+import event._
+import Orientation.{left, right}
+
+/** A GUI app to convert celsius to centigrade
+ */
+object CelsiusConverter extends SimpleGUIApplication {
+ def top: Frame = new MainFrame {
+ title = "Convert Celsius to Fahrenheit"
+ defaultButton = convertButton
+ object tempCelsius extends TextField();
+ object celsiusLabel extends Label {
+ text = "Celsius"
+ border = new EmptyBorder(5, 5, 5, 5)
+ }
+ object convertButton extends Button {
+ icon = new javax.swing.ImageIcon("c:\\workspace\\gui\\images\\convert.gif")
+ border = new EmptyBorder(5, 5, 5, 5)
+ }
+ object fahrenheitLabel extends Label {
+ text = "Fahrenheit "
+ border = new EmptyBorder(5, 5, 5, 5)
+ listenTo(convertButton, tempCelsius)
+ reactions += {
+ case ButtonPressed(_) | TextModified(_) =>
+ val c = Integer.parseInt(tempCelsius.text)
+ val f = c * 9 / 5 + 32
+ text = "<html><font color = red>"+f+"</font> Fahrenheit</html>"
+ }
+ }
+ contents += new Panel(tempCelsius, celsiusLabel, convertButton, fahrenheitLabel) {
+ layout = grid(2, 2)
+ border = new EmptyBorder(10, 10, 10, 10)
+ }
+ }
+}
+
diff --git a/src/swing/scala/swing/test/CelsiusConverter2.scala b/src/swing/scala/swing/test/CelsiusConverter2.scala
new file mode 100644
index 0000000000..5813b3042d
--- /dev/null
+++ b/src/swing/scala/swing/test/CelsiusConverter2.scala
@@ -0,0 +1,30 @@
+package swing.test;
+
+import swing._
+import layout._
+import event._
+import Orientation.{left, right, center}
+
+object CelsiusConverter2 extends SimpleGUIApplication {
+ def top = new MainFrame {
+ title = "Convert Celsius / Fahrenheit"
+ object Celsius extends TextField { columns = 5 };
+ object Fahrenheit extends TextField { columns = 5 }
+ contents += new Panel(Celsius, new Label(" Celsius = "),
+ Fahrenheit, new Label(" Fahrenheit")) {
+ border = new EmptyBorder(15, 10, 10, 10)
+ }
+ listenTo(Fahrenheit, Celsius)
+ reactions += {
+ case TextModified(Fahrenheit) =>
+ val f = Integer.parseInt(Fahrenheit.text)
+ val c = (f - 32) * 5 / 9
+ Celsius.text = c.toString
+ case TextModified(Celsius) =>
+ val c = Integer.parseInt(Celsius.text)
+ val f = c * 9 / 5 + 32
+ Fahrenheit.text = f.toString
+ }
+ }
+}
+
diff --git a/src/swing/scala/swing/test/HelloWorld.scala b/src/swing/scala/swing/test/HelloWorld.scala
new file mode 100644
index 0000000000..e19a6e92e4
--- /dev/null
+++ b/src/swing/scala/swing/test/HelloWorld.scala
@@ -0,0 +1,13 @@
+package swing.test;
+
+import swing._;
+import javax.swing._;
+
+object HelloWorld extends GUIApplication {
+ def main(args: Array[String]) = run {
+ new Frame {
+ title = "HelloWorldSwing";
+ contents += new Label("Hello World");
+ }.pack.show
+ }
+}
diff --git a/src/swing/scala/swing/test/SwingApp.scala b/src/swing/scala/swing/test/SwingApp.scala
new file mode 100644
index 0000000000..1712b74ee4
--- /dev/null
+++ b/src/swing/scala/swing/test/SwingApp.scala
@@ -0,0 +1,30 @@
+package swing.test;
+
+import swing._
+import swing.event._
+import swing.layout._
+
+object SwingApp extends SimpleGUIApplication {
+ def top = new MainFrame {
+ title = "SwingApp"
+ var numclicks = 0
+ object label extends Label {
+ val prefix = "Number of button clicks: "
+ text = prefix + "0 "
+ listenTo(button)
+ reactions += {
+ case ButtonPressed(button) =>
+ numclicks = numclicks + 1
+ text = prefix + numclicks
+ }
+ }
+ object button extends Button {
+ text = "I am a button"
+ }
+ contents += new Panel(label, button) {
+ layout = column
+ border = new EmptyBorder(30, 30, 10, 30)
+ }
+ }
+}
+