view src/name/blackcap/clipman/Menus.kt @ 50:3f8409470fdf

Input type to SetOnceImpl cannot be nullable.
author David Barts <n5jrn@me.com>
date Sun, 12 Apr 2020 18:45:23 -0700
parents bb80148e2cb3
children 22725d4d7849
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 java.util.logging.Level
import java.util.logging.Logger
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" -> {
                LOGGER.log(Level.INFO, "execution complete")
                System.exit(0)
            }
            "File.Preferences" -> Application.settingsDialog.setVisible(true)
            "Edit.Clone" -> onlyIfSelected { PasteboardItem.write(it.contents) }
            "Edit.Coerce" -> onlyIfSelected { Application.coerceDialog.setVisible(true) }
            "Edit.Find" -> Application.searchDialog.setVisible(true)
            "Edit.FindAgain" -> Application.searchDialog.find()
            "Help.About" -> showAboutDialog()
            else -> throw RuntimeException("unexpected actionCommand!")
        }
    }

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

/**
 * 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)
}

/**
 * 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(Application.menuItemListener)
                    makeShortcut(KeyEvent.VK_Q)
                })
                add(JMenuItem("Preferences…").apply {
                    actionCommand = "File.Preferences"
                    addActionListener(Application.menuItemListener)
                    makeShortcut(KeyEvent.VK_COMMA)
                })
            })
        }
        add(JMenu("Edit").apply {
            add(Application.anyRequired.add(JMenuItem("Clone").apply {
                setEnabled(false)
                actionCommand = "Edit.Clone"
                addActionListener(Application.menuItemListener)
                makeShortcut(KeyEvent.VK_C)
            }))
            add(Application.styledRequired.add(JMenuItem("Coerce…").apply {
                setEnabled(false)
                actionCommand = "Edit.Coerce"
                addActionListener(Application.menuItemListener)
                makeShortcut(KeyEvent.VK_K)
            }))
            add(JMenuItem("Find…").apply {
                actionCommand = "Edit.Find"
                addActionListener(Application.menuItemListener)
                makeShortcut(KeyEvent.VK_F)
            })
            add(JMenuItem("Find Again").apply {
                actionCommand = "Edit.FindAgain"
                addActionListener(Application.menuItemListener)
                makeShortcut(KeyEvent.VK_G)
            })
        })
        if (OS.type != OS.MAC) {
            add(JMenu("Help").apply {
                add(JMenuItem("About ClipMan…").apply {
                    actionCommand = "Help.About"
                    addActionListener(Application.menuItemListener)
                })
            })
        }
    }

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

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

/**
 * Show an About dialog.
 */
fun showAboutDialog() {
    JOptionPane.showMessageDialog(Application.frame,
        "ClipMan, a clipboard manager.\n"
        + "© MMXX, David W. Barts",
        "About ClipMan",
        JOptionPane.PLAIN_MESSAGE)
}