Mercurial > cgi-bin > hgweb.cgi > JpegWasher
view src/name/blackcap/exifwasher/Misc.kt @ 3:19c381c536ec
Code to make it a proper Mac GUI app. Untested!
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 08 Apr 2020 20:29:12 -0700 |
parents | |
children | dc1f4359659d |
line wrap: on
line source
/* * Miscellaneous utility stuff. */ package name.blackcap.exifwasher import java.awt.Component import java.awt.Cursor import java.awt.Toolkit import javax.swing.* import kotlin.annotation.* import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty /** * Delegate that makes a var that can only be set once. This is commonly * needed in Swing, because some vars inevitably need to be declared at * outer levels but initialized in the Swing event dispatch thread. */ class SetOnce<T: Any>: ReadWriteProperty<Any?,T> { private var value: T? = null override operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { throw RuntimeException("${property.name} has not been initialized") } else { return value!! } } @Synchronized override operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T): Unit { if (value != null) { throw RuntimeException("${property.name} has already been initialized") } value = newValue } } /** * Run something in the Swing thread, asynchronously. * @param block lambda containing code to run */ fun inSwingThread(block: () -> Unit) { SwingUtilities.invokeLater(Runnable(block)) } /** * Run something in the Swing thread, synchronously. * @param block lambda containing code to run */ fun inSynSwingThread(block: () -> Unit) { SwingUtilities.invokeAndWait(Runnable(block)) } /** * Make a shortcut for a menu item, using the standard combining key * (control, command, etc.) for the system we're on. * @param key KeyEvent constant describing the key */ fun JMenuItem.makeShortcut(key: Int): Unit { val SC_KEY_MASK = Toolkit.getDefaultToolkit().menuShortcutKeyMask setAccelerator(KeyStroke.getKeyStroke(key, SC_KEY_MASK)) } /** * Given a MenuElement object, get the item whose text matches the * specified text. * @param text to match * @return first matched element, null if no match found */ fun MenuElement.getItem(name: String) : JMenuItem? { subElements.forEach { val jMenuItem = it.component as? JMenuItem if (jMenuItem?.text == name) { return jMenuItem } } return null } /** * Change to the standard wait cursor. */ fun Component.useWaitCursor() { this.cursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)) } /** * Return back to the normal cursor(). */ fun Component.useNormalCursor() { this.cursor = Cursor.defaultCursor } /** * Thrown if the programmer botches something in our DSL. */ class SwingWorkerException(message: String): Exception(message) { } /** * A simplified SwingWorker DSL. It does not support intermediate * results. Just lets one define a background task and something * to execute when complete. * * @param T Type returned by inBackground (Java doInBackground) task. */ class SwingWorkerBuilder<T>: SwingWorker<T,Unit>() { private var inBackgroundLambda: (SwingWorkerBuilder.() -> T)? = null private var whenDoneLambda: (SwingWorkerBuilder.() -> Unit)? = null private fun setOnce<U>(prop: KMutableProperty<(SwingWorkerBuilder.() -> U)?>, value: SwingWorkerBuilder.() -> U) { if (prop.get() != null) { throw SwingWorkerException(prop.name.removeSuffix("Lambda") + " already defined!") } prop.set(value) } /** * Define the inBackground task. */ fun inBackground(lambda: SwingWorkerBuilder.() -> T): Unit { setOnce<T>(::inBackgroundLambda, lambda) } /** * Define the whenDone task. */ fun whenDone(lambda: SwingWorkerBuilder.() -> Unit): Unit { setOnce<Unit>(::whenDoneLambda, lambda) } /* standard overrides for SwingWorker follow */ override fun doInBackground(): T = inBackgroundLambda?.invoke(this) override fun done(): Unit = whenDoneLambda?.invoke(this) override fun execute(): Unit { if (inBackgroundLambda == null) { throw SwingWorkerException("inBackground not defined!") } else { super.execute() } } } /** * Provides for an outer swingWorker block to contain the DSL. */ fun swingWorker<T>(initializer: SwingWorkerBuilder.() -> Unit): Unit { SwingWorkerBuilder<T>().run { initializer() execute() } } /** * Close a dialog (don't just hide it). */ fun JDialog.close() { setVisible(false) dispose() }