view src/name/blackcap/clipman/SettingsDialog.kt @ 57:c6cccbe2f393

Port to OpenJDK 15 (mostly done).
author David Barts <n5jrn@me.com>
date Wed, 23 Mar 2022 23:56:29 -0700
parents 19d9da731c43
children
line wrap: on
line source

/*
 * The dialog that controls font corecion.
 */
package name.blackcap.clipman

import java.awt.Dimension
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.io.BufferedWriter
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStreamWriter
import java.util.Hashtable
import java.util.Properties
import java.util.logging.Level
import java.util.logging.Logger
import javax.swing.*
import javax.swing.event.ChangeEvent
import javax.swing.event.ChangeListener
import kotlin.math.log10
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.text.toInt

/* work around name shadowing */
private val _PROPS = PROPERTIES

class SettingsDialog: JDialog(Application.frame), ActionListener, ChangeListener {
    /* max queue length */
    private val _qLength = _PROPS.getInt("queue.length")
    private val _qlSlider = JSlider(10000, 30000, spinToSlide(_qLength)).also {
        it.majorTickSpacing = 10000
        it.paintTicks = true
        it.labelTable = Hashtable<Int, JComponent>().apply {
            put(10000, JLabel("10"))
            put(20000, JLabel("100"))
            put(30000, JLabel("1000"))
        }
        it.paintLabels = true
        it.addChangeListener(this)
    }
    private val _qlSpinner = JSpinner(SpinnerNumberModel(_qLength, 10, 1000, 1)).also {
        it.addChangeListener(this)
        it.maximumSize = Dimension(it.maximumSize.width, it.preferredSize.height)
        (it.editor as? JSpinner.DefaultEditor)?.getTextField()?.setEditable(false)
    }
    val qLength: Int
    get() {
        return _qlSpinner.value as Int
    }

    /* standard spacing between elements (10 pixels ≅ 1/7") and half that */
    private val BW = 5
    private val BW2 = 10

    /* buttons */
    private val _ok = JButton("OK").also {
        it.actionCommand = "OK"
        it.addActionListener(this)
    }

    private val _cancel = JButton("Cancel").also {
        it.actionCommand = "Cancel"
        it.addActionListener(this)
    }

    /* initializer */
    init {
        title = "Preferences"
        contentPane.apply {
            add(Box(BoxLayout.Y_AXIS).apply {
                add(Box(BoxLayout.Y_AXIS).apply {
                    alignmentX = Box.CENTER_ALIGNMENT
                    border = BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2)
                    add(leftLabel("Maximum queue size:"))
                    add(Box.createVerticalStrut(BW))
                    add(Box(BoxLayout.X_AXIS).apply {
                        alignmentX = Box.LEFT_ALIGNMENT
                        add(Box.createGlue())
                        add(_qlSlider)
                        add(Box.createGlue())
                        add(_qlSpinner)
                        add(Box.createGlue())
                    })
                })
                add(JSeparator())
                add(Box(BoxLayout.X_AXIS).apply {
                    alignmentX = Box.CENTER_ALIGNMENT
                    border = BorderFactory.createEmptyBorder(BW, BW2, BW2, BW2)
                    add(Box.createGlue())
                    add(_cancel)
                    add(Box.createGlue())
                    add(_ok)
                    add(Box.createGlue())
                })
            })
        }
        rootPane.setDefaultButton(_ok)
        pack()
        setResizable(false)
    }

    override fun actionPerformed(e: ActionEvent) {
        when (e.actionCommand) {
            "OK" -> {
                writeProperties()
                Application.queue.maxSize = qLength
                setVisible(false)
            }
            "Cancel" -> {
                revertValues()
                setVisible(false)
            }
        }
    }

    override fun stateChanged(e: ChangeEvent) {
        when (e.source) {
            is JSlider ->
                _qlSpinner.value = (10.0).pow(_qlSlider.value.toDouble() / 10000.0).roundToInt()
            is JSpinner ->
                _qlSlider.value = spinToSlide(_qlSpinner.value as Int)
        }
    }

    private fun spinToSlide(value: Int): Int =
        (log10(value.toDouble()) * 10000.0).roundToInt()

    private fun leftLabel(text: String) = JLabel(text).apply {
        alignmentX = JLabel.LEFT_ALIGNMENT
    }

    private fun revertValues()
    {
        val ql = _PROPS.getInt("queue.length")
        _qlSpinner.value = ql
        _qlSlider.value = spinToSlide(ql)
    }

    private fun writeProperties()
    {
        try {
            BufferedWriter(OutputStreamWriter(FileOutputStream(PROP_FILE), CHARSET)).use {
                _PROPS.put("queue.length", qLength.toString())
                _PROPS.store(it, null)
            }
        } catch (e: IOException) {
            LOGGER.log(Level.WARNING, "IOException writing properties file")
            val message = e.message
            if (message != null && !message.isEmpty()) {
                LOGGER.log(Level.WARNING, message)
            }
            JOptionPane.showMessageDialog(Application.frame,
                "Unable to write settings.",
                "Error",
                JOptionPane.ERROR_MESSAGE)
        }
    }
}

fun Properties.getString(key: String): String = getProperty(key) as String

fun Properties.getInt(key: String): Int = getString(key).toInt()