Writing own key publisher for MainFrame - scala

I want my MainFrame to catch key events. I didn't find any key publisher already in it, so I'm going to write my own ... I have something like this:
class ImageView(image: ImageIcon, parent: UIElement = null) extends MainFrame {
object keys extends Publisher {
peer.addKeyListener(new KeyListener {
def keyPressed(e: java.awt.event.KeyEvent) {
publish(new KeyPressed(e))
}
def keyReleased(e: java.awt.event.KeyEvent) {
publish(new KeyReleased(e))
}
def keyTyped(e: java.awt.event.KeyEvent) {
publish(new KeyTyped(e))
}
})
}
listenTo(keys)
reactions += {
case KeyPressed(_, key,_,_) =>
if (key == Key.Escape) dispose
}
}
Anyway when I press any key, I get this exception:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: scala.swing.Frame$$anon$1 cannot be cast to javax.swing.JComponent
at scala.swing.event.KeyPressed.<init>(KeyEvent.scala:33)
at pip.gui.ImageView$keys$$anon$2.keyPressed(ImageView.scala:35)
at java.awt.Component.processKeyEvent(Component.java:6225)
at java.awt.Component.processEvent(Component.java:6044)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Window.processEvent(Window.java:1836)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Window.dispatchEventImpl(Window.java:2478)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1850)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:712)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:990)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:855)
at
.
.
.
.
(continues long further)
I brought up this publisher code from Component.keys, so what is actually wrong here?
Thanks in advance,
Tony

This seems bad design in the library. Looking into KeyEvent.scala, there's all kinds of casting to JComponent going on, and JFrame is a subclass of java.awt.Component but not JComponent, so it should be impossible to call listenTo(keys).
What you want is to listen to the top-most component in the frame's contents. For instance:
import scala.swing._; import event._
import javax.swing._
class ImageView(image: ImageIcon, parent: UIElement = null) extends MainFrame {
val b = new BorderPanel {
listenTo( keys )
reactions += {
case KeyPressed(_, key,_,_) =>
println( "PRESSED : " + key )
if (key == Key.Escape) dispose
}
}
contents = b
}
val w = new ImageView( null )
w.peer.setSize( 200, 200 )
w.visible = true
w.b.requestFocus
the requestFocus is essential because the panel doesn't request the focus by itself even if you click on it, so otherwise it wouldn't receive key events.

Related

Scala/Akka How do you reference the message being received?

I have a Java program that I must implement in Scala, but I am extremely new to Scala. After reading a number of SO question & answers as well as reading through a number of Google-retrieved resources on case classes, I am still having trouble grasping how to acquire a reference to the message I received? Example code is below:
case class SpecialMessage(key: Int) {
val id: Int = Main.idNum.getAndIncrement().intValue()
def getId(): Int = {
return id
}
}
Then in another class's receive I am trying to reference that number with:
def receive() = {
case SpecialMessage(key) {
val empID = ?? getId() // Get the id stored in the Special Message
// Do stuff with empID
}
}
I cannot figure out what to put on the right sight of empID = in order to get that id. Is this really simple, or something that isn't normally done?
These are 2 ways to do what you want, pick the one that suits best
case msg: SpecialMessage => {
val empID = msg.getId() // Get the id stored in the Special Message
// Do stuff with empID
}
case msg # SpecialMessage(key) => {
val empID = msg.getId() // Get the id stored in the Special Message
// Do stuff with empID
}
Pim's answer is good.
But maybe you can modify the structure of SpecialMessage like
case class SpecialMessage(key: Int,val id: Int = Main.idNum.getAndIncrement().intValue())
so you can get id directly from pattern matching.
def receive() = {
case SpecialMessage(key, empID) {
// Do stuff with empID
}
}

Terminating a scala program?

I have used try catch as part of my mapreduce code. I am reducing my values based on COUNT in the below code. how do i terminate the job using the code in the below
class RepReducer extends Reducer[NullWritable, Text, Text, IntWritable] {
override def reduce(key: NullWritable, values: Iterable[Text], context: Reducer[NullWritable, Text, Text, IntWritable]#Context): Unit = {
val count = values.toList.length
if (count == 0){
try {
context.write(new Text("Number of tables with less than 40% coverage"), new IntWritable(count))
} catch {
case e: Exception =>
Console.err.println(" ")
e.printStackTrace()
}
}
else
{
System.out.println("terminate job") //here i want to terminate if count is not equal to 0
}
}
}
I think you still need to call context.write to return the control back to Hadoop even if you decide to skip certain data in the 'else'.

Lift Framework - problems with passing url param to Snippet class

I am trying to do a simple case of /author/ and get the Lift to build a Person object based on the id passed in.
Currently i have an Author snippet
class Author(item: Person) {
def render = {
val s = item match { case Full(item) => "Name"; case _ => "not found" }
" *" #> s;
}
}
object Author{
val menu = Menu.param[Person]("Author", "Author", authorId => findPersonById(authorId), person => getIdForPerson(person)) / "author"
def findPersonById(id:String) : Box[Person] = {
//if(id == "bob"){
val p = new Person()
p.name="Bobby"
p.age = 32
println("findPersonById() id = " +id)
Full(p)
//}else{
//return Empty
//}
}
def getIdForPerson(person:Person) : String = {
return "1234"
}
}
What i am attempting to do is get the code to build a boxed person object and pass it in to the Author class's constructor. In the render method i want determine if the box is full or not and proceed as appropriate.
If i change
class Author(item: Person) {
to
class Author(item: Box[Person]) {
It no longer works but if i leave it as is it is no longer valid as Full(item) is incorrect. If i remove the val s line it works (and replace the s with item.name). So how do i do this. Thanks
The Box returned from findPersonById(id:String) : Box[Person] is evaluated and if the Box is Full, the unboxed value is passed into your function. If the Box is Empty or Failure the application will present a 404 or appropriate error page instead.
You can try double boxing your return if you want to handle this error checking yourself (so that the result of this method is always a Full Box).
def findPersonById(id:String) : Box[Box[Person]] = {
if(id == "bob"){
val p = new Person()
p.name="Bobby"
p.age = 32
println("findPersonById() id = " +id)
Full(Full(p))
}else{
return Full(Empty)
}
}
and then this should work:
class Author(item: Box[Person])

Modifying Scala GUI's outside of object

I have a GUI ive created in Scala. Its very simple but I would like to modify the DSLOutput object from outside of DSLGUI. Does anyone know how I can call DSLOutput.append() from outside of the DSLGUI? Ive tried importing DSLGUI but I cant seems to figure out how to access DSLOutput.
package api
import swing._
import event._
object DSLGUI extends SimpleSwingApplication{
def top = new MainFrame{
title = "Computer Repair Advisory System"
object Commands extends TextField(columns = 50)
object DSLOutput extends TextArea(rows = 15, columns = 50)
object SendCommand extends Button("Send")
val CommandPanel = new FlowPanel{
contents += Commands
contents += SendCommand
}
contents = new BoxPanel(Orientation.Vertical){
contents +=CommandPanel
contents += DSLOutput
}
listenTo(SendCommand)
reactions += {
case ButtonClicked(SendCommand) =>
DSLOutput append "Test "
}
}
}
You would have to declare it in the scope of DSLGUI, rather than as a local object within your top method. Then you can access it with DSLGUI.DSLOutput.
i.e.
object DSLGUI extends SimpleSwingApplication {
object DSLOutput extends TextArea(rows = 15, columns = 50)
def top = new MainFrame {
...
}
}

Copy Groovy class properties

I want to copy object properties to another object in a generic way (if a property exists on target object, I copy it from the source object).
My code works fine using ExpandoMetaClass, but I don't like the solution. Are there any other ways to do this?
class User {
String name = 'Arturo'
String city = 'Madrid'
Integer age = 27
}
class AdminUser {
String name
String city
Integer age
}
def copyProperties(source, target) {
target.properties.each { key, value ->
if (source.metaClass.hasProperty(source, key) && key != 'class' && key != 'metaClass') {
target.setProperty(key, source.metaClass.getProperty(source, key))
}
}
}
def (user, adminUser) = [new User(), new AdminUser()]
assert adminUser.name == null
assert adminUser.city == null
assert adminUser.age == null
copyProperties(user, adminUser)
assert adminUser.name == 'Arturo'
assert adminUser.city == 'Madrid'
assert adminUser.age == 27
I think the best and clear way is to use InvokerHelper.setProperties method
Example:
import groovy.transform.ToString
import org.codehaus.groovy.runtime.InvokerHelper
#ToString
class User {
String name = 'Arturo'
String city = 'Madrid'
Integer age = 27
}
#ToString
class AdminUser {
String name
String city
Integer age
}
def user = new User()
def adminUser = new AdminUser()
println "before: $user $adminUser"
InvokerHelper.setProperties(adminUser, user.properties)
println "after : $user $adminUser"
Output:
before: User(Arturo, Madrid, 27) AdminUser(null, null, null)
after : User(Arturo, Madrid, 27) AdminUser(Arturo, Madrid, 27)
Note: If you want more readability you can use category
use(InvokerHelper) {
adminUser.setProperties(user.properties)
}
I think your solution is quite good and is in the right track. At least I find it quite understandable.
A more succint version of that solution could be...
def copyProperties(source, target) {
source.properties.each { key, value ->
if (target.hasProperty(key) && !(key in ['class', 'metaClass']))
target[key] = value
}
}
... but it's not fundamentally different. I'm iterating over the source properties so I can then use the values to assign to the target :). It may be less robust than your original solution though, as I think it would break if the target object defines a getAt(String) method.
If you want to get fancy, you might do something like this:
def copyProperties(source, target) {
def (sProps, tProps) = [source, target]*.properties*.keySet()
def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
commonProps.each { target[it] = source[it] }
}
Basically, it first computes the common properties between the two objects and then copies them. It also works, but I think the first one is more straightforward and easier to understand :)
Sometimes less is more.
Another way is to do:
def copyProperties( source, target ) {
[source,target]*.getClass().declaredFields*.grep { !it.synthetic }.name.with { a, b ->
a.intersect( b ).each {
target."$it" = source."$it"
}
}
}
Which gets the common properties (that are not synthetic fields), and then assigns them to the target
You could also (using this method) do something like:
def user = new User()
def propCopy( src, clazz ) {
[src.getClass(), clazz].declaredFields*.grep { !it.synthetic }.name.with { a, b ->
clazz.newInstance().with { tgt ->
a.intersect( b ).each {
tgt[ it ] = src[ it ]
}
tgt
}
}
}
def admin = propCopy( user, AdminUser )
assert admin.name == 'Arturo'
assert admin.city == 'Madrid'
assert admin.age == 27
So you pass the method an object to copy the properties from, and the class of the returned object. The method then creates a new instance of this class (assuming a no-args constructor), sets the properties and returns it.
Edit 2
Assuming these are Groovy classes, you can invoke the Map constructor and set all the common properties like so:
def propCopy( src, clazz ) {
[src.getClass(), clazz].declaredFields*.grep { !it.synthetic }.name.with { a, b ->
clazz.metaClass.invokeConstructor( a.intersect( b ).collectEntries { [ (it):src[ it ] ] } )
}
}
Spring BeanUtils.copyProperties will work even if source/target classes are different types. http://docs.spring.io/autorepo/docs/spring/3.2.3.RELEASE/javadoc-api/org/springframework/beans/BeanUtils.html