All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.truffulatree.h2odb.App.scala Maven / Gradle / Ivy

// Copyright 2013, Martin Pokorny 
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
//
package org.truffulatree.h2odb

import scala.swing._
import scala.swing.event._
import javax.swing.filechooser.FileNameExtensionFilter
import javax.swing.JPopupMenu
import java.awt.{ Cursor, Dimension, Font }
import java.awt.datatransfer.{ StringSelection }
import scala.concurrent.SyncVar
import java.io.{ File, FileInputStream }
import org.slf4j.LoggerFactory
import com.healthmarketscience.jackcess.DatabaseBuilder
import org.apache.poi.hssf.usermodel.HSSFWorkbook

/** Add xsbti.MainResult return value to SimpleSwingApplication.main().
  */
trait SwingAppMain {
  self: SimpleSwingApplication =>

  private val exitVal = new SyncVar[Int]()

  /** Call SimpleSwingApplication.main(), then wait until exitVal has a value.
    */
  def apply(args: Array[String]): xsbti.MainResult = {
    main(args)
    new Exit(exitVal.take())
  }

  override def quit(): Unit = {
    shutdown()
    exitVal.put(0)
  }
}

object PopupMenu {
  private[PopupMenu] trait JPopupMenuMixin { def popupMenuWrapper: PopupMenu }

  def defaultLightWeightPopupEnabled: Boolean =
    JPopupMenu.getDefaultLightWeightPopupEnabled

  def defaultLightWeightPopupEnabled_=(aFlag: Boolean): Unit = {
    JPopupMenu.setDefaultLightWeightPopupEnabled(aFlag)
  }
}

class PopupMenu extends Component with SequentialContainer.Wrapper {

  override lazy val peer: JPopupMenu =
    new JPopupMenu with PopupMenu.JPopupMenuMixin with SuperMixin {
      def popupMenuWrapper = PopupMenu.this
    }

  def lightWeightPopupEnabled: Boolean = peer.isLightWeightPopupEnabled

  def lightWeightPopupEnabled_=(aFlag: Boolean): Unit = {
    peer.setLightWeightPopupEnabled(aFlag)
  }

  def show(invoker: Component, x: Int, y: Int): Unit = {
    peer.show(invoker.peer, x, y)
  }
}

object SwingApp extends SimpleSwingApplication with SwingAppMain {

  class SelectButton(
    val buttonText: String,
    val fileFilter: FileNameExtensionFilter,
    val field: TextField)
      extends Button {
    button =>

    text = buttonText

    var chooser: FileChooser = _

    resetChooser(None)

    def resetChooser(dir: Option[File]): Unit = {
      chooser = new FileChooser(dir.getOrElse(null)) {
        fileFilter = button.fileFilter
        multiSelectionEnabled = false
        fileSelectionMode = FileChooser.SelectionMode.FilesOnly
        title = button.text
      }
    }
  }

  class FileSelectorPanel(
    tooltip: String,
    buttonText: String,
    fileFilter: FileNameExtensionFilter)
      extends BoxPanel(Orientation.Horizontal) {
    panel =>

    val textField = new TextField(20) {
      tooltip = panel.tooltip
      editable = false
    }

    val selectButton = new SelectButton(buttonText, fileFilter, textField)

    def reset(): Unit = {
      if (!selectButton.field.text.isEmpty) {
        val file = new File(selectButton.field.text)
        if (file.isFile)
          selectButton.resetChooser(Some(new File(file.getParent)))
        selectButton.field.text = ""
      } else {
        selectButton.resetChooser(None)
      }
    }

    contents += selectButton
    contents += textField
    border = Swing.EmptyBorder(5)
  }

  val buttonPanel = new BoxPanel(Orientation.Horizontal) {
    val quitButton = new Button {
      text = "Quit"
    }

    val goButton = new Button {
      text = "Go"
      enabled = false
    }

    contents += goButton
    contents += quitButton

    border = Swing.EmptyBorder(10)
  }

  def top = new MainFrame {
    title = "H2Odb"

    val xlsPanel = new FileSelectorPanel(
      "Water analysis report (Excel file)",
      "Select report",
      new FileNameExtensionFilter("Excel file", "xls"))

    val dbPanel = new FileSelectorPanel(
      "Database (Access file)",
      "Select database",
      new FileNameExtensionFilter("Access database", "mdb"))

    contents = new BoxPanel(Orientation.Vertical) {
      contents += xlsPanel
      contents += dbPanel
      contents += buttonPanel
      border = Swing.EmptyBorder(30, 30, 10, 30)
    }

    reactions += {
      case ButtonClicked(b) if b == buttonPanel.quitButton =>
        quit()

      case ButtonClicked(b) if b == buttonPanel.goButton => {
        buttonPanel.goButton.enabled = false
        val xlsPath = xlsPanel.selectButton.field.text
        val dbPath = dbPanel.selectButton.field.text
        val origCursor = cursor
        cursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)
        runFiller(xlsPath, dbPath)
        xlsPanel.reset()
        dbPanel.reset()
        cursor = origCursor
      }

      case ButtonClicked(b: SelectButton) => {
        b.chooser.showDialog(b, "Select") match {
          case FileChooser.Result.Approve =>
            b.field.text = b.chooser.selectedFile.getPath
          case _ =>
        }
      }

      case ValueChanged(f: TextField)
          if (f == xlsPanel.selectButton.field ||
            f == dbPanel.selectButton.field) => {
            if (!(xlsPanel.selectButton.field.text.isEmpty ||
              dbPanel.selectButton.field.text.isEmpty))
              buttonPanel.goButton.enabled = true
            else
              buttonPanel.goButton.enabled = false
          }
    }

    listenTo(buttonPanel.quitButton)
    listenTo(buttonPanel.goButton)
    listenTo(xlsPanel.selectButton)
    listenTo(dbPanel.selectButton)
    listenTo(xlsPanel.selectButton.field)
    listenTo(dbPanel.selectButton.field)
  }

  def runFiller(xlsPath: String, dbPath: String): Unit = {

    class OpenException(m: String) extends Exception(m)

    def openFile[A](path: String, opener: (String) => A, desc: String): A =
      try {
        opener(path)
      } catch {
        case _: java.io.IOException =>
          throw new OpenException(s"Failed to open ${path} as ${desc}")
      }

    try {
      val xls = openFile(
        xlsPath,
        (s: String) => new HSSFWorkbook(new FileInputStream(s)),
        "an Excel file")

      val db = openFile(
        dbPath,
        (s: String) => (new DatabaseBuilder(new File(s))).setAutoSync(false).
          setReadOnly(false).open,
        "an Access database")

      val resultsFrame = new Frame {
        title = "Results"

        val textArea = new TextArea(10, 40) {
          textArea =>

          lineWrap = true
          wordWrap = true

          reactions += {
            case ev @ MousePressed(_,_,_,_,true) => showPopupMenu(ev)
            case ev @ MouseReleased(_,_,_,_,true) => showPopupMenu(ev)
          }
          listenTo(mouse.clicks)

          def showPopupMenu(event: MouseEvent): Unit = {
            if (selected != null && selected.length > 0)
              popupMenu.show(event.source, event.point.x, event.point.y)
          }

          val popupMenu = new PopupMenu {
            contents += new MenuItem(
              Action("Copy") {
                val selection = new StringSelection(textArea.selected)
                toolkit.getSystemClipboard.setContents(selection, selection)
                this.visible = false
              })
          }
        }

        contents = new BoxPanel(Orientation.Vertical) {

          contents += new TextField {
            editable = false
            text = s"${(new File(xlsPath)).getName} loaded into ${(new File(dbPath)).getName}"
            font = font.deriveFont(Font.BOLD)
            horizontalAlignment = Alignment.Center
            border = Swing.EmptyBorder(10)
            maximumSize = preferredSize
          }

          contents += new ScrollPane {
            contents = textArea
            verticalScrollBarPolicy = ScrollPane.BarPolicy.AsNeeded
            horizontalScrollBarPolicy = ScrollPane.BarPolicy.Never
          }
        }
      }

      try {
        DBFiller((s: String) => resultsFrame.textArea.append(s + "\n"), xls, db)
      } catch {
        case dbe: H2ODbException =>
          resultsFrame.textArea.append(dbe.getMessage)
      }

      if (resultsFrame.size == new Dimension(0, 0)) resultsFrame.pack()
      resultsFrame.visible = true

    } catch {
      case oe: OpenException =>
        Dialog.showOptions(
          message = oe.getMessage,
          title = "File Error",
          optionType = Dialog.Options.Default,
          messageType = Dialog.Message.Error,
          entries = List("OK"),
          initial = 0)
    }
  }
}

class Exit(val code: Int) extends xsbti.Exit

class Run extends xsbti.AppMain {
  private val logger = LoggerFactory.getLogger(getClass.getName.init)
  def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = {
    configuration.provider.scalaProvider.version match {
      case "2.11.4" => {
        try {
          SwingApp(configuration.arguments)
        } catch {
          case e: Exception => {
            logger.error(e.getMessage)
            new Exit(1)
          }
        }
      }
      case _ => new xsbti.Reboot {
        def arguments = configuration.arguments
        def baseDirectory = configuration.baseDirectory
        def scalaVersion = "2.11.4"
        def app = configuration.provider.id
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy