From 37c849ab35d2155a703e4dd2cc01579d37b1db93 Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 11:11:54 +0200 Subject: [PATCH 1/8] fix compilation for Scala 2.13.0-RC1 - BufferWrapper, argument type for patchInPlace updated --- build.sbt | 14 +++++++------- .../scala-2.13+/scala/swing/BufferWrapper.scala | 6 ++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index 63731a64..a6321bc1 100644 --- a/build.sbt +++ b/build.sbt @@ -10,14 +10,14 @@ scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature") // Map[JvmMajorVersion, List[(ScalaVersion, UseForPublishing)]] scalaVersionsByJvm in ThisBuild := Map( - 8 -> List("2.11.12", "2.12.8", "2.13.0-M5").map(_ -> true), - 9 -> List("2.11.12", "2.12.8", "2.13.0-M5").map(_ -> false), - 10 -> List("2.11.12", "2.12.8", "2.13.0-M5").map(_ -> false), - 11 -> List("2.11.12", "2.12.8", "2.13.0-M5").map(_ -> false), - 12 -> List("2.11.12", "2.12.8", "2.13.0-M5").map(_ -> false) + 8 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> true), + 9 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> false), + 10 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> false), + 11 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> false), + 12 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> false) ) -scalaVersion in ThisBuild := "2.13.0-M5" // for testing +scalaVersion in ThisBuild := "2.13.0-RC1" // for testing OsgiKeys.exportPackage := Seq(s"scala.swing.*;version=${version.value}") @@ -29,7 +29,7 @@ shellPrompt in ThisBuild := { state => Project.extract(state).currentRef.project lazy val swing = project.in(file(".")) .settings( libraryDependencies += { - "org.scalatest" %% "scalatest" % "3.0.7" % Test + "org.scalatest" %% "scalatest" % "3.0.8-RC2" % Test }, // Adds a `src/main/scala-2.13+` source directory for Scala 2.13 and newer // and a `src/main/scala-2.13-` source directory for Scala version older than 2.13 diff --git a/src/main/scala-2.13+/scala/swing/BufferWrapper.scala b/src/main/scala-2.13+/scala/swing/BufferWrapper.scala index bd59a2c5..a65351cc 100644 --- a/src/main/scala-2.13+/scala/swing/BufferWrapper.scala +++ b/src/main/scala-2.13+/scala/swing/BufferWrapper.scala @@ -48,13 +48,11 @@ abstract class BufferWrapper[A] extends mutable.Buffer[A] { } } - override def patchInPlace(from: Int, patch: scala.collection.Seq[A], replaced: Int): this.type = { + override def patchInPlace(from: Int, patch: MoreElem[A], replaced: Int): this.type = { if (replaced > 0) { remove(from, replaced) } - if (patch.nonEmpty) { - insertAll(from, patch) - } + insertAll(from, patch) this } } From 29d76854eeebe05173d6cf935d2372e38c2f00c5 Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 11:17:06 +0200 Subject: [PATCH 2/8] fixes #31 - we add `var text` to `Action`; `title` becomes an alias. --- build.sbt | 2 +- src/main/scala/scala/swing/Action.scala | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index a6321bc1..ead1ebdb 100644 --- a/build.sbt +++ b/build.sbt @@ -17,7 +17,7 @@ scalaVersionsByJvm in ThisBuild := Map( 12 -> List("2.11.12", "2.12.8", "2.13.0-RC1").map(_ -> false) ) -scalaVersion in ThisBuild := "2.13.0-RC1" // for testing +scalaVersion in ThisBuild := "2.12.8" OsgiKeys.exportPackage := Seq(s"scala.swing.*;version=${version.value}") diff --git a/src/main/scala/scala/swing/Action.scala b/src/main/scala/scala/swing/Action.scala index d1571210..3b32a1b2 100644 --- a/src/main/scala/scala/swing/Action.scala +++ b/src/main/scala/scala/swing/Action.scala @@ -81,11 +81,23 @@ abstract class Action(title0: String) { def actionPerformed(a: java.awt.event.ActionEvent): Unit = apply() } - /** - * Title is not optional. - */ - def title: String = ifNull(peer.getValue(javax.swing.Action.NAME),"") - def title_=(t: String): Unit = peer.putValue(javax.swing.Action.NAME, t) + /** Gets the `NAME` property. + */ + def text: String = ifNull(peer.getValue(javax.swing.Action.NAME),"") + + /** Sets the `NAME` property. + */ + def text_=(t: String): Unit = peer.putValue(javax.swing.Action.NAME, t) + + /** An alias for `text`. This is kept for backwards compatibility. + * + * @see [[text]] + */ + def title: String = text + + /** An alias for `text_=`. This is kept for backwards compatibility. + */ + def title_=(t: String): Unit = text = t /** * None if large icon and small icon are not equal. From 4cf7f427538dfbfe3ed4bdb888b5406af3a421f3 Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 11:21:25 +0200 Subject: [PATCH 3/8] fixes #88 --- src/main/scala/scala/swing/PopupMenu.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/scala/scala/swing/PopupMenu.scala b/src/main/scala/scala/swing/PopupMenu.scala index 0317b6a7..7e9884c4 100644 --- a/src/main/scala/scala/swing/PopupMenu.scala +++ b/src/main/scala/scala/swing/PopupMenu.scala @@ -59,7 +59,13 @@ class PopupMenu extends Component with SequentialContainer.Wrapper with Publishe def show(invoker: Component, x: Int, y: Int): Unit = peer.show(invoker.peer, x, y) def margin: Insets = peer.getMargin + def label: String = peer.getLabel def label_=(s: String): Unit = peer.setLabel(s) + + /** Lays out the popup menu so that it uses the minimum space + * needed to display its contents. + */ + def pack(): Unit = peer.pack() } From a1b9f4f3b1ac6a077ef9960df1f2efbb469b2a5f Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 13:36:06 +0200 Subject: [PATCH 4/8] fixes #97 --- src/main/scala/scala/swing/Component.scala | 14 ----- src/test/scala/scala/swing/Issue97.scala | 64 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 src/test/scala/scala/swing/Issue97.scala diff --git a/src/main/scala/scala/swing/Component.scala b/src/main/scala/scala/swing/Component.scala index cf0c734d..4eb23f95 100644 --- a/src/main/scala/scala/swing/Component.scala +++ b/src/main/scala/scala/swing/Component.scala @@ -203,20 +203,6 @@ abstract class Component extends UIElement { protected override def onFirstSubscribe(): Unit = { super.onFirstSubscribe() - // TODO: deprecated, remove after 2.8 - peer.addComponentListener(new java.awt.event.ComponentListener { - def componentHidden(e: java.awt.event.ComponentEvent): Unit = - publish(event.UIElementHidden(Component.this)) - - def componentShown(e: java.awt.event.ComponentEvent): Unit = - publish(event.UIElementShown(Component.this)) - - def componentMoved(e: java.awt.event.ComponentEvent): Unit = - publish(event.UIElementMoved(Component.this)) - - def componentResized(e: java.awt.event.ComponentEvent): Unit = - publish(event.UIElementResized(Component.this)) - }) peer.addFocusListener(new java.awt.event.FocusListener { def other(e: java.awt.event.FocusEvent): Option[Component] = e.getOppositeComponent match { diff --git a/src/test/scala/scala/swing/Issue97.scala b/src/test/scala/scala/swing/Issue97.scala new file mode 100644 index 00000000..f2ba52cf --- /dev/null +++ b/src/test/scala/scala/swing/Issue97.scala @@ -0,0 +1,64 @@ +package scala.swing + +import java.util.concurrent.TimeUnit + +import org.scalatest.{FlatSpec, Matchers} + +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, Future, Promise} +import scala.swing.event.{UIElementHidden, UIElementMoved, UIElementResized, UIElementShown} +import scala.util.control.NonFatal + +// Note: `AsyncFlatSpec` has issues with swallowing errors and returning early. +class Issue97 extends FlatSpec with Matchers { + case class Count(shown: Int = 0, hidden: Int = 0, moved: Int = 0, resized: Int = 0) + + def countEvents(): Future[Count] = { + val p = Promise[Count]() + + def safely(thunk: => Unit): Unit = + try { + thunk + } catch { + case NonFatal(ex) => + p.tryFailure(ex) + } + + Swing.onEDT { + safely { + var c = Count() + val lb = new Label("Foo") + lb.listenTo(lb) + lb.reactions += { + case UIElementShown (`lb`) => c = c.copy(shown = c.shown + 1) + case UIElementHidden (`lb`) => c = c.copy(hidden = c.hidden + 1) + case UIElementMoved (`lb`) => c = c.copy(moved = c.moved + 1) + case UIElementResized (`lb`) => c = c.copy(resized = c.resized + 1) + } + val b = new BoxPanel(Orientation.Horizontal) + b.contents += lb + lb.visible = false + lb.visible = true + b.contents.insert(0, new Label("Bar")) // about to move `lb` to the right + b.peer.doLayout() + // note: `Frame#pack()` creates a native window peer, + // and thus is not possible to run on Travis without X11 + + // wait till next EDT cycle + Swing.onEDT { + p.trySuccess(c) + } + } + } + p.future + } + + "Components" should "fire exactly one event when moved, removed or made visible or invisible" in { + val futCount = countEvents() + val c = Await.result(futCount, Duration(20, TimeUnit.SECONDS)) + assert(c.shown === 1) + assert(c.hidden === 1) + assert(c.moved === 1) + assert(c.resized === 1) + } +} From c1f96aa7c7a3bacc80a5d93b19d42670b2fd8fa7 Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 19:55:06 +0200 Subject: [PATCH 5/8] addresses #98 --- src/main/scala/scala/swing/SplitPane.scala | 65 +++++++++++++--------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/main/scala/scala/swing/SplitPane.scala b/src/main/scala/scala/swing/SplitPane.scala index 5560993a..d829775f 100644 --- a/src/main/scala/scala/swing/SplitPane.scala +++ b/src/main/scala/scala/swing/SplitPane.scala @@ -17,54 +17,69 @@ import javax.swing.JSplitPane import scala.collection.immutable import scala.swing.Swing.nullPeer -/** - * A container with exactly two children. Arranges them side by side, either - * horizontally or vertically. Displays a draggable divider component between - * them that lets the user adjust the size ratio of the children. - * - * @see javax.swing.JSplitPane - */ -class SplitPane(o: Orientation.Value, left: Component, right: Component) extends Component with Container with Orientable.Wrapper { - override lazy val peer: JSplitPane = - new javax.swing.JSplitPane(o.id, left.peer, right.peer) with SuperMixin +/** A container with exactly two children. Arranges them side by side, either + * horizontally or vertically. Displays a draggable divider component between + * them that lets the user adjust the size ratio of the children. + * + * @param o the orientation of the divider. Note that we are using + * `Orientation.Horizontal` and `Orientation.Vertical`, which are + * different from the underlying `JSplitPane` values. + * `Orientation.Horizontal` corresponds with `VERTICAL_SPLIT`, thus + * producing a left and right component and a "vertical divider", + * and `Orientation.Vertical` corresponds with `HORIZONTAL_SPLIT`, thus + * producing a top and bottom component and a "horizontal divider". + * + * @see javax.swing.JSplitPane + */ +class SplitPane(o: Orientation.Value, left: Component, right: Component) + extends Component with Container with Orientable.Wrapper { + def this(o: Orientation.Value) = this(o, new Component {}, new Component {}) def this() = this(Orientation.Horizontal) + override lazy val peer: JSplitPane = + new javax.swing.JSplitPane(o.id, left.peer, right.peer) with SuperMixin + def contents: immutable.Seq[Component] = List(leftComponent, rightComponent) + def contents_=(left: Component, right: Component): Unit = { - peer.setLeftComponent(nullPeer(left)) + peer.setLeftComponent (nullPeer(left)) peer.setRightComponent(nullPeer(right)) } def topComponent: Component = UIElement.cachedWrapper[Component](peer.getTopComponent.asInstanceOf[javax.swing.JComponent]) def topComponent_=(c: Component): Unit = peer.setTopComponent(nullPeer(c)) + def bottomComponent: Component = UIElement.cachedWrapper[Component](peer.getBottomComponent.asInstanceOf[javax.swing.JComponent]) def bottomComponent_=(c: Component): Unit = peer.setBottomComponent(nullPeer(c)) - def leftComponent: Component = topComponent - def leftComponent_=(c: Component): Unit = { topComponent = c } - def rightComponent: Component = bottomComponent - def rightComponent_=(c: Component): Unit = { bottomComponent = c } + def leftComponent : Component = topComponent + def leftComponent_= (c: Component): Unit = { topComponent = c } - def dividerLocation: Int = peer.getDividerLocation - def dividerLocation_=(n: Int): Unit = peer.setDividerLocation(n) + def rightComponent : Component = bottomComponent + def rightComponent_=(c: Component): Unit = { bottomComponent = c } + + def dividerLocation : Int = peer.getDividerLocation + def dividerLocation_= (n: Int): Unit = peer.setDividerLocation(n) /*def proportionalDividerLocation: Double = if (orientation == Orientation.Vertical) dividerLocation / (size.height - dividerSize) else dividerLocation / (size.width - dividerSize)*/ def dividerLocation_=(f: Double): Unit = peer.setDividerLocation(f) - def dividerSize: Int = peer.getDividerSize - def dividerSize_=(n: Int): Unit = peer.setDividerSize(n) - def resizeWeight: Double = peer.getResizeWeight - def resizeWeight_=(n: Double): Unit = peer.setResizeWeight(n) + def dividerSize : Int = peer.getDividerSize + def dividerSize_= (n: Int): Unit = peer.setDividerSize(n) + + def resizeWeight : Double = peer.getResizeWeight + def resizeWeight_= (n: Double): Unit = peer.setResizeWeight(n) def resetToPreferredSizes(): Unit = peer.resetToPreferredSizes() - def oneTouchExpandable: Boolean = peer.isOneTouchExpandable - def oneTouchExpandable_=(b: Boolean): Unit = peer.setOneTouchExpandable(b) - def continuousLayout: Boolean = peer.isContinuousLayout - def continuousLayout_=(b: Boolean): Unit = peer.setContinuousLayout(b) + def oneTouchExpandable : Boolean = peer.isOneTouchExpandable + def oneTouchExpandable_=(b: Boolean): Unit = peer.setOneTouchExpandable(b) + + def continuousLayout : Boolean = peer.isContinuousLayout + def continuousLayout_= (b: Boolean): Unit = peer.setContinuousLayout(b) } From ecdb5d290e51e26acd3b3da0867e53a836c4fff1 Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 20:08:59 +0200 Subject: [PATCH 6/8] fixes #99 - FileChooser extends Component now --- src/main/scala/scala/swing/FileChooser.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scala/swing/FileChooser.scala b/src/main/scala/scala/swing/FileChooser.scala index bb255b0d..d696f443 100644 --- a/src/main/scala/scala/swing/FileChooser.scala +++ b/src/main/scala/scala/swing/FileChooser.scala @@ -46,9 +46,9 @@ object FileChooser { * * @see [[http://docs.oracle.com/javase/7/docs/api/javax/swing/JFileChooser.html javax.swing.JFileChooser]] */ -class FileChooser(dir: File) { +class FileChooser(dir: File) extends Component { import scala.swing.FileChooser._ - lazy val peer: JFileChooser = new JFileChooser(dir) + override lazy val peer: JFileChooser = new JFileChooser(dir) def this() = this(null) From cec0b174dd86327b96b805116e39c7bffd5e076b Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 20:20:41 +0200 Subject: [PATCH 7/8] fixes #96 - add `var alignOnBaseline` to `FlowPanel` --- src/main/scala/scala/swing/FlowPanel.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/scala/swing/FlowPanel.scala b/src/main/scala/scala/swing/FlowPanel.scala index 7ab40263..fcb0d70a 100644 --- a/src/main/scala/scala/swing/FlowPanel.scala +++ b/src/main/scala/scala/swing/FlowPanel.scala @@ -43,8 +43,12 @@ class FlowPanel(alignment: FlowPanel.Alignment.Value)(contents0: Component*) ext private def layoutManager: FlowLayout = peer.getLayout.asInstanceOf[FlowLayout] - def vGap: Int = layoutManager.getVgap - def vGap_=(n: Int): Unit = layoutManager.setVgap(n) - def hGap: Int = layoutManager.getHgap - def hGap_=(n: Int): Unit = layoutManager.setHgap(n) + def vGap : Int = layoutManager.getVgap + def vGap_=(n: Int): Unit = layoutManager.setVgap(n) + + def hGap : Int = layoutManager.getHgap + def hGap_=(n: Int): Unit = layoutManager.setHgap(n) + + def alignOnBaseline : Boolean = layoutManager.getAlignOnBaseline + def alignOnBaseline_=(value : Boolean): Unit = layoutManager.setAlignOnBaseline(value) } From 6af731574b088d68e5de0664d1c84aff387d814d Mon Sep 17 00:00:00 2001 From: Hanns Holger Rutz Date: Wed, 10 Apr 2019 20:23:48 +0200 Subject: [PATCH 8/8] v2.1.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index ead1ebdb..083ce0be 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ scalaModuleSettings name := "scala-swing" -version := "2.1.1-SNAPSHOT" +version := "2.1.1" scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature")