How do I implement specific interface methods using closure conversion in jruby? - jruby

I would like to take different actions when an swt menu is shown or hidden, so I am adding a MenuListener to a Menu
If I create the listener using a class and add an instance of that class via add_menu_listener I can separately detect showing events and hiding events. For example using the following Listener class:
class MyListener
include MenuListener
def menu_shown e
puts "#{e} was a show event"
end
def menu_hidden e
puts "#{e} was a Hide event"
end
end
and then add the listener to the menu via
my_menu.add_menu_listener MyListener.new
will print different messages when the menu is shown vs hidden.
I can also add a listener using "closure conversion" for example this will produce a message whenever the menu is shown or hidden.
my_menu.add_menu_listener { |e| puts "#{e} was a menu event" }
These two sections of the jruby wiki seem to cover implementing interfaces in jruby.
https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#implementing-java-interfaces-in-jruby
https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#closure-conversion
The second section seems to indicate that this "closure conversion" method should work for any interface, but I can't figure out out to get it to separate out the two different methods.
Does anyone know how to use this "closure conversion" scheme to implement each of the specific interface methods separately?

Looking more closely at https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby#closure-conversion
I see this statement:
The block is converted to a Proc object, which is then decorated with
a java interface proxy that invokes the block for any method
called on the interface.
I think this means there is no way to tell what method called the block.
What I decided to (unless someone has a better solution) is this
show = "Show"
hide = "Hide"
my_listener = MenuListener.new
my_listener.define_singleton_method(:menu_shown) { |e| puts "#{e} was a #{show} event" }
my_listener.define_singleton_method(:menu_hidden) { |e| puts "#{e} was a #{hide} event" }
my_menu.add_menu_listener my_listener
Note:
I chose this over
my_listener = MenuListener.new
class << my_listener
def menu_shown e
...
end
def menu_hidden e
...
end
end
my_menu.add_menu_listener my_listener
since I need to reference some free variables as shown above

Related

How should I access generated children of a custom HTML component in an idiomatic React way?

I am attempting to create a search bar using a custom HTML component for predictive text input. The way this component is built, it generates several plain HTML children that I need to act on to get full features. Specifically, I need to execute a blur action on one of the generated elements when the user presses escape or enter.
I got it to work using a ref on the custom component and calling getElementsByClassName on the ref, but using getElementsByClassName does not seem like the best solution. It pierces through the virtual and has odd side effects when testing.
This is a snippet of the component being rendered:
<predictive-input id='header-search-bar-input' type='search'
value={this.state.keywords}
ref={(ref: any) => this.predictiveInput = ref}
onKeyDown={(e: React.KeyboardEvent<any>) => this.handleKeyDown(e)}>
</predictive-input>
and the keyDown handler:
private handleKeyDown(e: React.KeyboardEvent<any>) {
// must access the underlying input element of the kat-predictive-input
let input: HTMLElement = this.predictiveInput.getElementsByClassName('header-row-text value')[0] as HTMLElement;
if (e.key === 'Escape') {
// blur the predictive input when the user presses escape
input.blur();
} else if (e.key === 'Enter') {
// commit the search when user presses enter
input.blur();
// handles action of making actual search, using search bar contents
this.commitSearch();
}
}
The element renders two children, one for the bar itself and one for the predictive dropdown. The classes of the underlying in the first are 'header-row-text' and 'value', so the element is correctly selected, but I am worried that this is violating proper React style.
I am using React 16.2, so only callback refs are available. I would rather avoid upgrading, but if a 16.3+ solution is compelling enough, I could consider it.
If you don't have any control over the input then this is the best approach in my opinion.
It's not ideal, but as you're stuck with a 3rd party component you can only choose from the methods that are available to you. In this case, your only real options are to find the element based on its class, or its position in the hierarchy. Both might change if the package is updated, but if I had to choose which would be more stable, I'd go for className.

get an error trying right_click for Selenium Webriver

I am using Ruby/Cucumber
my page:
class DemoContextMenuPage
include PageObject
include DataMagic
page_url 'http://the-internet.herokuapp.com/context_menu'
h5(:context_menu_title, :css => '.example > h3:nth-child(1)')
div(:context_menu_hotspot, :id => 'hot-spot')
end
my step:
When /^I right click context menu hot spot$/ do
on(DemoContextMenuPage).context_menu_hotspot_element.right_click
end
my feature:
Scenario: Verify right click menu
Given I am on the context menu page
When I right click context menu hot spot
result:
undefined method `context_click' for # (NoMethodError)
no issues with watir-webdriver only selenium-webdriver Se=2.53.4, watir=0.9.3
This is a bug in the Page Object gem. You can see from the page object's Selenium implementation that it does:
def right_click
element.context_click
end
context_click is not a method defined for Selenium elements.
As seen from the Watir source code, context clicks need to be done using the action builder:
driver.action.context_click(#element).perform
Unfortunately, there does not appear to be a way to get the Selenium::WebDriver from a Selenium::Element. I think you will need to call the context click from the page object:
on(DemoContextMenuPage) do |page|
e = page.context_menu_hotspot_element.element
page.browser.action.context_click(e).perform
end

How to use contents = to add to a Scala Panel?

Sorry this must be a very silly question.. but everywhere I've been seeing Scala code examples where you just do
contents+= on a BoxPanel or some layout Panel. I figured because they have contents as mutable.buffer so you can just add and remove components.
But how do you add a component to Scala Panel? It accepts a seq so do you have to give it a list or something? I know you can just call peer.add but I want to see how Scala code does it. :)
For example contents = new Button {} isn't working.
Sorry for this simple question I'm very new to Scala..
EDIT:
Thanks for the replies. My question now though becomes.. can you ever just have a class extending Panel? Would you be able to set contents for it at all? Or is it never done and everyone always just uses the Panels associated with a layout manager?
The Panel class itself is abstract, meaning it can't be instantiated directly, and is intended as a "base" for concrete implementations of panels.
It doesn't seem to have a "common" method for adding components probably because each subclass implements its own, sometimes mutually incompatible custom one:
BoxPanel, as you've noted, has a settable Buffer,
FlowPanel seems to mandate adding components as constructor arguments,
GridBagLayout and some others implement addition via the layout Map,
etc.
As you might see from the above examples, it would be hard to specify what a general "add" method would mean in all of those cases.
EDIT in response: of course you can, there's nothing stopping you from subclassing a Panel yourself and override the contents method, e.g.:
val myPanel = new Panel() {
private val myContents = (new Content += new Button())
override def contents = myContents
}
You can also use Panel as a type parameter for your methods that process panels in a general way, etc. It's just that you can't have an instance that's just a Panel, because, again, the class is abstract, so you can't instantiate it.
Note that this is not unique to Scala, if JPanel was abstract in Java (like Component is) the outcome would be the same.
I want to see how Scala code does it.
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Container.scala#L35
I, too, practiced on some Swing code when I first learned some Scala.
Here is a Panel component that renders itself as a simple game grid:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/LightBox.scala#L286
To see how the Scala and Swing pieces fit together, see SuperMixin:
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Component.scala#L51
Assembly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L18
This is what you asked about directly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L45
If you have a button:
val button=new Button{
text="Click me!"
}
or
val label=new Label{
text="Look, i'm a label!"
}
or
object myField extends TextField{ columns=2 }
then you just use:
contents=new BoxPanel(Orientation.Vertical){
contents+=button
border=Swing.EmptyBorder(10,20,10,20)
}
or in a more simpler form:
contents=new FlowPanel(){
contents+=new Label("This is my button:")
contents+=new Button("Click me!")
border=Swing.EmptyBorder(10,20,10,20)
}

Destroy data based on HTML class name in Rails

I'm building a simple todo list using Rails (3.2.5).
I show all of the users todo items in an unordered list, each list item being the todo itself. By clicking on the todo item the user marks it as completed. Using jQuery I give the li a class of done so I can change its styling. By clicking on a "Clear completed" button I want the completed items to be destroyed (and deleted from the database).
How can this be done?
NB: I'm basically trying to recreate this app using Rails: http://davidpdrsn.com/todos/
You can do it using a remote form
So you would have something like
you would have a form with remote: true for each item or you could have only one form and submit it with JQuery.
class TodoController
def set_completed
#todo = Todo.find(params[:id])
#todo.done = true # you could move this to your model and do something like #todo.done! and that would save it automatically
#todo.save
end
def destroy_completed
#todos_to_delete = Todo.where(done: true)# here you could also move it to your model and do it like Todo.completed
#todos_to_delete.destroy_all
end
end
and you would render the response with the js for formatting, or even removing items on your list, like
views/todo/set_completed.erb.js
$("#item_<%= #todo.id %>").addClass("completed");
Supposing the model is called Todo and the completed column is called completed, you can write one of these in the controller:
Todo.destroy_all(:completed => true)
Todo.where(:completed => true).destroy_all
If you need help with how to manage the ajax request/response, here there is a good start (sorry, I don't want to give you the solution, IMHO you should make your way by yourself)
Resources: ActiveRecord#Base::destroy_all

How to use a QGraphicsWebView?

I want to use a QGraphicWebView inside a delegate to render a QTableView cell, but I just don't know what to do with the QStyleOptionGraphicsItem parameter the paint() method requires. How to build it up / where should I retrieve it?
I'm using this code as reference, so the paint() method should be something like this:
def paint(self, painter, option, index):
web = QGraphicsWebView()
web.setHtml(some_html_text)
web.page().viewportSize().setWidth(option.rect.width())
painter.save()
painter.translate(option.rect.topLeft());
painter.setClipRect(option.rect.translated(-option.rect.topLeft()))
web.paint(painter, ??????) # what here?
painter.restore()
Any advice?
I'll assume that you don't really need QGraphicsWebView and that QWebView is sufficient.
It's important to keep in mind that you're not expected to call QWidget::paintEvent() yourself. Given that constraint, you'll want to use a helper class that can render on a paint device or render using a given painter. QWebFrame has one such method in the form of its render function. Based off of your linked-to example, the following should work:
class HTMLDelegate(QStyledItemDelegate):
def paint(self, painter, option, index):
model = index.model()
record = model.listdata[index.row()]
# don't instantiate every time, so move this out
# to the class level
web = QWebView()
web.setHtml(record)
web.page().viewportSize().setWidth(option.rect.width())
painter.save()
painter.translate(option.rect.topLeft());
painter.setClipRect(option.rect.translated(-option.rect.topLeft()))
web.page().mainFrame().render(painter)
painter.restore()