Mercurial > cgi-bin > hgweb.cgi > ClipMan
diff src/name/blackcap/clipman/Main.kt @ 27:8aa2dfac27eb
Big reorg; compiled but untested.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 29 Jan 2020 10:50:07 -0800 |
parents | dac8dfb4b549 |
children | f1fcc1281dad |
line wrap: on
line diff
--- a/src/name/blackcap/clipman/Main.kt Wed Jan 29 10:47:46 2020 -0800 +++ b/src/name/blackcap/clipman/Main.kt Wed Jan 29 10:50:07 2020 -0800 @@ -4,25 +4,19 @@ package name.blackcap.clipman import java.awt.BorderLayout -import java.awt.Color import java.awt.Container import java.awt.Dimension import java.awt.Font -import java.awt.Toolkit; import java.awt.datatransfer.* -import java.awt.event.ActionEvent -import java.awt.event.ActionListener -import java.awt.event.KeyEvent +import java.awt.event.MouseEvent +import java.awt.event.MouseListener import java.awt.event.WindowEvent import java.awt.event.WindowListener import java.util.Date -import java.util.concurrent.Semaphore import java.util.logging.Level import java.util.logging.Logger import javax.swing.* import javax.swing.border.* -import javax.swing.text.JTextComponent -import javax.swing.text.html.HTMLEditorKit import javax.swing.text.html.StyleSheet import kotlin.concurrent.thread import org.jsoup.Jsoup @@ -35,19 +29,19 @@ val CPWIDTH = 640 val CPHEIGHT = 480 -/* border widths */ +/* width of main panel border */ val PANEL_BORDER = 9 -val OUTER_BORDER_TOP = 3 -val OUTER_BORDER = 9 -val INNER_BORDER = 1 -val MARGIN_BORDER = 3 /* default font sizes in the text-display panes */ val MONO_SIZE = 14 val PROP_SIZE = 16 +/* the queue of data we deal with and the main application frame */ +val queue = LateInit<PasteboardQueue>() +val frame = LateInit<JFrame>() + /* kills the updating thread (and does a system exit) when needed */ -class KillIt(val thr: Thread) : WindowListener { +class KillIt() : WindowListener { // events we don't care about override fun windowActivated(e: WindowEvent) {} override fun windowClosed(e: WindowEvent) {} @@ -58,41 +52,14 @@ // and the one we do override fun windowClosing(e: WindowEvent) { - thr.run { interrupt(); join() } LOGGER.log(Level.INFO, "execution complete") System.exit(0) } } -class ClipText: JTextPane() { - override fun getMaximumSize(): Dimension { - return Dimension(Int.MAX_VALUE, preferredSize.height) - } -} - -/* HTMLEditorKit shares all stylesheets. How unbelievably braindamaged. */ -class MyEditorKit: HTMLEditorKit() { - private var _styleSheet = defaultStyleSheet - override fun getStyleSheet() = _styleSheet - override fun setStyleSheet(value: StyleSheet) { - _styleSheet = value - } - - val defaultStyleSheet: StyleSheet - get() { - return super.getStyleSheet() - } -} - /* the updating thread */ -class UpdateIt(val queue: PasteboardQueue, val interval: Int): Thread() { +class UpdateIt(val interval: Int): Thread(), MouseListener { @Volatile var enabled = true - private val outerBorder = - MatteBorder(OUTER_BORDER_TOP, OUTER_BORDER, OUTER_BORDER, OUTER_BORDER, - queue.parent.background) - private val stdBorder = - CompoundBorder(LineBorder(Color.GRAY, INNER_BORDER), - EmptyBorder(MARGIN_BORDER, MARGIN_BORDER, MARGIN_BORDER, MARGIN_BORDER)) override fun run() { var oldContents: PasteboardItem? = null @@ -100,52 +67,30 @@ if (enabled) { var contents = PasteboardItem.read() if ((contents != null) && (contents != oldContents)) { - val stdWidth = queue.parent.size.width - 2 * (PANEL_BORDER+OUTER_BORDER+INNER_BORDER+MARGIN_BORDER) - val widget = JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - background = queue.parent.background - border = outerBorder - } val (plain, html) = when(contents) { is PasteboardItem.Plain -> Pair(contents.plain, null) is PasteboardItem.HTML -> Pair(null, contents.html) is PasteboardItem.RTF -> Pair(contents.plain, contents.html) } - var searchable: JTextComponent? = null - if (html == null) { - widget.run { - add(stdLabel("Plain text")) - searchable = ClipText().apply { - contentType = "text/plain" - text = plain - font = Font(Font.MONOSPACED, Font.PLAIN, MONO_SIZE) - border = stdBorder - autoSize(stdWidth) - setEditable(false) - alignmentX = JTextPane.LEFT_ALIGNMENT - } - add(searchable) - } + val piv = if (html == null) { + PasteboardItemView("Plain text", ClipText().apply { + contentType = "text/plain" + text = plain + font = Font(Font.MONOSPACED, Font.PLAIN, MONO_SIZE) + }) } else { - widget.run { - add(stdLabel("Styled text")) - val (dhtml, style) = preproc(html) - val hek = MyEditorKit().apply { - style.addStyleSheet(defaultStyleSheet) - styleSheet = style - } - searchable = ClipText().apply { - editorKit = hek - text = dhtml - border = stdBorder - autoSize(stdWidth) - setEditable(false) - alignmentX = JTextPane.LEFT_ALIGNMENT - } - add(searchable) + val (dhtml, style) = preproc(html) + val hek = MyEditorKit().apply { + style.addStyleSheet(defaultStyleSheet) + styleSheet = style } + PasteboardItemView("Styled text", ClipText().apply { + editorKit = hek + text = dhtml + }) } - queue.add(QueueItem(widget, searchable!!, contents)) + piv.searchable.addMouseListener(this) + queue.v.add(QueueItem(contents, piv)) oldContents = contents } } @@ -160,15 +105,10 @@ } } - private fun stdLabel(text: String) = JLabel(text).apply { - horizontalAlignment = JLabel.LEFT - alignmentX = JLabel.LEFT_ALIGNMENT - } - private fun preproc(html: String): Pair<String, StyleSheet> { val sty = StyleSheet().apply { - addRule("body { font-family: serif; font-size: %d; }".format(PROP_SIZE)) - addRule("code, kbd, pre, samp, tt { font-family: monospace; font-size: %d; }".format(MONO_SIZE)) + addRule("body { font-family: serif; font-size: ${PROP_SIZE}; }") + addRule("code, kbd, pre, samp, tt { font-family: monospace; font-size: ${MONO_SIZE}; }") } val scrubbed = Jsoup.parse(html).run { select("style").forEach { @@ -182,113 +122,67 @@ } return Pair(scrubbed, sty) } + + /* MouseListener methods */ + + override fun mouseClicked(e: MouseEvent) { + val source = e.getSource() as? ClipText + if (source == null) { + return + } + queue.v.deselectAll() + source.selected = true + source.validate() + SelectionRequired.enable() + } + + override fun mousePressed(e: MouseEvent) { + maybeShowPopup(e) + } + + override fun mouseReleased(e: MouseEvent) { + maybeShowPopup(e) + } + + private fun maybeShowPopup(e: MouseEvent) { + if (e.isPopupTrigger()) { + popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseEntered(e: MouseEvent) { } + override fun mouseExited(e: MouseEvent) { } } +/* entry point */ fun main(args: Array<String>) { LOGGER.log(Level.INFO, "beginning execution") if (OS.type == OS.MAC) { System.setProperty("apple.laf.useScreenMenuBar", "true") } - var frame: JFrame? = null - var con: JPanel? = null + lateinit var con: JPanel inSynSwingThread { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - frame = JFrame(MYNAME) + frame.v = JFrame(MYNAME) con = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) border = EmptyBorder(PANEL_BORDER, PANEL_BORDER, PANEL_BORDER, PANEL_BORDER) - background = frame!!.background + background = frame.v.background } - frame!!.apply { - jMenuBar = makeMenuBar() + frame.v.jMenuBar = menuBar + frame.v.apply { contentPane.add( - JScrollPane(con!!).apply { + JScrollPane(con).apply { verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER preferredSize = Dimension(CPWIDTH, CPHEIGHT) - background = frame!!.background + background = frame.v.background }, BorderLayout.CENTER) pack() setVisible(true) + addWindowListener(KillIt()) } } - val queue = PasteboardQueue(con!!, 10) - val updater = UpdateIt(queue, 1000).apply { start() } - inSwingThread { frame!!.addWindowListener(KillIt(updater)) } -} - -class MenuItemListener: ActionListener { - override fun actionPerformed(e: ActionEvent) { - println(e.actionCommand + " selected") - } + queue.v = PasteboardQueue(con, 10) + UpdateIt(1000).apply { start() } } - -fun makeMenuBar() = JMenuBar().apply { - val al: ActionListener = MenuItemListener() - if (OS.type != OS.MAC) { - add(JMenu("File").apply { - add(JMenuItem("Quit").apply { - actionCommand = "File.Quit" - addActionListener(al) - makeShortcut(KeyEvent.VK_Q) - }) - }) - } - add(JMenu("Edit").apply { - add(JMenuItem("Clone").apply { - actionCommand = "Edit.Clone" - addActionListener(al) - makeShortcut(KeyEvent.VK_C) - }) - add(JMenuItem("Coerce…").apply { - actionCommand = "Edit.Coerce" - addActionListener(al) - makeShortcut(KeyEvent.VK_K) - }) - add(JMenuItem("Delete").apply { - actionCommand = "Edit.Delete" - addActionListener(al) - setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)) - }) - add(JMenuItem("Find…").apply { - actionCommand = "Edit.Find" - addActionListener(al) - makeShortcut(KeyEvent.VK_F) - }) - }) - if (OS.type != OS.MAC) { - add(JMenu("Help").apply { - add(JMenuItem("About ClipMan…").apply { - actionCommand = "Help.About" - addActionListener(al) - }) - }) - } -} - -fun inSwingThread(block: () -> Unit) { - SwingUtilities.invokeLater(Runnable(block)) -} - -fun inSynSwingThread(block: () -> Unit) { - val ready = Semaphore(0) - inSwingThread { - block() - ready.release() - } - ready.acquire() -} - -fun JTextComponent.autoSize(width: Int): Unit { - val SLOP = 10 - val dim = Dimension(width, width) - preferredSize = dim - size = dim - val r = modelToView(document.length) - preferredSize = Dimension(width, r.y + r.height + SLOP) -} - -val SC_KEY_MASK = Toolkit.getDefaultToolkit().menuShortcutKeyMask -fun JMenuItem.makeShortcut(key: Int): Unit { - setAccelerator(KeyStroke.getKeyStroke(key, SC_KEY_MASK)) -}