Skip to content

Commit

Permalink
Merge pull request #100 from Sciss/work
Browse files Browse the repository at this point in the history
Fix Scala 2.13.0-RC1 compilation, fix a number of simple bugs / enhancements
  • Loading branch information
Sciss authored Apr 11, 2019
2 parents 732c1cc + 6af7315 commit 07ce708
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 62 deletions.
16 changes: 8 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ scalaModuleSettings

name := "scala-swing"

version := "2.1.1-SNAPSHOT"
version := "2.1.1"

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.12.8"

OsgiKeys.exportPackage := Seq(s"scala.swing.*;version=${version.value}")

Expand All @@ -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
Expand Down
6 changes: 2 additions & 4 deletions src/main/scala-2.13+/scala/swing/BufferWrapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
22 changes: 17 additions & 5 deletions src/main/scala/scala/swing/Action.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 0 additions & 14 deletions src/main/scala/scala/swing/Component.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/scala/swing/FileChooser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
12 changes: 8 additions & 4 deletions src/main/scala/scala/swing/FlowPanel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
6 changes: 6 additions & 0 deletions src/main/scala/scala/swing/PopupMenu.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

65 changes: 40 additions & 25 deletions src/main/scala/scala/swing/SplitPane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
64 changes: 64 additions & 0 deletions src/test/scala/scala/swing/Issue97.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}

0 comments on commit 07ce708

Please sign in to comment.