comparison src/name/blackcap/clipman/Main.kt @ 9:8fcff14defa2

Stomp out race conditions and set width adaptively.
author David Barts <n5jrn@me.com>
date Sun, 19 Jan 2020 15:43:01 -0800
parents 7715ff59f053
children e7e067f5b649
comparison
equal deleted inserted replaced
8:7715ff59f053 9:8fcff14defa2
13 import java.awt.event.WindowEvent 13 import java.awt.event.WindowEvent
14 import java.awt.event.WindowListener 14 import java.awt.event.WindowListener
15 import java.util.Date 15 import java.util.Date
16 import java.util.logging.Level 16 import java.util.logging.Level
17 import java.util.logging.Logger 17 import java.util.logging.Logger
18 import java.util.concurrent.Semaphore
18 import javax.swing.* 19 import javax.swing.*
19 import javax.swing.border.* 20 import javax.swing.border.*
20 import javax.swing.text.JTextComponent 21 import javax.swing.text.JTextComponent
21 import kotlin.concurrent.thread 22 import kotlin.concurrent.thread
22 import org.jsoup.Jsoup 23 import org.jsoup.Jsoup
26 val MYNAME = "ClipMan" 27 val MYNAME = "ClipMan"
27 28
28 /* default sizes */ 29 /* default sizes */
29 val CPWIDTH = 640 30 val CPWIDTH = 640
30 val CPHEIGHT = 480 31 val CPHEIGHT = 480
31 val TPWIDTH = CPWIDTH - 60 32
33 /* border widths */
34 val PANEL_BORDER = 9
35 val OUTER_BORDER = 9 /* must be 6 or more */
36 val INNER_BORDER = 1
37 val MARGIN_BORDER = 3
32 38
33 /* kills the updating thread (and does a system exit) when needed */ 39 /* kills the updating thread (and does a system exit) when needed */
34 class KillIt(val thr: Thread) : WindowListener { 40 class KillIt(val thr: Thread) : WindowListener {
35 // events we don't care about 41 // events we don't care about
36 override fun windowActivated(e: WindowEvent) {} 42 override fun windowActivated(e: WindowEvent) {}
49 } 55 }
50 56
51 /* the updating thread */ 57 /* the updating thread */
52 class UpdateIt(val queue: PasteboardQueue, val interval: Int): Thread() { 58 class UpdateIt(val queue: PasteboardQueue, val interval: Int): Thread() {
53 @Volatile var enabled = true 59 @Volatile var enabled = true
54 private val outerBorder = MatteBorder(3, 9, 9, 9, queue.parent.background) 60 private val outerBorder =
61 MatteBorder(OUTER_BORDER-6, OUTER_BORDER, OUTER_BORDER, OUTER_BORDER,
62 queue.parent.background)
55 private val stdBorder = 63 private val stdBorder =
56 CompoundBorder(LineBorder(Color.GRAY, 1), EmptyBorder(3, 3, 3, 3)) 64 CompoundBorder(LineBorder(Color.GRAY, INNER_BORDER),
65 EmptyBorder(MARGIN_BORDER, MARGIN_BORDER, MARGIN_BORDER, MARGIN_BORDER))
57 66
58 override fun run() { 67 override fun run() {
59 var oldContents = "" 68 var oldContents = ""
60 var newContents = "" 69 var newContents = ""
61 while (true) { 70 while (true) {
65 newContents = when (contents) { 74 newContents = when (contents) {
66 is PasteboardItem.Plain -> contents.plain 75 is PasteboardItem.Plain -> contents.plain
67 is PasteboardItem.HTML -> contents.plain 76 is PasteboardItem.HTML -> contents.plain
68 } 77 }
69 if (oldContents != newContents) { 78 if (oldContents != newContents) {
79 var stdWidth: Int? = null
80 inSynSwingThread {
81 stdWidth = queue.parent.size.width - 2 * (PANEL_BORDER+OUTER_BORDER+INNER_BORDER+MARGIN_BORDER)
82 }
70 var widget = JPanel().apply { 83 var widget = JPanel().apply {
71 layout = BoxLayout(this, BoxLayout.Y_AXIS) 84 layout = BoxLayout(this, BoxLayout.Y_AXIS)
72 background = queue.parent.background 85 background = queue.parent.background
73 border = outerBorder 86 border = outerBorder
74 } 87 }
78 add(JTextPane().apply { 91 add(JTextPane().apply {
79 contentType = "text/plain" 92 contentType = "text/plain"
80 text = contents.plain 93 text = contents.plain
81 font = Font(Font.MONOSPACED, Font.PLAIN, 14) 94 font = Font(Font.MONOSPACED, Font.PLAIN, 14)
82 border = stdBorder 95 border = stdBorder
83 autoSize(TPWIDTH) 96 autoSize(stdWidth!!)
84 setEditable(false) 97 setEditable(false)
85 alignmentX = JTextPane.LEFT_ALIGNMENT 98 alignmentX = JTextPane.LEFT_ALIGNMENT
86 }) 99 })
87 } 100 }
88 is PasteboardItem.HTML -> widget.run { 101 is PasteboardItem.HTML -> widget.run {
90 add(JTextPane().apply { 103 add(JTextPane().apply {
91 contentType = "text/html" 104 contentType = "text/html"
92 toolTipText = "Styled text" 105 toolTipText = "Styled text"
93 text = scrub(contents.html) 106 text = scrub(contents.html)
94 border = stdBorder 107 border = stdBorder
95 autoSize(TPWIDTH) 108 autoSize(stdWidth!!)
96 setEditable(false) 109 setEditable(false)
97 alignmentX = JTextPane.LEFT_ALIGNMENT 110 alignmentX = JTextPane.LEFT_ALIGNMENT
98 }) 111 })
99 } 112 }
100 } 113 }
134 LOGGER.log(Level.INFO, "beginning execution") 147 LOGGER.log(Level.INFO, "beginning execution")
135 setLookFeel() 148 setLookFeel()
136 val frame = JFrame(MYNAME) 149 val frame = JFrame(MYNAME)
137 val con = JPanel().apply { 150 val con = JPanel().apply {
138 layout = BoxLayout(this, BoxLayout.Y_AXIS) 151 layout = BoxLayout(this, BoxLayout.Y_AXIS)
139 border = EmptyBorder(9, 9, 9, 9) 152 border = EmptyBorder(PANEL_BORDER, PANEL_BORDER, PANEL_BORDER, PANEL_BORDER)
140 background = frame.background 153 background = frame.background
141 } 154 }
142 inSwingThread { 155 inSynSwingThread {
143 frame.apply { 156 frame.apply {
144 contentPane.add( 157 contentPane.add(
145 JScrollPane(con).apply { 158 JScrollPane(con).apply {
146 verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS 159 verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
147 horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER 160 horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
165 178
166 fun inSwingThread(block: () -> Unit) { 179 fun inSwingThread(block: () -> Unit) {
167 SwingUtilities.invokeLater(Runnable(block)) 180 SwingUtilities.invokeLater(Runnable(block))
168 } 181 }
169 182
183 fun inSynSwingThread(block: () -> Unit) {
184 val ready = Semaphore(0)
185 inSwingThread {
186 block()
187 ready.release()
188 }
189 ready.acquire()
190 }
191
170 fun JTextComponent.autoSize(width: Int): Unit { 192 fun JTextComponent.autoSize(width: Int): Unit {
171 val SLOP = 10 193 val SLOP = 10
172 val dim = Dimension(width, width) 194 val dim = Dimension(width, width)
173 preferredSize = dim 195 preferredSize = dim
174 size = dim 196 size = dim