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

y.swing-shortcut-manager_2.9.0-1.1.0.0.source-code.XActionParser.scala Maven / Gradle / Ivy

The newest version!
/*
This file is part of swing-keyboard-manager
, a shortcut manager
for Java Swing used in Penn TotalRecall


swing-keyboard-manager is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, version 3 only.

swing-keyboard-manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with swing-keyboard-manager.  If not, see
.
*/

package edu.upenn.psych.memory.shortcutmanager

import java.net.URL

import scala.collection.{ mutable => m }
import scala.collection.JavaConverters._
import scala.util.Properties

import org.jdom.{ Attribute, Element }
import org.jdom.input.SAXBuilder
import org.jdom.xpath.XPath

class XActionParser(url: URL) {

  private val ClassAttr = "class"
  private val KeyNameAttr = "keyname"
  private val NameAttr = "name"
  private val TooltipAttr = "tooltip"
  private val ArgAttr = "enum"
  private val OsAttr = "os"

  private val KeyName  = "key"
  private val MaskName = "mask"

  sealed trait OS
  case object Windows extends OS
  case object Mac extends OS
  case object Linux extends OS

  lazy val xactions: List[XAction] = {
    val acts = parseXActions()
    val shortcuts: List[Shortcut] = acts.flatMap { _.shortcut }
    val ids: List[String] = acts map { _.id }
    def assertNoDups[A](lst: List[A]) = {
      for (el <- lst) {
        if (lst.count{ el == _ } > 1)
          throw ShortcutFileFormatException(
            "shortcuts file contains duplicate: " + el
          )
      }
    }
    assertNoDups(ids)
    assertNoDups(shortcuts)
    acts
  }

  private def xpathEls(query: String, context: AnyRef): List[Element] = {
    val xpath = XPath newInstance query
    xpath.selectNodes(context).asScala.map {
      _.asInstanceOf[Element]
    }.toList
  }

  private def parseXActions(): List[XAction] = {

    val builder = new SAXBuilder
    val doc = builder build url.openStream()
    val actionEls = xpathEls("//action", doc)

    val xactions = actionEls flatMap { parseSingleXAction(_) }
    xactions toList
  }

  /* `None` is returned if any expected element (e.g., they shortcut element)
   * is not parseable, even if that element is optional. */
  private def parseSingleXAction(act: Element): Option[XAction] = {
    val name = act getAttributeValue NameAttr
    val clazz = act getAttributeValue ClassAttr
    val tooltipOpt = Option(act getAttributeValue TooltipAttr)
    val argOpt = Option(act getAttributeValue ArgAttr)
    val osOpt: Option[List[String]] =
      Option(act getAttributeValue OsAttr) match {
        case Some(str) => Some(str.split(",").toList)
        case None => None
      }

    osOpt match {
      case Some(goodOSes) if goodOSes.contains(Properties.osName) == false => None
      case _ => {
        val baseXAction = XAction(clazz, argOpt, name, tooltipOpt, None)

        if (act.getChildren.size == 0) Some(baseXAction)
        else {
          parseShortcut(act.getChildren.get(0).asInstanceOf[Element]) match {
            case opt @ Some(_) => Some(baseXAction.copy(shortcut = opt))
            case None => None
          }
        }
      }
    }
  }

  def parseShortcut(short: Element): Option[Shortcut] = {
    val keys = short.getChildren.asScala.map { _.asInstanceOf[Element] }
    val maskKeyEls = xpathEls(".//mask", short)
    val nonMaskKeyEls = xpathEls(".//key", short)
    def getNames(els: List[Element]) =
      els.map { _.getAttributeValue(KeyNameAttr) }
    val nonMaskKeyNames = getNames(nonMaskKeyEls)
    val maskKeyNames = getNames(maskKeyEls).map(Key external2InternalForm _)
    Shortcut fromExternalForm (maskKeyNames, nonMaskKeyNames)
  }
}

case class ShortcutFileFormatException(msg: String)
  extends RuntimeException(msg)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy