diff src/name/blackcap/clipman/CoerceDialog.kt @ 31:0c6c18a733b7

Compiles, new menu still a mess.
author David Barts <n5jrn@me.com>
date Thu, 30 Jan 2020 16:01:51 -0800
parents
children 4d87bedb3f65
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/name/blackcap/clipman/CoerceDialog.kt	Thu Jan 30 16:01:51 2020 -0800
@@ -0,0 +1,221 @@
+/*
+ * The dialog that controls font corecion.
+ */
+package name.blackcap.clipman
+
+import java.awt.Color
+import java.awt.Font
+import java.awt.GraphicsEnvironment
+import java.awt.Toolkit
+import java.awt.event.ActionEvent
+import java.awt.event.ActionListener
+import java.util.logging.Level
+import java.util.logging.Logger
+import javax.swing.*
+import javax.swing.event.DocumentEvent
+import javax.swing.event.DocumentListener
+
+class CoerceDialog: JDialog(frame.v), ActionListener {
+    private val FONTS =
+        GraphicsEnvironment.getLocalGraphicsEnvironment().availableFontFamilyNames.copyOf().apply {
+            sort()
+        }
+    private val SIZES =
+        arrayOf(9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 16.0f, 18.0f,
+            24.0f, 36.0f, 48.0f, 64.0f, 72.0f, 96.0f, 144.0f, 288.0f)
+    private val DSIZEI = 6  /* SIZES[6] = 16 */
+
+    /* the proportional font family */
+    private val _pFamily = JComboBox<String>(FONTS).apply {
+        selectedIndex = getFontIndex(Font.SERIF)
+    }
+    val pFamily: String
+    get() {
+        return _pFamily.selectedItem as String
+    }
+
+    /* the proportional font size */
+    private val _pSize = JComboBox<Float>(SIZES).also {
+        it.selectedIndex = DSIZEI
+        it.setEditable(true)
+        it.actionCommand = "Size"
+        it.addActionListener(this)
+    }
+    val pSize: Float
+    get() {
+        return _pSize.selectedItem as Float
+    }
+
+    /* the monospaced font family */
+    private val _mFamily = JComboBox<String>(FONTS).apply {
+        selectedIndex = getFontIndex(Font.MONOSPACED)
+    }
+    val mFamily: String
+    get() {
+        return _mFamily.selectedItem as String
+    }
+
+    /* the monospaced font size */
+    private val _mSize = JComboBox<Float>(SIZES).also {
+        it.selectedIndex = DSIZEI
+        it.setEditable(true)
+        it.actionCommand = "Size"
+        it.addActionListener(this)
+    }
+    val mSize: Float
+    get() {
+        return _mSize.selectedItem as Float
+    }
+
+    /* standard spacing between elements (10 pixels ≅ 1/7") and half that */
+    private val BW = 5
+    private val BW2 = 10
+    private val VSPACE = Box.createVerticalStrut(BW)
+    private val VSPACE2 = Box.createVerticalStrut(BW2)
+    private val HSPACE2 = Box.createHorizontalStrut(BW2)
+
+    /* buttons */
+    private val _coerce = JButton("Coerce").also {
+        it.actionCommand = "Coerce"
+        it.addActionListener(this)
+    }
+
+    private val _cancel = JButton("Cancel").also {
+        it.actionCommand = "Cancel"
+        it.addActionListener(this)
+    }
+
+    /* initializer */
+    init {
+        title = "Coerce Fonts"
+        contentPane.apply {
+            add(Box(BoxLayout.Y_AXIS).apply {
+                add(VSPACE2)
+                add(leftLabel("Coerce proportionally-spaced text to:"))
+                add(VSPACE)
+                add(Box(BoxLayout.X_AXIS).apply {
+                    add(HSPACE2)
+                    add(Box.createGlue())
+                    add(Box(BoxLayout.Y_AXIS).apply {
+                        add(leftLabel("Family:"))
+                        add(_pFamily)
+                    })
+                    add(Box.createGlue())
+                    add(Box(BoxLayout.Y_AXIS).apply {
+                        add(leftLabel("Size:"))
+                        add(_pSize)
+                    })
+                    add(Box.createGlue())
+                    add(HSPACE2)
+                })
+                add(VSPACE2)
+                add(JSeparator())
+                add(VSPACE2)
+                add(leftLabel("Coerce monospaced text to:"))
+                add(VSPACE)
+                add(Box(BoxLayout.X_AXIS).apply {
+                    add(HSPACE2)
+                    add(Box.createGlue())
+                    add(Box(BoxLayout.Y_AXIS).apply {
+                        add(leftLabel("Family:"))
+                        add(_mFamily)
+                    })
+                    add(Box.createGlue())
+                    add(Box(BoxLayout.Y_AXIS).apply {
+                        add(leftLabel("Size:"))
+                        add(_mSize)
+                    })
+                    add(Box.createGlue())
+                    add(HSPACE2)
+                })
+                add(VSPACE2)
+                add(JSeparator())
+                add(VSPACE2)
+                add(Box(BoxLayout.X_AXIS).apply {
+                    add(Box.createGlue())
+                    add(_cancel)
+                    add(Box.createGlue())
+                    add(_coerce)
+                    add(Box.createGlue())
+                })
+                add(VSPACE2)
+            })
+        }
+        rootPane.setDefaultButton(_coerce)
+        pack()
+    }
+
+    private fun leftLabel(text: String) = JLabel(text).apply {
+        horizontalAlignment = JLabel.LEFT
+        alignmentX = JLabel.LEFT_ALIGNMENT
+    }
+
+    override fun actionPerformed(e: ActionEvent) {
+        when (e.actionCommand) {
+            "Size" -> {
+                val source = e.source as? JComboBox<Float>
+                if (source != null && (source.selectedItem as Float) < 1.0f) {
+                    Toolkit.getDefaultToolkit().beep()
+                    source.selectedIndex = DSIZEI
+                }
+            }
+            "Coerce" -> {
+                setVisible(false)
+                coerce()
+            }
+            "Cancel" -> setVisible(false)
+        }
+    }
+
+    private fun coerce() {
+        val selected = queue.v.getSelected()
+        if (selected == null) {
+            JOptionPane.showMessageDialog(frame.v,
+                "No item selected.",
+                "Error",
+                JOptionPane.ERROR_MESSAGE)
+        } else {
+            val (plain, html) = when (selected.contents) {
+                is PasteboardItem.Plain ->
+                    Pair(selected.contents.plain, null)
+                is PasteboardItem.HTML ->
+                    Pair(selected.contents.plain, selected.contents.html)
+                is PasteboardItem.RTF ->
+                    Pair(selected.contents.plain, selected.contents.html)
+            }
+            if (html == null) {
+                JOptionPane.showMessageDialog(frame.v,
+                    "Only styled texts may be coerced.",
+                    "Error",
+                    JOptionPane.ERROR_MESSAGE)
+            } else {
+                PasteboardItem.write(
+                    PasteboardItem.HTML(
+                        plain,
+                        coerceHTML(html, normalizeFont(pFamily), pSize,
+                            normalizeFont(mFamily), mSize)))
+            }
+        }
+    }
+
+    private fun getFontIndex(font: String): Int {
+        val found = FONTS.indexOf(font)
+        if (found < 0) {
+            LOGGER.log(Level.WARNING, "font '${font}' not found")
+            return 0
+        }
+        return found
+    }
+
+    private fun normalizeFont(font: String): String {
+        val lcFont = font.toLowerCase()
+        return when (lcFont) {
+            in setOf("monospace", "serif", "sans-serif") -> lcFont
+            "monospaced" -> "monospace"
+            "sansserif" -> "sans-serif"
+            else -> font
+        }
+    }
+}
+
+val coerceDialog = CoerceDialog()