comparison src/name/blackcap/clipman/Main.kt @ 0:be282c48010a

Incomplete; checking it in as a backup.
author David Barts <n5jrn@me.com>
date Tue, 14 Jan 2020 14:07:19 -0800
parents
children 70caa73e32f7
comparison
equal deleted inserted replaced
-1:000000000000 0:be282c48010a
1 /*
2 * The entry point and most of the view logic is here.
3 */
4 package name.blackcap.clipman
5
6 import java.awt.BorderLayout
7 import java.awt.Color
8 import java.awt.Container
9 import java.awt.Dimension
10 import java.awt.Font
11 import java.awt.Toolkit;
12 import java.awt.datatransfer.*
13 import java.awt.event.WindowEvent
14 import java.awt.event.WindowListener
15 import java.util.Date
16 import java.util.logging.Level
17 import java.util.logging.Logger
18 import javax.swing.*
19 import javax.swing.border.CompoundBorder
20 import javax.swing.border.EmptyBorder
21 import javax.swing.border.LineBorder
22 import javax.swing.text.JTextComponent
23 import kotlin.concurrent.thread
24 import org.jsoup.Jsoup
25 import org.jsoup.nodes.*
26
27
28 /* kills the updating thread (and does a system exit) when needed */
29 class KillIt(val thr: Thread) : WindowListener {
30 // events we don't care about
31 override fun windowActivated(e: WindowEvent) {}
32 override fun windowClosed(e: WindowEvent) {}
33 override fun windowDeactivated(e: WindowEvent) {}
34 override fun windowDeiconified(e: WindowEvent) {}
35 override fun windowIconified(e: WindowEvent) {}
36 override fun windowOpened(e: WindowEvent) {}
37
38 // and the one we do
39 override fun windowClosing(e: WindowEvent) {
40 thr.run { interrupt(); join() }
41 System.exit(0)
42 }
43 }
44
45 /* the updating thread */
46 class UpdateIt(val queue: PasteboardQueue, val interval: Int): Thread() {
47 @Volatile var enabled = true
48 private val stdBorder =
49 CompoundBorder(EmptyBorder(5, 10, 5, 10), LineBorder(Color.GRAY, 1))
50
51 override fun run() {
52 var oldContents = ""
53 var newContents = ""
54 while (true) {
55 if (enabled) {
56 var contents = PasteboardItem.read()
57 if (contents == null) {
58 LOGGER.log(Level.WARNING, "unable to read clipboard")
59 continue
60 }
61 newContents = when (contents) {
62 is PasteboardItem.Plain -> contents.plain
63 is PasteboardItem.HTML -> contents.plain
64 }
65 if (oldContents != newContents) {
66 var widget: JComponent = when(contents) {
67 is PasteboardItem.Plain -> JTextPane().apply {
68 contentType = "text/plain"
69 toolTipText = "Plain text"
70 text = contents.plain
71 font = Font(Font.MONOSPACED, Font.PLAIN, 14)
72 border = stdBorder
73 autoSize(600)
74 setEditable(false)
75 }
76 is PasteboardItem.HTML -> JTextPane().apply {
77 contentType = "text/html"
78 toolTipText = "Styled text"
79 text = scrub(contents.html)
80 border = stdBorder
81 autoSize(600)
82 setEditable(false)
83 }
84 }
85 queue.add(QueueItem(widget, contents))
86 oldContents = newContents
87 }
88 }
89 if (Thread.interrupted()) {
90 return
91 }
92 try {
93 Thread.sleep(interval - System.currentTimeMillis() % interval)
94 } catch (e: InterruptedException) {
95 return
96 }
97 }
98 }
99
100 private fun scrub(html: String): String {
101 return Jsoup.parse(html).run {
102 select(":root>head>meta").remove()
103 outputSettings()
104 .charset(CHARSET_NAME)
105 .syntax(Document.OutputSettings.Syntax.xml)
106 outerHtml()
107 }
108 }
109 }
110
111 fun main(args: Array<String>) {
112 LOGGER.log(Level.INFO, "beginning execution")
113 val con = Container().apply {
114 layout = BoxLayout(this, BoxLayout.Y_AXIS)
115 }
116 var frame: JFrame? = null
117 inSwingThread {
118 frame = JFrame("ClipMan").apply {
119 preferredSize = Dimension(640, 480)
120 contentPane.add(
121 JScrollPane(con).apply {
122 verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
123 horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
124 preferredSize = Dimension(640, 480)
125 }, BorderLayout.CENTER)
126 pack()
127 setVisible(true)
128 }
129 }
130 val queue = PasteboardQueue(con, 10)
131 val updater = UpdateIt(queue, 1000).apply { start() }
132 inSwingThread { frame?.addWindowListener(KillIt(updater)) }
133 LOGGER.log(Level.INFO, "execution complete")
134 }
135
136 fun inSwingThread(block: () -> Unit) {
137 SwingUtilities.invokeLater(Runnable(block))
138 }
139
140 fun JTextComponent.autoSize(width: Int): Unit {
141 val SLOP = 10
142 val dim = Dimension(width, width)
143 preferredSize = dim
144 size = dim
145 val r = modelToView(document.length)
146 preferredSize = Dimension(width, r.y + r.height + SLOP)
147 }