diff options
author | Ingo Maier <ingo.maier@epfl.ch> | 2009-11-02 06:05:02 +0000 |
---|---|---|
committer | Ingo Maier <ingo.maier@epfl.ch> | 2009-11-02 06:05:02 +0000 |
commit | 852f027607699ac4a11f7bae752c2455ff0f7151 (patch) | |
tree | c2a90d4e820d82794570bb258579963f1054b91f | |
parent | b42e1f1902c47f4b5fef0be17f5a5c606ac6a777 (diff) | |
download | scala-852f027607699ac4a11f7bae752c2455ff0f7151.tar.gz scala-852f027607699ac4a11f7bae752c2455ff0f7151.tar.bz2 scala-852f027607699ac4a11f7bae752c2455ff0f7151.zip |
Synchronize trunk with local changes:
* Fixes for #2452, #2036, #2491
* More comments
* Added paint methods
* Added convenience methods and constructors
* Deprecated UIApplication classes, replaced by SwingApplication classes
* Replaced case class inheritance by unapplies
* Introduced type aliases for AWT classes in package object
* Refactored RichWindow hierarchy
* Some minor code cleanup
45 files changed, 393 insertions, 154 deletions
diff --git a/src/swing/scala/swing/AbstractButton.scala b/src/swing/scala/swing/AbstractButton.scala index 991d82fb55..243a274792 100644 --- a/src/swing/scala/swing/AbstractButton.scala +++ b/src/swing/scala/swing/AbstractButton.scala @@ -12,7 +12,6 @@ package scala.swing import event._ -import java.awt.{Dimension, Insets} import javax.swing.{AbstractButton => JAbstractButton, Icon} /** @@ -42,6 +41,7 @@ abstract class AbstractButton extends Component with Action.Trigger with Publish def rolloverSelectedIcon: Icon = peer.getRolloverSelectedIcon def rolloverSelectedIcon_=(b: Icon) = peer.setRolloverSelectedIcon(b) + // TODO: we need an action cache private var _action: Action = Action.NoAction def action: Action = _action def action_=(a: Action) { _action = a; peer.setAction(a.peer) } diff --git a/src/swing/scala/swing/Action.scala b/src/swing/scala/swing/Action.scala index 61ce4a5276..d2f48d4b48 100644 --- a/src/swing/scala/swing/Action.scala +++ b/src/swing/scala/swing/Action.scala @@ -15,16 +15,23 @@ import javax.swing.{KeyStroke, Icon} import java.awt.event.ActionListener object Action { + /** + * Special action that has an empty title and all default properties and does nothing. + * Use this as a "null action", i.e., to tell components that they do not have any + * associated action. A component may then obtain its properties from its direct members + * instead of from its action. + * In Java Swing, one would use `null` instead of a designated action. + */ case object NoAction extends Action("") { def apply() {} } object Trigger { - abstract trait Wrapper extends Component with Action.Trigger { - self: Component { - def peer: javax.swing.JComponent { - def addActionListener(a: ActionListener) - def removeActionListener(a: ActionListener) - } - } => + trait Wrapper extends Action.Trigger { + def peer: javax.swing.JComponent { + def addActionListener(a: ActionListener) + def removeActionListener(a: ActionListener) + def setAction(a: Action): javax.swing.Action + def getAction: javax.swing.Action + } } } @@ -39,8 +46,11 @@ object Action { //def hideActionText_=(b: Boolean) } - def apply(title: String)(block: =>Unit) = new Action(title) { - def apply() { block } + /** + * Convenience method to create an action with a given title and body to run. + */ + def apply(title: String)(body: =>Unit) = new Action(title) { + def apply() { body } } } diff --git a/src/swing/scala/swing/BufferWrapper.scala b/src/swing/scala/swing/BufferWrapper.scala index 191e23242b..56d6e19887 100644 --- a/src/swing/scala/swing/BufferWrapper.scala +++ b/src/swing/scala/swing/BufferWrapper.scala @@ -18,7 +18,7 @@ import scala.collection.IndexedSeq * Default partial implementation for buffer adapters. */ protected[swing] abstract class BufferWrapper[A] extends Buffer[A] { outer => - def clear { for (i <- 0 to length) remove(0) } + def clear() { for (i <- 0 until length) remove(i) } def update(n: Int, a: A) { remove(0) insertAt(n, a) @@ -32,11 +32,6 @@ protected[swing] abstract class BufferWrapper[A] extends Buffer[A] { outer => } protected def insertAt(n: Int, a: A) - override def readOnly: IndexedSeq[A] = new IndexedSeq[A] { - def length = outer.length - def apply(idx : Int) = outer.apply(idx) - override def stringPrefix = outer.stringPrefix + "RO" - } def +=:(a: A): this.type = { insertAt(0, a); this } def iterator = Iterator.range(0,length).map(apply(_)) } diff --git a/src/swing/scala/swing/Component.scala b/src/swing/scala/swing/Component.scala index dd0f04086e..598e78abf4 100644 --- a/src/swing/scala/swing/Component.scala +++ b/src/swing/scala/swing/Component.scala @@ -13,7 +13,7 @@ package scala.swing import event._ -import java.awt.{Dimension, Point, Graphics, Graphics2D} +import java.awt.Graphics import java.awt.event._ import javax.swing.JComponent import javax.swing.border.Border @@ -58,6 +58,19 @@ abstract class Component extends UIElement { def __super__paintComponent(g: Graphics) { super.paintComponent(g) } + override def paintBorder(g: Graphics) { + Component.this.paintBorder(g.asInstanceOf[Graphics2D]) + } + def __super__paintBorder(g: Graphics) { + super.paintBorder(g) + } + override def paintChildren(g: Graphics) { + Component.this.paintChildren(g.asInstanceOf[Graphics2D]) + } + def __super__paintChildren(g: Graphics) { + super.paintChildren(g) + } + override def paint(g: Graphics) { Component.this.paint(g.asInstanceOf[Graphics2D]) } @@ -245,14 +258,28 @@ abstract class Component extends UIElement { protected def paintComponent(g: Graphics2D) { peer match { case peer: SuperMixin => peer.__super__paintComponent(g) - case _ => // it's a wrapper created on the fly + case _ => + } + } + + protected def paintBorder(g: Graphics2D) { + peer match { + case peer: SuperMixin => peer.__super__paintBorder(g) + case _ => + } + } + + protected def paintChildren(g: Graphics2D) { + peer match { + case peer: SuperMixin => peer.__super__paintChildren(g) + case _ => } } - protected def paint(g: Graphics2D) { + def paint(g: Graphics2D) { peer match { case peer: SuperMixin => peer.__super__paint(g) - case _ => // it's a wrapper created on the fly + case _ => peer.paint(g) } } diff --git a/src/swing/scala/swing/Container.scala b/src/swing/scala/swing/Container.scala index c540353948..fba1ab87a3 100644 --- a/src/swing/scala/swing/Container.scala +++ b/src/swing/scala/swing/Container.scala @@ -35,7 +35,7 @@ object Container { protected def insertAt(n: Int, c: Component) { peer.add(c.peer, n) } def +=(c: Component): this.type = { peer.add(c.peer) ; this } def length = peer.getComponentCount - def apply(n: Int) = UIElement.cachedWrapper(peer.getComponent(n)) + def apply(n: Int) = UIElement.cachedWrapper[Component](peer.getComponent(n)) } peer.addContainerListener(new java.awt.event.ContainerListener { diff --git a/src/swing/scala/swing/EditorPane.scala b/src/swing/scala/swing/EditorPane.scala index a258865508..0175d6140a 100644 --- a/src/swing/scala/swing/EditorPane.scala +++ b/src/swing/scala/swing/EditorPane.scala @@ -13,7 +13,6 @@ package scala.swing import event._ import javax.swing._ import javax.swing.text._ -import java.awt.Color import java.awt.event._ /** diff --git a/src/swing/scala/swing/FlowPanel.scala b/src/swing/scala/swing/FlowPanel.scala index 0778d7bca9..5047a622f0 100644 --- a/src/swing/scala/swing/FlowPanel.scala +++ b/src/swing/scala/swing/FlowPanel.scala @@ -29,9 +29,13 @@ object FlowPanel { * * @see java.awt.FlowLayout */ -class FlowPanel(alignment: FlowPanel.Alignment.Value) extends Panel with SequentialContainer.Wrapper { +class FlowPanel(alignment: FlowPanel.Alignment.Value)(contents0: Component*) extends Panel with SequentialContainer.Wrapper { override lazy val peer: javax.swing.JPanel = new javax.swing.JPanel(new java.awt.FlowLayout(alignment.id)) - def this() = this(FlowPanel.Alignment.Center) + def this(contents0: Component*) = this(FlowPanel.Alignment.Center)(contents0: _*) + def this() = this(FlowPanel.Alignment.Center)() + + contents ++= contents0 + private def layoutManager = peer.getLayout.asInstanceOf[java.awt.FlowLayout] def vGap: Int = layoutManager.getVgap diff --git a/src/swing/scala/swing/GUIApplication.scala b/src/swing/scala/swing/GUIApplication.scala index a3965fcec8..07b06e1b38 100644 --- a/src/swing/scala/swing/GUIApplication.scala +++ b/src/swing/scala/swing/GUIApplication.scala @@ -17,7 +17,7 @@ import javax.swing._ /** * Convenience class with utility methods for GUI applications. */ -class GUIApplication { +@deprecated("Use SwingApplication instead") class GUIApplication { /** * Called before the GUI is created. Override to customize. diff --git a/src/swing/scala/swing/GridBagPanel.scala b/src/swing/scala/swing/GridBagPanel.scala index c81ebeb8fa..15f506350d 100644 --- a/src/swing/scala/swing/GridBagPanel.scala +++ b/src/swing/scala/swing/GridBagPanel.scala @@ -11,7 +11,7 @@ package scala.swing -import java.awt.{Insets, GridBagConstraints} +import java.awt.{GridBagConstraints} object GridBagPanel { diff --git a/src/swing/scala/swing/ListView.scala b/src/swing/scala/swing/ListView.scala index 0712f78d57..4841cb3ee7 100644 --- a/src/swing/scala/swing/ListView.scala +++ b/src/swing/scala/swing/ListView.scala @@ -14,7 +14,6 @@ package scala.swing import event._ import javax.swing._ import javax.swing.event._ -import java.awt.Color object ListView { /** @@ -188,24 +187,32 @@ class ListView[A] extends Component { def iterator = a.iterator } + def leadIndex: Int = peer.getSelectionModel.getLeadSelectionIndex + def anchorIndex: Int = peer.getSelectionModel.getAnchorSelectionIndex + /** * The indices of the currently selected items. */ object indices extends Indices(peer.getSelectedIndices) { def -=(n: Int): this.type = { peer.removeSelectionInterval(n,n); this } def +=(n: Int): this.type = { peer.addSelectionInterval(n,n); this } - + @deprecated("Use ListView.selection.leadIndex") def leadIndex: Int = peer.getSelectionModel.getLeadSelectionIndex + @deprecated("Use ListView.selection.anchorIndex") def anchorIndex: Int = peer.getSelectionModel.getAnchorSelectionIndex } + + @deprecated("Use ListView.selectIndices") def selectIndices(ind: Int*) = peer.setSelectedIndices(ind.toArray) /** * The currently selected items. */ object items extends scala.collection.SeqProxy[A] { - def self = peer.getSelectedValues.toSeq.map(_.asInstanceOf[A]) + def self = peer.getSelectedValues.map(_.asInstanceOf[A]) + @deprecated("Use ListView.selection.leadIndex") def leadIndex: Int = peer.getSelectionModel.getLeadSelectionIndex + @deprecated("Use ListView.selection.anchorIndex") def anchorIndex: Int = peer.getSelectionModel.getAnchorSelectionIndex } @@ -214,7 +221,7 @@ class ListView[A] extends Component { peer.getSelectionModel.addListSelectionListener(new ListSelectionListener { def valueChanged(e: javax.swing.event.ListSelectionEvent) { - publish(ListSelectionChanged(ListView.this, e.getFirstIndex to e.getLastIndex, e.getValueIsAdjusting)) + publish(new ListSelectionChanged(ListView.this, e.getFirstIndex to e.getLastIndex, e.getValueIsAdjusting)) } }) @@ -238,6 +245,8 @@ class ListView[A] extends Component { def selectionBackground: Color = peer.getSelectionBackground def selectionBackground_=(c: Color) = peer.setSelectionBackground(c) + def selectIndices(ind: Int*) = peer.setSelectedIndices(ind.toArray) + peer.getModel.addListDataListener(new ListDataListener { def contentsChanged(e: ListDataEvent) { publish(ListChanged(ListView.this)) } def intervalRemoved(e: ListDataEvent) { publish(ListElementsRemoved(ListView.this, e.getIndex0 to e.getIndex1)) } diff --git a/src/swing/scala/swing/Menu.scala b/src/swing/scala/swing/Menu.scala index 360d77826c..1879725821 100644 --- a/src/swing/scala/swing/Menu.scala +++ b/src/swing/scala/swing/Menu.scala @@ -14,6 +14,10 @@ package scala.swing import scala.collection.mutable._ import javax.swing._ +object MenuBar { + case object NoMenuBar extends MenuBar +} + /** * A menu bar. Each window can contain at most one. Contains a number of menus. * diff --git a/src/swing/scala/swing/Publisher.scala b/src/swing/scala/swing/Publisher.scala index 9a1f0ec6f1..4603f3e62b 100644 --- a/src/swing/scala/swing/Publisher.scala +++ b/src/swing/scala/swing/Publisher.scala @@ -41,8 +41,8 @@ trait Publisher extends Reactor { } } - def subscribe(listener: Reaction) { listeners += listener } - def unsubscribe(listener: Reaction) { listeners -= listener } + private[swing] def subscribe(listener: Reaction) { listeners += listener } + private[swing] def unsubscribe(listener: Reaction) { listeners -= listener } /** * Notify all registered reactions. @@ -138,7 +138,7 @@ abstract class RefBuffer[A <: AnyRef] extends Buffer[A] with SingleRefCollection protected val underlying: Buffer[Reference[A]] def +=(el: A): this.type = { purgeReferences(); underlying += Ref(el); this } - def +=:(el: A) = { purgeReferences(); Ref(el) +: underlying; this } + def +=:(el: A) = { purgeReferences(); Ref(el) +=: underlying; this } def remove(el: A) { underlying -= Ref(el); purgeReferences(); } def remove(n: Int) = { val el = apply(n); remove(el); el } def insertAll(n: Int, iter: Iterable[A]) { @@ -146,11 +146,6 @@ abstract class RefBuffer[A <: AnyRef] extends Buffer[A] with SingleRefCollection underlying.insertAll(n, iter.view.map(Ref(_))) } def update(n: Int, el: A) { purgeReferences(); underlying(n) = Ref(el) } - override def readOnly : Seq[A] = new Seq[A] { - def length = self.length - def iterator = self.iterator - def apply(n: Int) = self(n) - } def apply(n: Int) = { purgeReferences() var el = underlying(n).get diff --git a/src/swing/scala/swing/RichWindow.scala b/src/swing/scala/swing/RichWindows.scala index cdcf918cc5..c4a72b3d20 100644 --- a/src/swing/scala/swing/RichWindow.scala +++ b/src/swing/scala/swing/RichWindows.scala @@ -11,7 +11,7 @@ package scala.swing -import java.awt.{Image, Window => AWTWindow, Frame => AWTFrame} +import java.awt.{Window => AWTWindow, Frame => AWTFrame} import javax.swing._ import Swing._ @@ -49,8 +49,19 @@ sealed trait RichWindow extends Window { def title: String = peer.getTitle def title_=(s: String) = peer.setTitle(s) - def menuBar: MenuBar = UIElement.cachedWrapper(peer.getJMenuBar) - def menuBar_=(m: MenuBar) = peer.setJMenuBar(m.peer) + /** + * The menu bar of this frame or `NoMenuBar` if no menu bar is set. + */ + def menuBar: MenuBar = { + val m = UIElement.cachedWrapper(peer.getJMenuBar) + if (m != null) m else MenuBar.NoMenuBar + } + /** + * Set the current menu bar of this frame. Pass `NoMenuBar` if this frame + * should not show a menu bar. + */ + def menuBar_=(m: MenuBar) = + peer.setJMenuBar(if(m == MenuBar.NoMenuBar) null else m.peer) def resizable_=(b: Boolean) { peer.setResizable(b) } def resizable = peer.isResizable diff --git a/src/swing/scala/swing/Scrollable.scala b/src/swing/scala/swing/Scrollable.scala index f59cb8b5d1..f5e3116c11 100644 --- a/src/swing/scala/swing/Scrollable.scala +++ b/src/swing/scala/swing/Scrollable.scala @@ -11,8 +11,6 @@ package scala.swing -import java.awt.{Rectangle, Dimension} - object Scrollable { trait Wrapper extends Scrollable { protected def scrollablePeer: javax.swing.Scrollable diff --git a/src/swing/scala/swing/SimpleGUIApplication.scala b/src/swing/scala/swing/SimpleGUIApplication.scala index ff6204049c..e349a0b65f 100644 --- a/src/swing/scala/swing/SimpleGUIApplication.scala +++ b/src/swing/scala/swing/SimpleGUIApplication.scala @@ -22,7 +22,7 @@ import javax.swing._ * the EDT (see Swing.onEDT and Swing.onEDTWait). Lazy values are okay for the same reason * if they are intialized on the EDT always. */ -abstract class SimpleGUIApplication extends GUIApplication { +@deprecated("Use SimpleSwingApplication instead") abstract class SimpleGUIApplication extends GUIApplication { /** * A GUI application's version of the main method. Called by the default diff --git a/src/swing/scala/swing/SimpleSwingApplication.scala b/src/swing/scala/swing/SimpleSwingApplication.scala new file mode 100644 index 0000000000..9f66cc5be5 --- /dev/null +++ b/src/swing/scala/swing/SimpleSwingApplication.scala @@ -0,0 +1,17 @@ +package scala.swing + +abstract class SimpleSwingApplication extends SwingApplication { + def top: Frame + + override def startup(args: Array[String]) { + val t = top + t.pack() + t.visible = true + } + + def resourceFromClassloader(path: String): java.net.URL = + this.getClass.getResource(path) + + def resourceFromUserDirectory(path: String): java.io.File = + new java.io.File(System.getProperty("user.dir"), path) +} diff --git a/src/swing/scala/swing/Slider.scala b/src/swing/scala/swing/Slider.scala index 8059bfaef5..53d7efa5e3 100644 --- a/src/swing/scala/swing/Slider.scala +++ b/src/swing/scala/swing/Slider.scala @@ -65,7 +65,7 @@ class Slider extends Component with Orientable.Wrapper with Publisher { peer.addChangeListener(new javax.swing.event.ChangeListener { def stateChanged(e: javax.swing.event.ChangeEvent) { - publish(ValueChanged(Slider.this)) + publish(new ValueChanged(Slider.this)) } }) } diff --git a/src/swing/scala/swing/Swing.scala b/src/swing/scala/swing/Swing.scala index 430e89a935..15bf30bb44 100644 --- a/src/swing/scala/swing/Swing.scala +++ b/src/swing/scala/swing/Swing.scala @@ -13,7 +13,6 @@ package scala.swing import java.awt.event._ import javax.swing.event._ -import java.awt.{Color, Dimension, Point, Rectangle} import javax.swing.border._ import javax.swing.{JComponent, Icon, BorderFactory, SwingUtilities} diff --git a/src/swing/scala/swing/SwingApplication.scala b/src/swing/scala/swing/SwingApplication.scala new file mode 100644 index 0000000000..e4a51ca5b3 --- /dev/null +++ b/src/swing/scala/swing/SwingApplication.scala @@ -0,0 +1,9 @@ +package scala.swing + +abstract class SwingApplication extends Reactor { + def main(args: Array[String]) = Swing.onEDT { startup(args) } + + def startup(args: Array[String]) + def quit() { shutdown(); System.exit(0) } + def shutdown() {} +} diff --git a/src/swing/scala/swing/SwingWorker.scala b/src/swing/scala/swing/SwingWorker.scala new file mode 100644 index 0000000000..0e514e38a7 --- /dev/null +++ b/src/swing/scala/swing/SwingWorker.scala @@ -0,0 +1,21 @@ +package scala.swing + +import scala.actors._ + +object SwingWorker { + +} + +abstract class SwingWorker extends Actor { + def queue() { + + } + + def done() { + + } + + private var _cancelled = false + def cancelled: Boolean = _cancelled + def cancelled_=(b: Boolean) { _cancelled = b } +}
\ No newline at end of file diff --git a/src/swing/scala/swing/TabbedPane.scala b/src/swing/scala/swing/TabbedPane.scala index 5d634c7082..5183bf25ca 100644 --- a/src/swing/scala/swing/TabbedPane.scala +++ b/src/swing/scala/swing/TabbedPane.scala @@ -14,7 +14,6 @@ package scala.swing import event._ import scala.collection.mutable.Buffer import javax.swing.{JTabbedPane, JComponent} -import java.awt.{Color, Rectangle} object TabbedPane { @@ -37,8 +36,12 @@ object TabbedPane { protected[TabbedPane] var parent: TabbedPane = parent0 protected var _title = title0 - def title: String = _title//parent.peer.getTitleAt(index) - def title_=(t: String) { _title = title0; if (parent != null) parent.peer.setTitleAt(index, t) } + def title: String = _title + def title_=(t: String) { + // beware to keep this order since, index depends on the _old_ title + if (parent != null) parent.peer.setTitleAt(index, t) + _title = t + } protected var _content = content0 def content: Component = _content//UIElement.cachedWrapper(peer.getComponentAt(index).asInstanceOf[JComponent]) def content_=(c: Component) { _content = c; if (parent != null) parent.peer.setComponentAt(index, c.peer) } diff --git a/src/swing/scala/swing/Table.scala b/src/swing/scala/swing/Table.scala index 88f19f5f02..47d0b43c60 100644 --- a/src/swing/scala/swing/Table.scala +++ b/src/swing/scala/swing/Table.scala @@ -15,7 +15,6 @@ import event._ import javax.swing._ import javax.swing.table._ import javax.swing.event._ -import java.awt.{Dimension, Color} import scala.collection.mutable.{Set, IndexedSeq} object Table { diff --git a/src/swing/scala/swing/TextComponent.scala b/src/swing/scala/swing/TextComponent.scala index 3b81b567bb..3ed495ad2f 100644 --- a/src/swing/scala/swing/TextComponent.scala +++ b/src/swing/scala/swing/TextComponent.scala @@ -15,7 +15,6 @@ import event._ import javax.swing._ import javax.swing.text._ import javax.swing.event._ -import java.awt.Color object TextComponent { trait HasColumns extends TextComponent { @@ -72,8 +71,8 @@ class TextComponent extends Component with Publisher { def selectAll() { peer.selectAll() } peer.getDocument.addDocumentListener(new DocumentListener { - def changedUpdate(e:DocumentEvent) { publish(ValueChanged(TextComponent.this)) } - def insertUpdate(e:DocumentEvent) { publish(ValueChanged(TextComponent.this)) } - def removeUpdate(e:DocumentEvent) { publish(ValueChanged(TextComponent.this)) } + def changedUpdate(e:DocumentEvent) { publish(new ValueChanged(TextComponent.this)) } + def insertUpdate(e:DocumentEvent) { publish(new ValueChanged(TextComponent.this)) } + def removeUpdate(e:DocumentEvent) { publish(new ValueChanged(TextComponent.this)) } }) } diff --git a/src/swing/scala/swing/TextField.scala b/src/swing/scala/swing/TextField.scala index acb34b9a1b..7067062d68 100644 --- a/src/swing/scala/swing/TextField.scala +++ b/src/swing/scala/swing/TextField.scala @@ -39,6 +39,11 @@ class TextField(text0: String, columns0: Int) extends TextComponent with TextCom def columns: Int = peer.getColumns def columns_=(n: Int) = peer.setColumns(n) + /** @see javax.swing.JTextField#getHorizontalAlignment() */ + def horizontalAlignment: Alignment.Value = Alignment(peer.getHorizontalAlignment) + /** @see javax.swing.JTextField#setHorizontalAlignment() */ + def horizontalAlignment_=(x: Alignment.Value) { peer.setHorizontalAlignment(x.id) } + private lazy val actionListener = Swing.ActionListener { e => publish(EditDone(TextField.this)) } diff --git a/src/swing/scala/swing/UIElement.scala b/src/swing/scala/swing/UIElement.scala index f8f050b3d6..599c671538 100644 --- a/src/swing/scala/swing/UIElement.scala +++ b/src/swing/scala/swing/UIElement.scala @@ -11,8 +11,8 @@ package scala.swing +import java.awt.Cursor import event._ -import java.awt.{Color, Cursor, Font, Dimension, Rectangle} import scala.collection.mutable.HashMap import scala.ref._ import java.util.WeakHashMap diff --git a/src/swing/scala/swing/Window.scala b/src/swing/scala/swing/Window.scala index bc333db9ca..b435d8041c 100644 --- a/src/swing/scala/swing/Window.scala +++ b/src/swing/scala/swing/Window.scala @@ -11,8 +11,8 @@ package scala.swing +import java.awt.{Window => AWTWindow} import event._ -import java.awt.{Image, Point, Window => AWTWindow} import javax.swing._ /** @@ -26,10 +26,7 @@ import javax.swing._ abstract class Window extends UIElement with RootPanel with Publisher { outer => def peer: AWTWindow with InterfaceMixin - protected trait InterfaceMixin extends javax.swing.RootPaneContainer { - def getRootPane: JRootPane - //protected def setRootPane(p: JRootPane) - } + protected trait InterfaceMixin extends javax.swing.RootPaneContainer /** * This method is called when the window is closing, after all other window diff --git a/src/swing/scala/swing/event/ActionEvent.scala b/src/swing/scala/swing/event/ActionEvent.scala index 357b78be70..1f3f795da8 100644 --- a/src/swing/scala/swing/event/ActionEvent.scala +++ b/src/swing/scala/swing/event/ActionEvent.scala @@ -12,4 +12,8 @@ package scala.swing package event -case class ActionEvent(override val source: Component) extends ComponentEvent +object ActionEvent { + def unapply(a: ActionEvent): Option[Component] = Some(a.source) +} + +class ActionEvent(override val source: Component) extends ComponentEvent diff --git a/src/swing/scala/swing/event/SelectionEvent.scala b/src/swing/scala/swing/event/SelectionEvent.scala index c5aad07f7f..ca0c0fabb7 100644 --- a/src/swing/scala/swing/event/SelectionEvent.scala +++ b/src/swing/scala/swing/event/SelectionEvent.scala @@ -25,5 +25,11 @@ trait ListSelectionEvent extends SelectionEvent { } case class SelectionChanged(override val source: Component) extends ComponentEvent with SelectionEvent -case class ListSelectionChanged[A](override val source: ListView[A], range: Range, live: Boolean) + +object ListSelectionChanged { + def unapply[A](e: ListSelectionChanged[A]): Option[(ListView[A], Range, Boolean)] = + Some((e.source, e.range, e.live)) +} + +class ListSelectionChanged[A](override val source: ListView[A], val range: Range, val live: Boolean) extends SelectionChanged(source) with ListEvent[A] diff --git a/src/swing/scala/swing/event/TableEvent.scala b/src/swing/scala/swing/event/TableEvent.scala index 3c684c483f..101f6dd5d7 100644 --- a/src/swing/scala/swing/event/TableEvent.scala +++ b/src/swing/scala/swing/event/TableEvent.scala @@ -37,7 +37,7 @@ case class TableUpdated(override val source: Table, range: Range, column: Int) /** * Any change that caused the table to change it's size */ -case class TableResized(override val source: Table) extends TableChange(source) +class TableResized(override val source: Table) extends TableChange(source) case class TableRowsAdded(override val source: Table, range: Range) extends TableResized(source) case class TableRowsRemoved(override val source: Table, range: Range) extends TableResized(source) diff --git a/src/swing/scala/swing/event/ValueChanged.scala b/src/swing/scala/swing/event/ValueChanged.scala index 0c6689eeef..dd64615cee 100644 --- a/src/swing/scala/swing/event/ValueChanged.scala +++ b/src/swing/scala/swing/event/ValueChanged.scala @@ -12,4 +12,8 @@ package scala.swing package event -case class ValueChanged(override val source: Component) extends ComponentEvent +object ValueChanged { + def unapply(a: ValueChanged): Option[Component] = Some(a.source) +} + +class ValueChanged(override val source: Component) extends ComponentEvent diff --git a/src/swing/scala/swing/package.scala b/src/swing/scala/swing/package.scala new file mode 100644 index 0000000000..8f4c281a4b --- /dev/null +++ b/src/swing/scala/swing/package.scala @@ -0,0 +1,90 @@ +package scala + +/** + * Useful imports that don't have wrappers. + */ +package object swing { + type Point = java.awt.Point + type Dimension = java.awt.Dimension + type Rectangle = java.awt.Rectangle + type Insets = java.awt.Insets + + type Graphics2D = java.awt.Graphics2D + type Color = java.awt.Color + type Image = java.awt.Image + type Font = java.awt.Font +} + +object Font { + import swing._ + + def apply(fontFormat: Int, fontFile: java.io.File) = java.awt.Font.createFont(fontFormat, fontFile) + def apply(fontFormat: Int, fontStream: java.io.InputStream) = java.awt.Font.createFont(fontFormat, fontStream) + def decode(str: String) = java.awt.Font.decode(str) + + /* TODO: finish implementation + /** + * See [java.awt.Font.getFont]. + */ + def get(attributes: Map[_ <: java.text.AttributedCharacterIterator.Attribute, _]) = + java.awt.Font.getFont(ImmutableMapWrapper(attributes)) + + import java.{util => ju} + private case class ImmutableMapWrapper[A, B](underlying : Map[A, B])(m : ClassManifest[A]) extends ju.AbstractMap[A, B] { + self => + override def size = underlying.size + + override def put(k : A, v : B) = + throw new UnsupportedOperationException("This is a wrapper that does not support mutation") + override def remove(k : AnyRef) = + throw new UnsupportedOperationException("This is a wrapper that does not support mutation") + + override def entrySet : ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] { + def size = self.size + + def iterator = new ju.Iterator[ju.Map.Entry[A, B]] { + val ui = underlying.iterator + var prev : Option[A] = None + + def hasNext = ui.hasNext + + def next = { + val (k, v) = ui.next + prev = Some(k) + new ju.Map.Entry[A, B] { + def getKey = k + def getValue = v + def setValue(v1 : B) = self.put(k, v1) + override def equals(other : Any) = other match { + case e : ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue + case _ => false + } + } + } + + def remove = prev match { + case Some(k) => val v = self.remove(k.asInstanceOf[AnyRef]) ; prev = None ; v + case _ => throw new IllegalStateException("next must be called at least once before remove") + } + } + } + } + */ + + /** + * See [java.awt.Font.getFont]. + */ + def get(nm: String) = java.awt.Font.getFont(nm) + /** + * See [java.awt.Font.getFont]. + */ + def get(nm: String, font: Font) = java.awt.Font.getFont(nm, font) + + + def Insets(x: Int, y: Int, width: Int, height: Int) = new Insets(x, y, width, height) + def Rectangle(x: Int, y: Int, width: Int, height: Int) = new Insets(x, y, width, height) + def Point(x: Int, y: Int) = new Point(x, y) + def Dimension(x: Int, y: Int) = new Dimension(x, y) + + +}
\ No newline at end of file diff --git a/src/swing/scala/swing/test/ButtonApp.scala b/src/swing/scala/swing/test/ButtonApp.scala index 163da63612..dcf567d365 100644 --- a/src/swing/scala/swing/test/ButtonApp.scala +++ b/src/swing/scala/swing/test/ButtonApp.scala @@ -6,7 +6,7 @@ import java.awt.Dimension import swing._ import swing.event._ -object ButtonApp extends SimpleGUIApplication { +object ButtonApp extends SimpleSwingApplication { def top = new MainFrame { title = "My Frame" contents = new GridPanel(2, 2) { @@ -22,3 +22,4 @@ object ButtonApp extends SimpleGUIApplication { size = new Dimension(300, 80) } } + diff --git a/src/swing/scala/swing/test/CelsiusConverter.scala b/src/swing/scala/swing/test/CelsiusConverter.scala index 00a65e2a65..4ead632d7a 100644 --- a/src/swing/scala/swing/test/CelsiusConverter.scala +++ b/src/swing/scala/swing/test/CelsiusConverter.scala @@ -6,7 +6,7 @@ import event._ /** A GUI app to convert celsius to centigrade */ -object CelsiusConverter extends SimpleGUIApplication { +object CelsiusConverter extends SimpleSwingApplication { def top = new MainFrame { title = "Convert Celsius to Fahrenheit" val tempCelsius = new TextField diff --git a/src/swing/scala/swing/test/CelsiusConverter2.scala b/src/swing/scala/swing/test/CelsiusConverter2.scala index 9ec0550f66..5ce1b157fe 100644 --- a/src/swing/scala/swing/test/CelsiusConverter2.scala +++ b/src/swing/scala/swing/test/CelsiusConverter2.scala @@ -4,25 +4,30 @@ package test import swing._ import event._ -object CelsiusConverter2 extends SimpleGUIApplication { - lazy val ui = new FlowPanel { - val Celsius = new TextField { text = "0"; columns = 5 } - val Fahrenheit = new TextField { text = "0"; columns = 5 } - contents.append(Celsius, new Label(" Celsius = "), - Fahrenheit, new Label(" Fahrenheit")) - border = Swing.EmptyBorder(15, 10, 10, 10) +object CelsiusConverter2 extends SimpleSwingApplication { + def newField = new TextField { + text = "0" + columns = 5 + horizontalAlignment = Alignment.Right + } + val celsius = newField + val fahrenheit = newField - listenTo(Fahrenheit, Celsius) - reactions += { - case EditDone(Fahrenheit) => - val f = Integer.parseInt(Fahrenheit.text) - val c = (f - 32) * 5 / 9 - Celsius.text = c.toString - case EditDone(Celsius) => - val c = Integer.parseInt(Celsius.text) - val f = c * 9 / 5 + 32 - Fahrenheit.text = f.toString - } + listenTo(fahrenheit, celsius) + reactions += { + case EditDone(`fahrenheit`) => + val f = Integer.parseInt(fahrenheit.text) + val c = (f - 32) * 5 / 9 + celsius.text = c.toString + case EditDone(`celsius`) => + val c = Integer.parseInt(celsius.text) + val f = c * 9 / 5 + 32 + fahrenheit.text = f.toString + } + + lazy val ui = new FlowPanel(celsius, new Label(" Celsius = "), + fahrenheit, new Label(" Fahrenheit")) { + border = Swing.EmptyBorder(15, 10, 10, 10) } def top = new MainFrame { title = "Convert Celsius / Fahrenheit" diff --git a/src/swing/scala/swing/test/ComboBoxes.scala b/src/swing/scala/swing/test/ComboBoxes.scala index 1241955304..cf1a70d97b 100644 --- a/src/swing/scala/swing/test/ComboBoxes.scala +++ b/src/swing/scala/swing/test/ComboBoxes.scala @@ -13,7 +13,7 @@ import javax.swing.{Icon, ImageIcon} * * TODO: clean up layout */ -object ComboBoxes extends SimpleGUIApplication { +object ComboBoxes extends SimpleSwingApplication { import ComboBox._ lazy val ui = new FlowPanel { contents += new ComboBox(List(1,2,3,4)) diff --git a/src/swing/scala/swing/test/CountButton.scala b/src/swing/scala/swing/test/CountButton.scala index 88464def2c..373db785ba 100644 --- a/src/swing/scala/swing/test/CountButton.scala +++ b/src/swing/scala/swing/test/CountButton.scala @@ -4,7 +4,7 @@ package test import scala.swing._ import scala.swing.event._ -object CountButton extends SimpleGUIApplication { +object CountButton extends SimpleSwingApplication { def top = new MainFrame { title = "My Frame" contents = new GridPanel(2, 2) { diff --git a/src/swing/scala/swing/test/Dialogs.scala b/src/swing/scala/swing/test/Dialogs.scala index f9a7ad4c88..14fa2febf2 100644 --- a/src/swing/scala/swing/test/Dialogs.scala +++ b/src/swing/scala/swing/test/Dialogs.scala @@ -4,7 +4,7 @@ package test import swing._ import swing.event._ -object Dialogs extends SimpleGUIApplication { +object Dialogs extends SimpleSwingApplication { import TabbedPane._ lazy val label = new Label("No Result yet") diff --git a/src/swing/scala/swing/test/GridBagDemo.scala b/src/swing/scala/swing/test/GridBagDemo.scala index 8f05ddacc2..ebb538f1c0 100644 --- a/src/swing/scala/swing/test/GridBagDemo.scala +++ b/src/swing/scala/swing/test/GridBagDemo.scala @@ -6,7 +6,7 @@ import swing.event._ import GridBagPanel._ import java.awt.Insets -object GridBagDemo extends SimpleGUIApplication { +object GridBagDemo extends SimpleSwingApplication { lazy val ui = new GridBagPanel { val c = new Constraints val shouldFill = true diff --git a/src/swing/scala/swing/test/HelloWorld.scala b/src/swing/scala/swing/test/HelloWorld.scala index c1bad84782..6014a14b2d 100644 --- a/src/swing/scala/swing/test/HelloWorld.scala +++ b/src/swing/scala/swing/test/HelloWorld.scala @@ -6,13 +6,9 @@ import swing._ /** * A simple swing demo. */ -object HelloWorld extends GUIApplication { - def main(args: Array[String]) = run { - val frame = new MainFrame { - title = "HelloWorldSwing" - contents = new Label("Hello World") - } - frame.pack() - frame.visible = true +object HelloWorld extends SimpleSwingApplication { + def top = new MainFrame { + title = "Hello, World!" + contents = new Button("Click Me!") } -} +}
\ No newline at end of file diff --git a/src/swing/scala/swing/test/LabelTest.scala b/src/swing/scala/swing/test/LabelTest.scala index d2c9745c94..47eedb84ac 100644 --- a/src/swing/scala/swing/test/LabelTest.scala +++ b/src/swing/scala/swing/test/LabelTest.scala @@ -4,7 +4,7 @@ package test import scala.swing._ import scala.swing.event._ -object LabelTest extends SimpleGUIApplication{ +object LabelTest extends SimpleSwingApplication { def top = new MainFrame{ contents = new Label { text = "Hello" diff --git a/src/swing/scala/swing/test/LinePainting.scala b/src/swing/scala/swing/test/LinePainting.scala index a5f8475c99..78a94dbab7 100644 --- a/src/swing/scala/swing/test/LinePainting.scala +++ b/src/swing/scala/swing/test/LinePainting.scala @@ -10,7 +10,7 @@ import java.awt.{Color, Dimension, Graphics, Graphics2D, Point, geom} * * @author Frank Teubler, Ingo Maier */ -object LinePainting extends SimpleGUIApplication { +object LinePainting extends SimpleSwingApplication { lazy val ui = new Panel { background = Color.white preferredSize = (200,200) diff --git a/src/swing/scala/swing/test/ListViewDemo.scala b/src/swing/scala/swing/test/ListViewDemo.scala new file mode 100644 index 0000000000..2b8c8c0719 --- /dev/null +++ b/src/swing/scala/swing/test/ListViewDemo.scala @@ -0,0 +1,18 @@ +package scala.swing +package test + +object ListViewDemo extends SimpleSwingApplication { + def top = new MainFrame { + case class City(name: String, country: String, population: Int, capital: Boolean) + val items = List(City("Lausanne", "Switzerland", 129273, false), + City("Paris", "France", 2203817, true), + City("New York", "USA", 8363710 , false), + City("Berlin", "Germany", 3416300, true), + City("Tokio", "Japan", 12787981, true)) + import ListView._ + contents = new FlowPanel(new ScrollPane(new ListView(items) { + renderer = Renderer(_.name) + })) + //new ScrollPane(new Table(items))) + } +} diff --git a/src/swing/scala/swing/test/SwingApp.scala b/src/swing/scala/swing/test/SwingApp.scala index fe14360ef4..b47d778d3a 100644 --- a/src/swing/scala/swing/test/SwingApp.scala +++ b/src/swing/scala/swing/test/SwingApp.scala @@ -4,7 +4,7 @@ package test import swing._ import swing.event._ -object SwingApp extends SimpleGUIApplication { +object SwingApp extends SimpleSwingApplication { def top = new MainFrame { title = "SwingApp" var numclicks = 0 diff --git a/src/swing/scala/swing/test/TableSelection.scala b/src/swing/scala/swing/test/TableSelection.scala index 75a07876a6..bbfef80277 100644 --- a/src/swing/scala/swing/test/TableSelection.scala +++ b/src/swing/scala/swing/test/TableSelection.scala @@ -2,10 +2,9 @@ package scala.swing package test import java.awt.Dimension -import swing._ import swing.event._ -object TableSelection extends SimpleGUIApplication { +object TableSelection extends SimpleSwingApplication { val model = Array(List("Mary", "Campione", "Snowboarding", 5, false).toArray, List("Alison", "Huml", "Rowing", 5, false).toArray, List("Kathy", "Walrath", "Knitting", 5, false).toArray, diff --git a/src/swing/scala/swing/test/UIDemo.scala b/src/swing/scala/swing/test/UIDemo.scala index 072fe0ecd2..ce40fe2056 100644 --- a/src/swing/scala/swing/test/UIDemo.scala +++ b/src/swing/scala/swing/test/UIDemo.scala @@ -4,36 +4,43 @@ package test import swing._ import event._ import Swing._ +import ListView._ -object UIDemo extends SimpleGUIApplication { +object UIDemo extends SimpleSwingApplication { def top = new MainFrame { - title = "UIElement Test" - menuBar = new MenuBar + title = "Scala Swing Demo" - val menu = new Menu("A Menu") - menu.contents += new MenuItem("An item") - menu.contents += new MenuItem(Action("An action item") { - println("Action '"+ title +"' invoked") - }) - menu.contents += new Separator - menu.contents += new CheckMenuItem("Check me") - menu.contents += new CheckMenuItem("Me too!") - menu.contents += new Separator - val a = new RadioMenuItem("a") - val b = new RadioMenuItem("b") - val c = new RadioMenuItem("c") - val mutex = new ButtonGroup(a,b,c) - menu.contents ++= mutex.buttons - - menuBar.contents += menu - menuBar.contents += new Menu("Empty Menu") - - var reactLive = false - - import Swing._ + /* + * Create a menu bar with a couple of menus and menu items and + * set the result as this frame's menu bar. + */ + menuBar = new MenuBar { + contents += new Menu("A Menu") { + contents += new MenuItem("An item") + contents += new MenuItem(Action("An action item") { + println("Action '"+ title +"' invoked") + }) + contents += new Separator + contents += new CheckMenuItem("Check me") + contents += new CheckMenuItem("Me too!") + contents += new Separator + val a = new RadioMenuItem("a") + val b = new RadioMenuItem("b") + val c = new RadioMenuItem("c") + val mutex = new ButtonGroup(a,b,c) + contents ++= mutex.buttons + } + contents += new Menu("Empty Menu") + } + /* + * The root component in this frame is a panel with a border layout. + */ contents = new BorderPanel { import BorderPanel.Position._ + + var reactLive = false + val tabs = new TabbedPane { import TabbedPane._ val buttons = new FlowPanel { @@ -42,29 +49,29 @@ object UIDemo extends SimpleGUIApplication { contents += new BoxPanel(Orientation.Vertical) { border = CompoundBorder(TitledBorder(EtchedBorder, "Radio Buttons"), EmptyBorder(5,5,5,10)) val a = new RadioButton("Green Vegetables") - val b = new RadioButton("Red Meat") - val c = new RadioButton("White Tofu") - val mutex = new ButtonGroup(a,b,c) - contents ++= mutex.buttons + val b = new RadioButton("Red Meat") + val c = new RadioButton("White Tofu") + val mutex = new ButtonGroup(a,b,c) + contents ++= mutex.buttons } contents += new BoxPanel(Orientation.Vertical) { border = CompoundBorder(TitledBorder(EtchedBorder, "Check Boxes"), EmptyBorder(5,5,5,10)) val paintLabels = new CheckBox("Paint Labels") - val paintTicks = new CheckBox("Paint Ticks") - val snapTicks = new CheckBox("Snap To Ticks") - val live = new CheckBox("Live") - contents.append(paintLabels, paintTicks, snapTicks, live) - listenTo(paintLabels, paintTicks, snapTicks, live) - reactions += { - case ButtonClicked(`paintLabels`) => - slider.paintLabels = paintLabels.selected - case ButtonClicked(`paintTicks`) => - slider.paintTicks = paintTicks.selected - case ButtonClicked(`snapTicks`) => - slider.snapToTicks = snapTicks.selected - case ButtonClicked(`live`) => - reactLive = live.selected - } + val paintTicks = new CheckBox("Paint Ticks") + val snapTicks = new CheckBox("Snap To Ticks") + val live = new CheckBox("Live") + contents.append(paintLabels, paintTicks, snapTicks, live) + listenTo(paintLabels, paintTicks, snapTicks, live) + reactions += { + case ButtonClicked(`paintLabels`) => + slider.paintLabels = paintLabels.selected + case ButtonClicked(`paintTicks`) => + slider.paintTicks = paintTicks.selected + case ButtonClicked(`snapTicks`) => + slider.snapToTicks = snapTicks.selected + case ButtonClicked(`live`) => + reactLive = live.selected + } } contents += new Button("Center Frame") { reactions += { @@ -78,9 +85,10 @@ object UIDemo extends SimpleGUIApplication { pages += new Page("Tables", TableSelection.ui) pages += new Page("Dialogs", Dialogs.ui) pages += new Page("Combo Boxes", ComboBoxes.ui) - pages += new Page("Split Panes", new SplitPane(Orientation.Vertical, new Button("Hello"), new Button("World")) { - continuousLayout = true - }) + pages += new Page("Split Panes", + new SplitPane(Orientation.Vertical, new Button("Hello"), new Button("World")) { + continuousLayout = true + }) val password = new FlowPanel { contents += new Label("Enter your secret password here ") @@ -96,12 +104,12 @@ object UIDemo extends SimpleGUIApplication { pages += new Page("Password", password) pages += new Page("Painting", LinePainting.ui) + //pages += new Page("Text Editor", TextEditor.ui) } val list = new ListView(tabs.pages) { - selection.selectIndices(0) + selectIndices(0) selection.intervalMode = ListView.IntervalMode.Single - import ListView._ renderer = ListView.Renderer(_.title) } val center = new SplitPane(Orientation.Vertical, new ScrollPane(list), tabs) { @@ -110,6 +118,11 @@ object UIDemo extends SimpleGUIApplication { } layout(center) = Center + /* + * This slider is used above, so we need lazy initialization semantics. + * Objects or lazy vals are the way to go, but objects give us better + * type inference at times. + */ object slider extends Slider { min = 0 value = tabs.selection.index @@ -118,6 +131,9 @@ object UIDemo extends SimpleGUIApplication { } layout(slider) = South + /* + * Establish connection between the tab pane, slider, and list view. + */ listenTo(slider) listenTo(tabs.selection) listenTo(list.selection) @@ -126,12 +142,11 @@ object UIDemo extends SimpleGUIApplication { if(!slider.adjusting || reactLive) tabs.selection.index = slider.value case SelectionChanged(`tabs`) => slider.value = tabs.selection.index - list.selection.selectIndices(tabs.selection.index) + list.selectIndices(tabs.selection.index) case SelectionChanged(`list`) => - if (list.selection.items.size == 1) + if (list.selection.items.length == 1) tabs.selection.page = list.selection.items(0) } } } -} - +}
\ No newline at end of file |