view src/name/blackcap/clipman/Menus.kt @ 37:9890445e4cc4

Didn't like eating its own dog food. Fixed.
author David Barts <n5jrn@me.com>
date Thu, 30 Jan 2020 21:03:56 -0800
parents fcf82e3b7e31
children 2a5808156f99
line wrap: on
line source

/*
 * Menu-related stuff, pertaining to both the menu bar and popup menus.
 */
package name.blackcap.clipman

import java.awt.Container
import java.awt.Toolkit
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyEvent
import javax.swing.*
import kotlin.collections.HashSet

/**
 * Listen to actionEvents from both menu bar and popup menu selections.
 */
class MenuItemListener: ActionListener {
    override fun actionPerformed(e: ActionEvent) {
        when (e.actionCommand) {
            "File.Quit" -> System.exit(0)
            "Edit.Clone" -> onlyIfSelected { PasteboardItem.write(it.contents) }
            "Edit.Coerce" -> onlyIfSelected { coerceDialog.setVisible(true) }
            "Edit.Find" -> searchDialog.setVisible(true)
            "Edit.FindAgain" -> searchDialog.find()
            else -> throw RuntimeException("unexpected actionCommand!")
        }
    }

    private fun onlyIfSelected(block: (QueueItem) -> Unit) {
        val selected = queue.v.getSelected()
        if (selected == null) {
            JOptionPane.showMessageDialog(frame.v,
                "No item selected.",
                "Error",
                JOptionPane.ERROR_MESSAGE)
        } else {
            block(selected)
        }
    }

    private fun clone(contents: PasteboardItem) {
        val (plain, html) = when(contents) {
            is PasteboardItem.Plain -> Pair(contents.plain, null)
            is PasteboardItem.HTML -> Pair(contents.plain, contents.html)
            is PasteboardItem.RTF -> Pair(contents.plain, contents.html)
        }
        if (html == null) {
            PasteboardItem.write(PasteboardItem.Plain(plain))
        } else {
            PasteboardItem.write(PasteboardItem.HTML(plain, scrub(html)))
        }
    }
}

val menuItemListener = MenuItemListener()

/**
 * Track menu items that require something to be selected in order
 * to work, and allow them to be enabled and disabled en masse.
 */
class SelectionRequired {
    private val controls = HashSet<JMenuItem>()

    fun add(item: JMenuItem): JMenuItem {
        controls.add(item)
        return item
    }

    private fun setEnabled(state: Boolean) {
        controls.forEach {
            it.setEnabled(state)
        }
    }

    fun enable() = setEnabled(true)

    fun disable() = setEnabled(false)
}

val anyRequired = SelectionRequired()
val styledRequired = SelectionRequired()

/**
 * Our menu bar. What we display depends somewhat on the system type, as
 * the Mac gives us a gratuitous menu bar entry for handling some stuff.
 */
class MyMenuBar: JMenuBar() {
    init {
        if (OS.type != OS.MAC) {
            add(JMenu("File").apply {
                add(JMenuItem("Quit").apply {
                    actionCommand = "File.Quit"
                    addActionListener(menuItemListener)
                    makeShortcut(KeyEvent.VK_Q)
                })
            })
        }
        add(JMenu("Edit").apply {
            add(anyRequired.add(JMenuItem("Clone").apply {
                setEnabled(false)
                actionCommand = "Edit.Clone"
                addActionListener(menuItemListener)
                makeShortcut(KeyEvent.VK_C)
            }))
            add(styledRequired.add(JMenuItem("Coerce…").apply {
                setEnabled(false)
                actionCommand = "Edit.Coerce"
                addActionListener(menuItemListener)
                makeShortcut(KeyEvent.VK_K)
            }))
            add(JMenuItem("Find…").apply {
                actionCommand = "Edit.Find"
                addActionListener(menuItemListener)
                makeShortcut(KeyEvent.VK_F)
            })
            add(JMenuItem("Find Again").apply {
                actionCommand = "Edit.FindAgain"
                addActionListener(menuItemListener)
                makeShortcut(KeyEvent.VK_G)
            })
        })
        if (OS.type != OS.MAC) {
            add(JMenu("Help").apply {
                add(JMenuItem("About ClipMan…").apply {
                    actionCommand = "Help.About"
                    addActionListener(menuItemListener)
                })
            })
        }
    }

    fun getMenu(name: String): JMenu? {
        subElements.forEach {
            val jmenu = it.component as? JMenu
            if (jmenu?.text == name) {
                return jmenu
            }
        }
        return null
    }
}

val menuBar = MyMenuBar()

/**
 * The popup menu we display when the user requests so atop a clipboard
 * item.
 */
class MyPopupMenu: JPopupMenu() {
    init {
        add(anyRequired.add(JMenuItem("Clone").apply {
            actionCommand = "Edit.Clone"
            addActionListener(menuItemListener)
        }))
        add(styledRequired.add(JMenuItem("Coerce…").apply {
            actionCommand = "Edit.Coerce"
            addActionListener(menuItemListener)
        }))
    }
}

val popupMenu = MyPopupMenu()