summaryrefslogtreecommitdiff
path: root/src/swing/scala/swing/UIElement.scala
blob: a83496fff0632177fc2d094d2a3445cf19c2f999 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2007-2011, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

package scala.swing

import java.awt.Cursor
import event._
import scala.ref._
import java.util.WeakHashMap

object UIElement {
  private val ClientKey = "scala.swingWrapper"
  private[this] val wrapperCache = new WeakHashMap[java.awt.Component, WeakReference[UIElement]]

  private def cache(e: UIElement) = e.peer match {
    case p: javax.swing.JComponent => p.putClientProperty(ClientKey, e)
    case _ => wrapperCache.put(e.peer, new WeakReference(e))
  }

  /**
   * Looks up the internal component cache for a wrapper of the given
   * Java Swing peer. If this method finds one of the given type `C`,
   * it will return that wrapper. Otherwise it returns `null`. This
   * method never throws an exception.
   *
   * Clients should be extremely careful with type parameter `C` and
   * its interaction with type inference. Better err on the side of caution
   * and explicitly specify `C`.
   */
  private[swing] def cachedWrapper[C>:Null<:UIElement](c: java.awt.Component): C = {
    val w = c match {
      case c: javax.swing.JComponent => c.getClientProperty(ClientKey)
      case _ => wrapperCache.get(c)
    }
    try { w.asInstanceOf[C] } catch { case _: Exception => null }
  }

  /**
   * Returns a wrapper for a given Java Swing peer. If there is a
   * compatible wrapper in use, this method will return it.
   *
   * `wrap` methods in companion objects of subclasses of `UIElement` have
   * the  same behavior, except that they return more specific wrappers.
   */
  def wrap(c: java.awt.Component): UIElement = {
    val w = cachedWrapper[UIElement](c)
    if (w != null) w
    else new UIElement { def peer = c }
  }
}

/**
 * The base trait of all user interface elements. Subclasses belong to one
 * of two groups: top-level elements such as windows and dialogs, or
 * `Component`s.
 *
 * @note [Java Swing] This trait does not have an exact counterpart in
 * Java Swing. The peer is of type java.awt.Component since this is the
 * least common upper bound of possible underlying peers.
 *
 * @note [Implementation] A UIElement automatically adds itself to the
 * component cache on creation.
 *
 * @see java.awt.Component
 */
trait UIElement extends Proxy with LazyPublisher {
  /**
   * The underlying Swing peer.
   */
  def peer: java.awt.Component
  def self = peer

  UIElement.cache(this)

  def foreground: Color = peer.getForeground
  def foreground_=(c: Color) = peer setForeground c
  def background: Color = peer.getBackground
  def background_=(c: Color) = peer setBackground c

  def minimumSize = peer.getMinimumSize
  def minimumSize_=(x: Dimension) = peer setMinimumSize x
  def maximumSize = peer.getMaximumSize
  def maximumSize_=(x: Dimension) = peer setMaximumSize x
  def preferredSize = peer.getPreferredSize
  def preferredSize_=(x: Dimension) = peer setPreferredSize x

  def font: Font = peer.getFont
  def font_=(f: Font) = peer setFont f

  def locationOnScreen = peer.getLocationOnScreen
  def location = peer.getLocation
  def bounds = peer.getBounds
  def size = peer.getSize

  def locale = peer.getLocale
  def toolkit = peer.getToolkit

  def cursor: Cursor = peer.getCursor
  def cursor_=(c: Cursor) { peer.setCursor(c) }

  def visible: Boolean = peer.isVisible
  def visible_=(b: Boolean) { peer.setVisible(b) }
  def showing: Boolean = peer.isShowing
  def displayable: Boolean = peer.isDisplayable

  def repaint() { peer.repaint }
  def repaint(rect: Rectangle) { peer.repaint(rect.x, rect.y, rect.width, rect.height) }
  def ignoreRepaint: Boolean = peer.getIgnoreRepaint
  def ignoreRepaint_=(b: Boolean) { peer.setIgnoreRepaint(b) }

  protected def onFirstSubscribe() {
    peer.addComponentListener(new java.awt.event.ComponentListener {
      def componentHidden(e: java.awt.event.ComponentEvent) {
        publish(UIElementHidden(UIElement.this))
      }
      def componentShown(e: java.awt.event.ComponentEvent) {
        publish(UIElementShown(UIElement.this))
      }
      def componentMoved(e: java.awt.event.ComponentEvent) {
        publish(UIElementMoved(UIElement.this))
      }
      def componentResized(e: java.awt.event.ComponentEvent) {
        publish(UIElementResized(UIElement.this))
      }
    })
  }
  protected def onLastUnsubscribe() {}
}