Mercurial > cgi-bin > hgweb.cgi > ClipMan
view src/name/blackcap/clipman/Pasteboard.kt @ 15:732f92dc3bc6
Don't need head.
author | David Barts <n5jrn@me.com> |
---|---|
date | Mon, 20 Jan 2020 23:02:51 -0800 |
parents | be282c48010a |
children | 9dd58db4d15a |
line wrap: on
line source
/* * We call the clipboard a "pasteboard" for our internal class name, not * because I prefer that term (I don't) but so as to not clash with the * AWT's Clipboard class. */ package name.blackcap.clipman import java.awt.Toolkit import java.awt.datatransfer.Clipboard import java.awt.datatransfer.ClipboardOwner import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.Transferable import java.awt.datatransfer.UnsupportedFlavorException import java.io.IOException import java.io.InputStream import java.nio.charset.Charset import java.util.logging.Level import java.util.logging.Logger import kotlin.collections.HashMap /* Constants, etc. */ val CHARSET_NAME = "UTF-8" /* * Represents an error dealing with pasteboard items. */ class PasteboardError(): Exception() /** * Represents an item of data in the clipboard and how to read and * write it. */ sealed class PasteboardItem { data class Plain(val plain: String): PasteboardItem() data class HTML(val plain: String, val html: String): PasteboardItem() private class PasteboardData(val item: PasteboardItem): Transferable, ClipboardOwner { private val CHARSET = Charset.forName(CHARSET_NAME) private val HTML_FLAVOR = DataFlavor("text/html; document=all; class=\"[B\"; charset=" + CHARSET_NAME) private val _data: HashMap<DataFlavor, Any> private val flavors: Array<DataFlavor> init { _data = HashMap<DataFlavor, Any>().apply { when (item) { is Plain -> put(DataFlavor.stringFlavor, item.plain as Any) is HTML -> { put(DataFlavor.stringFlavor, item.plain as Any) put(HTML_FLAVOR, item.html as Any) } } } _data.keys.asIterable().run { flavors = Array<DataFlavor>(count()) { elementAt(it) } } } override fun getTransferData(flavor: DataFlavor): Any { return _data.get(flavor) ?: throw UnsupportedFlavorException(flavor) } override fun getTransferDataFlavors(): Array<DataFlavor> = flavors override fun isDataFlavorSupported(flavor: DataFlavor) = _data.containsKey(flavor) override fun lostOwnership(clipboard: Clipboard, contents: Transferable) {} } companion object { private val CLIPBOARD = Toolkit.getDefaultToolkit().systemClipboard /** * Read the item in the pasteboard. * @return a PasteboardItem? object, null if nothing could be read */ fun read() : PasteboardItem? { check() var plain = getClipboardData(DataFlavor.stringFlavor) if (plain == null) { return null } var html = getClipboardData(DataFlavor.allHtmlFlavor) if (html == null) { html = htmlFromRTF() } return if (html == null) { Plain(plain) } else { HTML(plain, html) } } /** * Write an item to the pasteboard. * @param item a PasteboardItem to write */ fun write(item: PasteboardItem) { check() val pbdata = PasteboardData(item) CLIPBOARD.setContents(pbdata, pbdata) } private fun check() { if (CLIPBOARD == null) { throw RuntimeException("no clipboard available!") } } private fun getClipboardData(flavor: DataFlavor): String? { try { return CLIPBOARD.getData(flavor) as String? } catch (e: IOException) { return null } catch (e: UnsupportedFlavorException) { return null } } private fun htmlFromRTF(): String? { /* see if there's an appropriate flavor */ var rtf: DataFlavor? = null for (flavor in CLIPBOARD.availableDataFlavors) { if (flavor.isRepresentationClassInputStream() && "text".equals(flavor.primaryType ?: "", ignoreCase=true) && "rtf".equals(flavor.subType ?: "", ignoreCase=true)) { rtf = flavor break } } if (rtf == null) { return null } (CLIPBOARD.getData(rtf) as InputStream).use { val (html, errors) = rtfToHtml(it) if (errors != null) { LOGGER.log(Level.WARNING, errors) return null } return html } } } }