Is it possible to access a superclass's superclass in flex/as3? - apache-flex

I'm trying to override a subclass's method but I think I need access to the superclass one higher up in the hierarchy. So I'd like to do something like super.super.methodName();
FYI, the actual problem I'm trying to solve should be explained by my code below:
public class A extends UIComponent{
override protected function keyDownHandler(event:KeyboardEvent):void{
super.keyDownHandler(event);
if(event.keyCode==46)
remove();
}
}
public class B extends A{
override protected function keyDownHandler(event:KeyboardEvent):void{
if(event.keyCode==46 && removeable==true)
remove();
else
super.super.keyDownHandler(event);
}
}
If I use the class A's KeyDownHandler method, you will see that remove() is called regardless. However, the docs state that I need to call UIComponent.keyDownHandler whenever I subclass UIComponent. Of course this works for the first subclass, but not that subclass's subclasses.
I realise that I could put the functionality all into A with something like
if(this is B){...}
but that seems to me to be a hack.

You could add another method to class A, let's call it superKeyDownHandler whose only purpose would be to call some method from superclass.
protected function superKeyDownHandler(event:KeyboardEvent):void{
super.keyDownHandler(event);
}
And then what you want to achieve would be as easy as calling
super.superKeyDownHandler(event);
This is just a way around however not the actual clean solution, so use it at your own risk :)
UPDATE:
Something maybe cleaner would involve overriding keyDownHandler content of class A. So in class A you would have:
public class A{
override protected function keyDownHandler(event:KeyboardEvent):void{
super.keyDownHandler(event);
overridableContent();
}
protected function overridableContent(){
//do class A specific things here
if (event.keyCode==46)
remove();
}
}
public class B extends A{
override protected function overridableContent(){
//do class B specific things here
if (event.keyCode==46 && removeable==true)
remove();
}
}
Calling something like new B().keyDownHandler(event) now will cause calling keyDownHandler as it is defined in class A with content taken from class B.

What I gather from your question is that, you want to use the functionality given by the superclasses' superclass, and not by the superclass itself.
Am I right cammil?

Related

How can i implement Webdriver / PageObjects / Pagefactory in Java in a way that can be generally applied

Here is my attempted implementation understanding of PageObjects/Pagefactory as applied to Webdriver:
1. Create the following structure in eclipse
--> com.example.qa.pageobjects
--> LoginPage.java
Every class in this package has something like:
#FindBy(how = How.NAME, using = "logonName")
private WebElement logonNameField;
and the Methods, call Webelement, and call methods on them, like:
logonNameField.sendKeys("username");
Which are called from ScenrioTests.
--> HomePage.java (i go there after i login)
--> Page.java (abstract)
--> com.example.qa.setup
--> Browser.java
--> FirefoxBrowser.java (Code specific to FFox)
--> ChromeBrowser.java (Code Specific to Chrome)
--> com.example.qa.test
--> Scenario1234.java
--> Scenario2345.java
These Scenario Classes instantiate the PageObjects, and Call methods in them, while the Browser setup is only called Once per test run.
Now the question is:
Should i declare a method like below and call Pagefactory ?
public MyPage method() {
Call the Methods like Login() etc
return PageFactory.initElements(driver, MDNSLoginPage.class);
}
Or, Should i Call the same PageFactory from default Constructor
Is my understanding / implementation correct ?
I think I kind of follow your no 1 approach . I will try to answer by illustrating my implementation but I am not sure whether it would be useful for your purposes.
I have a baseTest class that I load with common methods that can be used across my test classes . (eg. instantiate browser, open login page etc)
abstract class TestBase {
//somewhere
protected static LoginPage goToLoginPage(){
driver.get(loginPage);
return PageFactory.initElements(driver, LoginPage.class);
}
protected static void startBrowser(Browser browser){}
//implemntation
}
Then, in my test classes that inherit the abstract class I use it in the following manner
#BeforeClass
public static void setup(){
//use a common method to start browser
startBrowser(Browser.FIREFOX);
}
#Test
public void canLogInToHomePage(){
//start my test like this
LoginPage loginPage =goToLoginPage();
}

Actionscript3 / LCCS: how to access property parent class protected var?

I would like to assign an event listener to a protected timer variable in the parent class.
I am working with Adobe LCCS, and created a BatonProperty
which implements Baton
Now, Baton has a protected timer variable declared like this, and for some reason, I am unable to get access to this _autoPutDownTimer, from a BatonProperty instance.
public function Baton()
{
super();
_autoPutDownTimer = new Timer(_timeout*1000, 1);
_autoPutDownTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);
invalidator.addEventListener(Invalidator.INVALIDATION_COMPLETE,commitP roperties);
}
I would love to attach an eventlistener to it like this, but it seems I cannot, any tips are truly appreciated:
public var mybatonprop:BatonProperty;
mybatonprop= new BatonProperty();
mybatonprop.sharedID = "myBaton";
mybatonprop.subscribe();
mybatonprop.baton._autoPutDownTimer.addEventListener(TimerEvent.TIMER,countDown);
This gives the error : "actionscript attempted access of inaccessible property through a reference with static type" But it seems that property is not private, only protected, since it is declared like this
/**
* #private
*/
protected var _autoPutDownTimer:Timer;
If BatonProperty extends Baton, then just change the line:
mybatonprop.baton._autoPutDownTimer.addEventListener(TimerEvent.TIMER,countDown);
to
mybatonprop._autoPutDownTimer.addEventListener(TimerEvent.TIMER,countDown);
otherwise, make _autoPutDownTimer public, or follow #Jacob's answer.
Or for a third suggestion, as Baton is an Adobe class and you can't edit it, create your own class MyBaton which extends Baton, then do either of the two suggestions. (MyBaton will work everywhere Baton does)
protected means private except to descendants of the class. i.e. classes that inherit from the parent. It looks like your BatonProperty uses Baton via composition, not inheritance. And, from what I can tell, it seems like you're trying to access the _autoPutDownTimer from Baton/BatonProperty via a third class.
My recommendation, though would not be to add the event listener directly to the timer, but to dispatch an event from Baton in the onTimerComplete function
protected function onTimerComplete(event:TimerEvent):void {
....
dispatchEvent(new Event('putDownComplete'));
}
and
mybatonprop.baton.addEventListener('putDownComplete', onPutdownComplete);

Flex watch bindable property other class

I'm creating an application using Flex 4.
When the app is started, it reads a XML file and populate objects. The .send() call is asynchronous, so I would want to listen/watch to this populated object, and when it has finished, dispatch an event for other classes, so they can use it.
package model{
public class LectureService extends HTTPService{
[Bindable]
private var _lecture:Lecture;
...
}
The xml is parsed correctly and loaded inside the object lecture of the class Lecture.
If I use the MXML notation in the main.mxml app, it works fine (the object is used when the it is populated after the async request):
<mx:Image id="currentSlide" source={lectureService.lecture.slides.getItemAt(0).path} />
BUT, I have another ActionScript class and I'm not able to listen to this dispatched (by [Bindable]) event.
package components{
public class LectureSlideDisplay extends Image
{
public function LectureSlideDisplay()
{
super();
this.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onChangeTest);
}
private function onChangeTest(e:PropertyChangeEvent):void {
trace('test');
}
I have already tried:
using (like above) addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, methodName).
tried to change the [Bindable] to [Bindalbe("nameEvent")] and listen for this, nothing.
using CreateWatcher method, doesn't work.
tried to have a look to the generated code of the class, but didn't help me
if (this.hasEventListener("propertyChange")){
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "lecture", oldValue, value));
}
How can I listen and have the populated object in another class?
Maybe the problem is that I'm listening from another class, but in this case how can I implement this?
It seems the event is dispatched, but I can't listen to it.
For who wants the answer, I have resolved changing the addEventListener object.
It is not right to use:
this.addEventListener(...)
Use instead:
lectureService.addEventListener(...)
I have changed my code to listen to this event in the main app MXML, and then inside the handler method, call the public method of your components to use the new data.
You can't solve all your problems by just extending the class. You should really look into Commands for your HTTP requests.
The change property event is used internally for watchers and won't dispatch in the overall component. What you want to do for your LectureSlideDisplay is to override the source setter. Every time it is called, a new value is being binded to it:
package components{
public class LectureSlideDisplay extends Image
{
override public function set source(value:Object):void
{
super.source = value;
// do whatever
}
public function LectureSlideDisplay()
{
super();
}
}
}
You should really read up on how Binding works.
Consider to use BindingUtils class. You can found documentation here. And a couple of usage samples: one, two.

Make File.nativePath bindable? or how to extend flash.filesystem.file

I would ultimately like to make .nativePath bindable or fire an event when it changes in Adobe Air. I figured I'd just extend the File class and be good.
But I cant find its source anywhere (so I know how to extend it). I've dug through http://opensource.adobe.com/svn/opensource/flex/sdk/ quite a bit and didnt see anything.
Is there a way to make .nativePath bindable or extend File?
alxx, your code was definitely close. Thank you - it gave me an idea on how to extend it. Working code:
public class FileEx extends File
{
public function FileEx(path:String=null)
{
super(path);
}
[Bindable("nativePathChanged")]
override public function get nativePath():String
{
return super.nativePath;
}
override public function set nativePath(value:String):void
{
super.nativePath=value;
dispatchEvent(new Event("nativePathChanged"));
}
}
The File Class is part of the Flash package, so it is not open source and you won't be able to get your hands on the code (unless you're deep in the inner circle of Adobe developers).
In theory you can extend the class, as it is not marked as final, and make the nativePath Bindable that way, but I'm not sure of the benefit. You'd have to expand on your use case to evaluate that.
You don't need source to subclass something. As long as it's not final, just extend it and override something you need:
public class BindableFile extends File {
[Bindable(event="nativePathChanged")]
override public function get nativePath():String {
return super.nativePath;
}
override public function set nativePath(value:String):void {
super.nativePath = value;
dispatchEvent("nativePathChanged");
}
}
Not tested, but looks realistic :)

When to use GWT ensureInjected()?

I created a few styles into a CSSResource and it works well whether I use
GWT.<MyResources>create(MyResources.class).myStyles().ensureInjected();
or not.
Could anyone shed a light on this and explain when to use ensureInjected or not?
Thank you!
Daniel
As Christian said, inside the UiBinder ui.xml file you don't have to worry about invoking ensureInjected(), the following XML statements do the job:
<ui:with field='myStyle' type='com...MyStyle'/>
<div class='{myStyle.redBorder}'/>
Of course this is assuming that there is somewhere a MyStyle interface defined:
public interface MyStyle {
public String redBorder();
}
Now I agree with you that things get annoying when you need to manipulate the CssResource extension outside of UiBinder templates. Precisely because you have to take care of invoking ensureInjected() somewhere before using the MyStyle instance with your widgets.
I personally use GIN to inject instances of extensions of CssResource whenever I need them.That way you can implement a custom GIN provider ensuring that ensureInjected() is called on the CssResource before injecting it.
There are three steps involved there:
Create an interface for MyStyle alongside with a CSS file.
MyStyle.java
public interface MyStyle {
public String redBorder();
}
MyStyle.css
.redBorder { border: 1px solid red; }
Expose it through a ClientBundle extension.
Resources.java
public interface Resources extends ClientBundle {
#Source("MyStyle.css")
public MyStyle style();
}
Configure a GIN provider method to inject your instances of MyStyle.
ClientModule.java
public class ClientModule extends AbstractGinModule {
#Override
protected void configure() {
//...
}
#Provides MyStyle createStyle(final Resources resources) {
MyStyle style = resources.style();
style.ensureInjected();
return style;
}
}
We smoothly inject the Resources instance here above, which means no more hassle of a static accessor calling GWT.<Resources>create(Resources.class) anywhere, it just all happens through the GIN injection.
Having done that you can inject your instances of MyStyle when you need them.
For example (in some MVP context):
private Widget widget;
#Inject
public SomeView(final MyStyle style) {
//...
widget = uiBinder.createAndBindUi(this);
widget.addStyleName(style.redBorder());
}
Good question - one situation that comes to my mind is when you want to use styles from some global stylesheet in a UiBinder template - then you need to call ensureInjected to... ensure the styles are indeed injected when you are referencing them (the "local" UiBinder styles, that you define in xml are automagically injected).
You can see this used as such in the Mail example:
public void onModuleLoad() {
// Inject global styles.
GWT.<GlobalResources>create(GlobalResources.class).css().ensureInjected();
// Create the UI defined in Mail.ui.xml.
DockLayoutPanel outer = binder.createAndBindUi(this);
// ...rest of the code
}
Note how ensureInjected is called before binding the UI.
This is the only situation I know that warrants using ensureInjected, but maybe I missed something.
The rule is easy: you have to call ensureInjected() explicitly, unless the CssResource is being generated from an <ui:style> in a UiBinder template (because most of the time you won't have a handle on the generated CssResource.
Specifically, <ui:with> provides no special treatment for CssResources.
Also, a few widgets take a specific ClientBundle as argument to a constructor (such as CellTable), they will then call ensureInjected() on the CssResource they use.
If you use UiBinder the call to ensureInjected is provided by the tag ui:with. For any other css you are using in a client bundle (i.e. legacy css excluded) and that are not declared in a ui:with block, you have to call ensureInjected explicitly.

Resources