Skip to content

Commit

Permalink
Add Menu to the application
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Scholz committed Nov 4, 2023
1 parent ba4997d commit 4dba2b1
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 12 deletions.
28 changes: 18 additions & 10 deletions kotlin-app/src/main/kotlin/io/github/simonscholz/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package io.github.simonscholz
import io.github.simonscholz.model.QrCodeConfigViewModel
import io.github.simonscholz.observables.SwingRealm
import io.github.simonscholz.service.RenderImageService.renderImage
import io.github.simonscholz.ui.FrameMenu
import io.github.simonscholz.ui.ImageUI
import io.github.simonscholz.ui.MainUI
import io.github.simonscholz.ui.PropertiesUI
import org.eclipse.core.databinding.DataBindingContext
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import java.awt.image.BufferedImage
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.SwingUtilities

fun main() {
Expand All @@ -25,15 +28,15 @@ fun main() {
},
)

var alreadyAppliedOnce = false
val alreadyAppliedOnceDelegate = { alreadyAppliedOnce }
val qrCodeConfigViewModel = QrCodeConfigViewModel()
FrameMenu.createFrameMenu(frame, qrCodeConfigViewModel, alreadyAppliedOnceDelegate)

val (imagePanel, setImage) = ImageUI.createImagePanel()
val (propertiesPanel, applyOnChange) = PropertiesUI.createPropertiesUI(qrCodeConfigViewModel, dataBindingContext) {
if (qrCodeConfigViewModel.qrCodeContent.value.isNotBlank()) {
val qrCodeImage = renderImage(qrCodeConfigViewModel, frame)
setImage(qrCodeImage)
imagePanel.revalidate()
}
onPropertyApply(qrCodeConfigViewModel, frame, setImage, imagePanel)
alreadyAppliedOnce = true
}

val mainPanel = MainUI.createMainPanel(imagePanel, propertiesPanel)
Expand All @@ -45,13 +48,18 @@ fun main() {
dataBindingContext.bindings.forEach {
it.model.addChangeListener {
if (applyOnChange()) {
if (qrCodeConfigViewModel.qrCodeContent.value.isNotBlank()) {
val qrCodeImage = renderImage(qrCodeConfigViewModel, frame)
setImage(qrCodeImage)
imagePanel.revalidate()
}
onPropertyApply(qrCodeConfigViewModel, frame, setImage, imagePanel)
alreadyAppliedOnce = true
}
}
}
}
}

private fun onPropertyApply(qrCodeConfigViewModel: QrCodeConfigViewModel, frame: JFrame, setImage: (BufferedImage) -> Unit, imagePanel: JPanel) {
if (qrCodeConfigViewModel.qrCodeContent.value.isNotBlank()) {
val qrCodeImage = renderImage(qrCodeConfigViewModel, frame)
setImage(qrCodeImage)
imagePanel.revalidate()
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package io.github.simonscholz.model

import io.github.simonscholz.qrcode.DEFAULT_IMG_SIZE
import org.eclipse.core.databinding.observable.value.WritableValue
import java.awt.Color

class QrCodeConfigViewModel {
val qrCodeContent: WritableValue<String> = WritableValue("https://simonscholz.github.io/", String::class.java)
val size: WritableValue<Int> = WritableValue(200, Int::class.java)
val size: WritableValue<Int> = WritableValue(DEFAULT_IMG_SIZE, Int::class.java)
val backgroundColor: WritableValue<Color> = WritableValue(Color.WHITE, Color::class.java)
val foregroundColor: WritableValue<Color> = WritableValue(Color.BLACK, Color::class.java)

Expand All @@ -25,5 +26,5 @@ class QrCodeConfigViewModel {
val positionalSquareOuterBorderColor: WritableValue<Color> = WritableValue(Color.WHITE, Color::class.java)

override fun toString(): String =
"QrCodeConfigViewModel(qrCodeContent=${qrCodeContent.value}, size=${size.value}, backgroundColor=${backgroundColor.value}, foregroundColor=${foregroundColor.value}, logo=${logo.value}, borderColor=${borderColor.value}, relativeBorderSize=${relativeBorderSize.value}, borderRadius=${borderRadius.value})"
"QrCodeConfigViewModel(qrCodeContent=$qrCodeContent, size=$size, backgroundColor=$backgroundColor, foregroundColor=$foregroundColor, logo=$logo, logoRelativeSize=$logoRelativeSize, logoBackgroundColor=$logoBackgroundColor, borderColor=$borderColor, relativeBorderSize=$relativeBorderSize, borderRadius=$borderRadius, positionalSquareIsCircleShaped=$positionalSquareIsCircleShaped, positionalSquareRelativeBorderRound=$positionalSquareRelativeBorderRound, positionalSquareCenterColor=$positionalSquareCenterColor, positionalSquareInnerSquareColor=$positionalSquareInnerSquareColor, positionalSquareOuterSquareColor=$positionalSquareOuterSquareColor, positionalSquareOuterBorderColor=$positionalSquareOuterBorderColor)"
}
119 changes: 119 additions & 0 deletions kotlin-app/src/main/kotlin/io/github/simonscholz/ui/FrameMenu.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package io.github.simonscholz.ui

import io.github.simonscholz.model.QrCodeConfigViewModel
import io.github.simonscholz.service.RenderImageService
import java.awt.Desktop
import java.awt.event.ActionEvent
import java.awt.event.InputEvent
import java.awt.event.KeyEvent
import java.net.URI
import javax.imageio.ImageIO
import javax.swing.AbstractAction
import javax.swing.JFileChooser
import javax.swing.JFrame
import javax.swing.JMenu
import javax.swing.JMenuBar
import javax.swing.JMenuItem
import javax.swing.JOptionPane
import javax.swing.KeyStroke
import javax.swing.filechooser.FileNameExtensionFilter
import kotlin.system.exitProcess

object FrameMenu {
fun createFrameMenu(frame: JFrame, qrCodeConfigViewModel: QrCodeConfigViewModel, alreadyAppliedOnceDelegate: () -> Boolean) {
// Create and set the menu bar
val menuBar = JMenuBar()
frame.jMenuBar = menuBar

// Create the File menu
val fileMenu = JMenu("File")
menuBar.add(fileMenu)

// Create menu items for File menu
val saveMenuItem = JMenuItem("Save Qr Code Image")
// Add the keybinding for Save (Ctrl + S)
saveMenuItem.accelerator = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)
frame.rootPane.actionMap.put(
"SaveAction",
object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
saveFile(frame, qrCodeConfigViewModel, alreadyAppliedOnceDelegate)
}
},
)
val exitMenuItem = JMenuItem("Exit")
exitMenuItem.accelerator = KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_DOWN_MASK)
frame.rootPane.actionMap.put(
"ExitAction",
object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
exitApplication()
}
},
)

// Add ActionListeners to the menu items
saveMenuItem.addActionListener { saveFile(frame, qrCodeConfigViewModel, alreadyAppliedOnceDelegate) }
exitMenuItem.addActionListener { exitApplication() }

// Add menu items to the File menu
fileMenu.add(saveMenuItem)
fileMenu.addSeparator()
fileMenu.add(exitMenuItem)

// Create the File menu
val helpMenu = JMenu("Help")
menuBar.add(helpMenu)

val gitHubRepoMenuItem = JMenuItem("GitHub Repository")
val readmeMenuItem = JMenuItem("README")
val issueMenuItem = JMenuItem("Open Issue")

gitHubRepoMenuItem.addActionListener { openURL(frame, "https://github.com/SimonScholz/qr-code-with-logo") }
readmeMenuItem.addActionListener { openURL(frame, "https://github.com/SimonScholz/qr-code-with-logo/blob/main/README.adoc") }
issueMenuItem.addActionListener { openURL(frame, "https://github.com/SimonScholz/qr-code-with-logo/issues") }

helpMenu.add(gitHubRepoMenuItem)
helpMenu.add(readmeMenuItem)
helpMenu.add(issueMenuItem)
}

private fun openURL(frame: JFrame, url: String) {
try {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(URI(url))
} else {
// Handle the case where the Desktop class is not supported
JOptionPane.showMessageDialog(frame, "Desktop is not supported on this platform.", "Error", JOptionPane.ERROR_MESSAGE)
}
} catch (e: Exception) {
e.printStackTrace()
// Handle any exceptions that may occur when opening the URL
JOptionPane.showMessageDialog(frame, "Error opening URL: ${e.message}", "Error", JOptionPane.ERROR_MESSAGE)
}
}

private fun saveFile(frame: JFrame, qrCodeConfigViewModel: QrCodeConfigViewModel, alreadyAppliedOnceDelegate: () -> Boolean) {
val fileChooser = JFileChooser()
fileChooser.fileFilter = FileNameExtensionFilter("Png Image Files (*.png)", "png")
val result = fileChooser.showSaveDialog(null)

if (result == JFileChooser.APPROVE_OPTION) {
if (fileChooser.selectedFile.extension.endsWith("png")) {
val selectedFile = fileChooser.selectedFile
val qrCodeImage = if (alreadyAppliedOnceDelegate()) {
RenderImageService.renderImage(qrCodeConfigViewModel = qrCodeConfigViewModel, component = frame)
} else {
RenderImageService.renderInitialImage()
}
ImageIO.write(qrCodeImage, "png", selectedFile)
} else {
JOptionPane.showMessageDialog(frame, "The file to be saved must have the png extension", "Image Saving Error", JOptionPane.ERROR_MESSAGE)
}
}
}

private fun exitApplication() {
exitProcess(0)
}
}

0 comments on commit 4dba2b1

Please sign in to comment.