view src/name/blackcap/imageprep/SettingsDialog.kt @ 27:404eb7e57fe6

Standardize things for Linux packaging.
author David Barts <n5jrn@me.com>
date Fri, 25 Dec 2020 18:58:45 -0800
parents 9bf3d8de6904
children 098c4f5507c7
line wrap: on
line source

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

import java.awt.Dimension
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.io.BufferedWriter
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStreamWriter
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.text.toInt

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

class SettingsDialog: JDialog(Application.mainFrame) {
    /* maximum allowed dimension in output */
    private val _maxDimension = MaxDimSpinner(_PROPS.getInt("maxDimension"))
    val maxDimension: Int
    get() {
        return _maxDimension.value as Int
    }
    
    /* JPEG output quality */
    private val _outputQuality = OutQualSpinner(_PROPS.getInt("outputQuality"))
    val outputQuality: Int
    get() {
        return _outputQuality.value as Int
    }
    
    /* file name output suffix */
    private val _outputSuffix = JTextField(_PROPS.getProperty("outputSuffix"), 24).apply {
        noTaller()
    }
    val outputSuffix: String
    get() {
        return _outputSuffix.text
    }
    
    /* button to change that other directory */
    private val otid = _PROPS.getBoolean("outputToInputDir")
    protected val changeOutputTo = JButton("Change").also {
        it.noTaller()
        it.addActionListener(ActionListener {
            val status = _outputTo.showOpenDialog(this)
            if (status == JFileChooser.APPROVE_OPTION) {
                val path = outputTo
                outputToText.text = path
            }
        })
        it.setEnabled(!otid)
    }
    
    /* output to input dir? */
    private val outputToInputButton = JRadioButton("Create output file in same folder as input.", otid).apply {
        alignmentX = LEFT_ALIGNMENT
    }
    val outputToInputDir: Boolean
    get() {
        return outputToInputButton.isSelected()
    }
    
    /* output to some other directory */
    private val outputToButton = JRadioButton("Create output file in:", !otid).apply {
        alignmentX = LEFT_ALIGNMENT
        addChangeListener(ChangeListener {
            changeOutputTo.setEnabled(isSelected())
        })
    }
    
    /* name of the other directory */
    private val oto = _getOutputTo()
    protected val outputToText = JTextField(oto, 40).apply {
        setEditable(false)
        noTaller()
    }
    
    /* chooser for other directory */
    private val _outputTo = JFileChooser(oto).apply {
        fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
        setMultiSelectionEnabled(false)
    }
    val outputTo: String
    get() {
        return _outputTo.selectedFile?.getCanonicalPath() ?: oto
    }
    
    /* radio button group */
    protected val buttonGroup = ButtonGroup().apply {
        add(outputToButton)
        add(outputToInputButton)
    }
    
    /* 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.noTaller()
        it.addActionListener(ActionListener {
            writeProperties()
            setVisible(false)
        })
    }

    private val _cancel = JButton("Cancel").also {
        it.noTaller()
        it.addActionListener(ActionListener {
            revertValues()
            setVisible(false)
        })
    }

    /* initializer */
    init {
        title = "Preferences"
        contentPane.apply {
            layout = BoxLayout(this, BoxLayout.Y_AXIS)
            add(Box(BoxLayout.X_AXIS).apply {
                alignmentX = LEFT_ALIGNMENT
                border = BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2)
                add(leftLabel("Default maximum dimension: "))
                add(_maxDimension)
                add(Box.createGlue())
                add(leftLabel("Default output quality: "))
                add(_outputQuality)
            })
            add(Box(BoxLayout.X_AXIS).apply {
                alignmentX = LEFT_ALIGNMENT
                border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2)
                add(leftLabel("Output filename suffix: "))
                add(_outputSuffix)
                add(Box.createGlue())
            })
            add(Box(BoxLayout.Y_AXIS).apply {
                alignmentX = LEFT_ALIGNMENT
                border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2)
                add(outputToInputButton)
                add(outputToButton)
                add(Box(BoxLayout.X_AXIS).apply {
                    alignmentX = LEFT_ALIGNMENT
                    add(outputToText)
                    add(changeOutputTo)
                    add(Box.createGlue())
                })
            })
            add(Box(BoxLayout.X_AXIS).apply {
                alignmentX = LEFT_ALIGNMENT
                border = BorderFactory.createEmptyBorder(BW, BW2, BW2, BW2)
                add(Box.createGlue())
                add(_cancel)
                add(Box.createGlue())
                add(_ok)
                add(Box.createGlue())
            })
        }
        pack()
        setResizable(false)
    }

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

    private fun revertValues()
    {
        _maxDimension.value = _PROPS.getInt("maxDimension")
        _outputQuality.value = _PROPS.getInt("outputQuality")
        _outputSuffix.text = _PROPS.getProperty("outputSuffix")
        val otid = _PROPS.getBoolean("outputToInputDir")
        outputToInputButton.setSelected(otid)
        outputToButton.setSelected(!otid)
        val oto = _getOutputTo()
        outputToText.text = oto
        _outputTo.selectedFile = File(oto)
    }

    private fun writeProperties()
    {
        _PROPS.setInt("maxDimension", maxDimension)
        _PROPS.setInt("outputQuality", outputQuality)
        _PROPS.setProperty("outputSuffix", outputSuffix)
        _PROPS.setBoolean("outputToInputDir", outputToInputDir)
        _PROPS.setProperty("outputTo", outputTo)
        try {
            BufferedWriter(OutputStreamWriter(FileOutputStream(PROP_FILE), CHARSET)).use {
                _PROPS.store(it, " -*- coding: ${CHARSET} -*-")
            }
        } 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.mainFrame,
                "Unable to write settings.",
                "Error",
                JOptionPane.ERROR_MESSAGE)
        }
    }
    
    private fun _getOutputTo(): String {
        val p = _PROPS.getProperty("outputTo")
        return if (p != null) tilde(p) else System.getProperty("user.dir")
    }
}

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

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

fun Properties.setInt(key: String, value: Int): Unit {
    setProperty(key, value.toString())
}

fun Properties.getBoolean(key: String): Boolean {
    val raw = getProperty(key)
    if (raw.isNullOrEmpty())
        return false
    val c1 = raw[0].toLowerCase()
    return c1 == 't' || c1 == 'y'
}

fun Properties.setBoolean(key: String, value: Boolean): Unit {
    setProperty(key, value.toString())
}

fun JComponent.noTaller() {
    maximumSize = Dimension(maximumSize.width, preferredSize.height)
}