In my code, MyTab extendes Tab and until version 8 existed the method setEventHandler (...);
As I am now using the javaFX 12 version, this method is private and I can not use it anymore.
I also do not have access to the variable eventHandlerManager of Tab.
How can I access this functionality in JavaFX 12?
Here is an example of the code.
public class MyTab extends Tab {
...
protected ObjectProperty<EventHandler<EventAction>> onEventDockRequest=null;
public void setOnEventDockRequest(EventHandler<EventAction> value) {
onEventDockRequestProperty().set(value);
}
public final ObjectProperty<EventHandler<EventAction>> onEventDockRequestProperty() {
if (onEventDockRequest == null) {
onEventDockRequest = new ObjectPropertyBase<EventHandler<EventAction>>() {
#Override protected void invalidated() {
setEventHandler(EventAction.DOCK_REQUEST, get()); // here error
}
#Override public Object getBean() {
return DTab.this;
}
#Override public String getName() {
return "onEventDockRequest";
}
};
}
return onEventDockRequest;
}
}
Related
I am new to unit test and I am trying to use robolectric to do the test for my android app, but I encountered some problems
DemoPresenterTest
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 23)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(DemoPresenterImpl_.class)
public class DemoPresenterTest {
#Rule
public MockitoRule rule = MockitoJUnit.rule();
private MockDemoNetworkService mMockDemoNetworkService;
private MockLceView mLceView;
private DemoPresenterImpl_ mPresenter;
#Before
public void setup() {
mMockDemoNetworkService = Mockito.mock(MockDemoNetworkService.class);
mLceView = Mockito.mock(MockLceView.class);
PowerMockito.mockStatic(DemoPresenterImpl_.class);
mPresenter = DemoPresenterImpl_.getInstance_(RuntimeEnvironment.application);
mPresenter.service = mMockDemoNetworkService;
mPresenter.view = mLceView;
}
#Test
public void testDownloadData() {
mPresenter.downloadData();
Mockito.verify(mLceView).onError(Mockito.anyInt());
}
}
DemoPresenterImpl
#EBean
public class DemoPresenterImpl implements DemoPresenter {
#Bean(DemoNetworkService.class)
DemoService service;
protected LceView<Demo> view;
/**
* download the data from server for the first time, data will be saved into the database
* and for the next time it will query the database instead
*/
#Override
#Background(delay = 1000)
public void downloadData() {
try {
List<Demo> result = service.getDemoList();
if (result != null) {
view.setData(result);
} // add else if the result is not return empty list but null
} catch (NetworkFailException e) {
view.onError(e.getResponse().getCode());
}
}
#Override
public void attach(LceView<Demo> view) {
this.view = view;
}
}
MockDemoNetworkService
public class MockDemoNetworkService implements DemoService {
#Override
public List<Demo> getDemoList() throws NetworkFailException {
NetworkFailResponse response = new NetworkFailResponse();
response.setCode(500);
throw new NetworkFailException(response);
}
#Override
public boolean setDemoList(List<Demo> demoList) {
return false;
}
}
When I run the test it returns "Cannot subclass final class class com.*.DemoPresenterImpl_", if I change to DemoPresenterImpl, the test can run but the mLceView never get called
Wanted but not invoked: mockLceView.onError();
-> at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:245)
Actually, there were zero interactions with this mock.
am I doing something wrong?
I think you can remove #PrepareForTest, because you are not mocking the presenter, you are actually testing it. Then you should use DemoPresenterImpl_, because it is containing the needed generated code.
I have a TreeTableView which allows multiselection. I got a ContextMenu for editing or deleting that selected items.
Delete and edit should only be enabled if there is at least one selection.
final BooleanBinding isTableSelectionEmpty = Bindings.isEmpty(this.table.getSelectionModel().getSelectedItems());
this.menuItemDelete.disableProperty().bind(isTableSelectionEmpty);
That is working as expected.
But now I have dependencies on different values of the selected rows. Like for example that the row is system-mandatory and should not be deleted.
I tried the following but it is not working
final BooleanBinding invalidSelection = Bindings.and(Bindings.isEmpty(tableSelection),
Bindings.isNotEmpty(tableSelection.filtered(item -> {
this.logger.trace("filtering :" + item);
return item.getValue().getSystemProperty().get();
})));
this.menuItemDelete.disableProperty().bind(invalidSelection);
Not even the debug-trace is printed and the value of the binding is always false (thus enabling the menu item). Now I am a bit lost. Where is my mistake?
FilteredList relies on a correct ListIterator, but currently there is a bug in the ListIterator the selectedItems list in MultipleSelectionModelBase. This prevents the filtering to properly work. To fix this you could create a ObservableList implementation delegating everything but the ListIterator creation to a source ObservableList. Most IDEs have a functionality to generate this kind of methods automatically, reducing the amount of work to a minimum (e.g.in NetBeans: Generate -> Delegate Method).
public class ObservableListIteratorFix<T> implements ObservableList<T> {
private final ObservableList<T> list;
public ObservableListIteratorFix(ObservableList<T> list) {
this.list = list;
}
#Override
public void addListener(ListChangeListener<? super T> listener) {
list.addListener(listener);
}
#Override
public void removeListener(ListChangeListener<? super T> listener) {
list.removeListener(listener);
}
#Override
public boolean addAll(T... elements) {
return list.addAll(elements);
}
...
private class CustomListIterator implements ListIterator<T> {
private final ListIterator<T> iterator;
private int index;
public CustomListIterator(int index) {
this.iterator = list.listIterator(index);
this.index = index;
}
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public T next() {
T t = iterator.next();
index++;
return t;
}
#Override
public boolean hasPrevious() {
return iterator.hasPrevious();
}
#Override
public T previous() {
T t = iterator.previous();
index--;
return t;
}
#Override
public int nextIndex() {
return index;
}
#Override
public int previousIndex() {
return index-1;
}
#Override
public void remove() {
iterator.remove();
}
#Override
public void set(T e) {
iterator.set(e);
}
#Override
public void add(T e) {
iterator.add(e);
}
#Override
public void forEachRemaining(Consumer<? super T> action) {
iterator.forEachRemaining(action);
}
}
#Override
public ListIterator<T> listIterator() {
return listIterator(0);
}
#Override
public ListIterator<T> listIterator(int index) {
return new CustomListIterator(index);
}
#Override
public FilteredList<T> filtered(Predicate<T> predicate) {
return new FilteredList<>(this, predicate);
}
...
This allows you to use the class as wrapper the selectedItems which should fix the filtering...
new ObservableListIteratorFix<>(tableSelection).filtered(...)
I am working in new Scout Neon and I am starting to get error :
Assertion error: Property 'modal' cannot be changed because Form is already showing
My forms has properties :
#Override
protected int getConfiguredModalityHint() {
return MODALITY_HINT_MODELESS;
}
#Override
protected int getConfiguredDisplayHint() {
return DISPLAY_HINT_VIEW;
}
#Override
protected String getConfiguredDisplayViewId() {
return VIEW_ID_CENTER;
}
What I did wrong?
EDIT : Marko
I add page in MyOutline witch extends from AbstractOutline
public class MyOutline extends AbstractOutline {
#Override
protected String getConfiguredTitle() {
return TEXTS.get("MyOutline");
}
#Override
protected void execCreateChildPages(final List<IPage<?>> pageList) {
final MyPage myPage = new MyPage();
pageList.add(myPage);
super.execCreateChildPages(pageList);
}
}
MyPage is only a wrapper page for form.
public class MyPage extends AbstractPageWithNodes {
#Override
protected boolean getConfiguredLeaf() {
return true;
}
#Override
protected boolean getConfiguredTableVisible() {
return false;
}
#Override
protected String getConfiguredTitle() {
return TEXTS.get("MyPage");
}
#Override
protected Class<? extends IForm> getConfiguredDetailForm() {
return MyForm.class;
}
}
and my form is nothing spacial :
#FormData(value = MyFormData.class, sdkCommand = FormData.SdkCommand.CREATE)
public class MyForm extends AbstractForm {
/**
* Method start Form for adding new person.
*/
public void startNew() {
this.startInternal(new NewHandler());
}
#Override
protected boolean getConfiguredAskIfNeedSave() {
return false;
}
#Override
protected int getConfiguredModalityHint() {
return MODALITY_HINT_MODELESS;
}
#Override
protected int getConfiguredDisplayHint() {
return DISPLAY_HINT_VIEW;
}
#Override
protected String getConfiguredDisplayViewId() {
return VIEW_ID_CENTER;
}
public MainBox getMainBox() {
...
But when I want to open this Page (on start application is not opened on this page), (and I do not do anything else before) I get error.
2016-01-22 11:13:56,236 ERROR scout-model-thread-11 'Processing JSON request' o.e.scout.rt.platform.exception.ExceptionHandler -
org.eclipse.scout.rt.platform.util.Assertions$AssertionException: Assertion error: Property 'modal' cannot be changed because Form is already showing
at org.eclipse.scout.rt.platform.util.Assertions.fail(Assertions.java:581) ~[org.eclipse.scout.rt.platform-5.2.0.M4.jar:5.2.0.M4]
at org.eclipse.scout.rt.platform.util.Assertions.assertFalse(Assertions.java:192) ~[org.eclipse.scout.rt.platform-5.2.0.M4.jar:5.2.0.M4]
at org.eclipse.scout.rt.client.ui.form.AbstractForm.setModal(AbstractForm.java:2700) ~[org.eclipse.scout.rt.client-5.2.0.M4.jar:5.2.0.M4]
at org.eclipse.scout.rt.client.ui.desktop.outline.pages.AbstractPage.decorateDetailForm(AbstractPage.java:692) ~[org.eclipse.scout.rt.client-5.2.0.M4.jar:5.2.0.M4]
I found solution for my problem.
in my constructor in form I have :
public PersonsExtensionFieldForm() {
this.startInternal(new NewHandler());
}
witch is ok, when you open form from other form with for example button click.
But when you put form in page as Detail form you need to have
public PersonsExtensionFieldForm() {
this.setHandler(new NewHandler());
}
I have created a custom ObservableList implementation for a list of TreeItems. My custom implementation can listen to various notifications from inside my app (using OSGi EventAdmin), and update itself accordingly. I then expect its consumer (a TreeView widget) to be updated with the changes to the list. However, I can't see how to notify the consumer.
In the ObservableList subclass I am implementing addListener(ListChangeListener), which I would expect to get called when the object is added to the widget. However it is never called; I have no listeners thus no apparent way to notify anyone when the list changes. I must be missing something.
Here is a snippet from my TreeItem implementation, which returns an instance of my ObservableList in response to a getChildren call:
#Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = new MyObservableList();
}
return children;
}
Here is an abridged version of my custom ObservableList implementation, which simply wraps an FXCollections.observableArrayList and adds an OSGi event handler. I listen to changes on the internal list so that I can pass those changes on to my listeners.
public class MyObservableList implements ObservableList<TreeItem<DataObject>>, EventHandler {
private List<ListChangeListener<? super TreeItem<DataObject>>> changeListeners = new ArrayList<>();
private List<InvalidationListener> invalidationListeners = new ArrayList<>();
private ObservableList<TreeItem<DataObject>> theList;
private int size;
public MyObservableList() {
theList = FXCollections.observableArrayList();
theList.addListener(new ListChangeListener<TreeItem<DataObject>>() {
#Override
public void onChanged(Change<? extends TreeItem<DataObject>> change) {
fireValueChangedEvent(change);
}
});
}
#Override
public int size() {
return theList.size();
}
#Override
public boolean isEmpty() {
return (size == 0);
}
#Override
public boolean contains(Object o) {
return theList.contains(o);
}
#Override
public Iterator iterator() {
return theList.iterator();
}
#Override
public boolean remove(Object o) {
return theList.remove(o);
}
#Override
public boolean addAll(Collection c) {
return theList.addAll(c);
}
#Override
public boolean addAll(int index, Collection c) {
return theList.addAll(index, c);
}
#Override
public void clear() {
theList.clear();
}
#Override
public TreeItem<DataObject> get(int index) {
return theList.get(index);
}
#Override
public int indexOf(Object o) {
return theList.indexOf(o);
}
#Override
public int lastIndexOf(Object o) {
return theList.lastIndexOf(o);
}
#Override
public ListIterator listIterator() {
return theList.listIterator();
}
#Override
public ListIterator listIterator(int index) {
return theList.listIterator(index);
}
#Override
public List<TreeItem<DataObject>> subList(int fromIndex, int toIndex) {
return theList.subList(fromIndex, toIndex);
}
#Override
public Object[] toArray(Object[] a) {
return theList.toArray(a);
}
#Override
public void addListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.add(listChangeListener);
}
#Override
public void removeListener(ListChangeListener<? super TreeItem<DataObject>> listChangeListener) {
changeListeners.remove(listChangeListener);
}
#Override
public boolean addAll(TreeItem<DataObject>... treeItems) {
return theList.addAll(treeItems);
}
#Override
public boolean setAll(TreeItem<DataObject>... treeItems) {
return theList.setAll(treeItems);
}
#Override
public boolean setAll(Collection<? extends TreeItem<DataObject>> treeItems) {
return theList.setAll(treeItems);
}
#Override
public boolean removeAll(TreeItem<DataObject>... treeItems) {
return theList.removeAll(treeItems);
}
#Override
public boolean retainAll(TreeItem<DataObject>... treeItems) {
return theList.retainAll(treeItems);
}
#Override
public void remove(int i, int i2) {
theList.remove(i, i2);
}
#Override
public Object[] toArray() {
return theList.toArray();
}
#Override
public boolean add(TreeItem<DataObject> dataObjectTreeItem) {
return theList.add(dataObjectTreeItem);
}
#Override
public boolean containsAll(Collection<?> c) {
return theList.containsAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return theList.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return theList.retainAll(c);
}
#Override
public TreeItem<DataObject> set(int index, TreeItem<DataObject> element) {
return theList.set(index, element);
}
#Override
public void add(int index, TreeItem<DataObject> element) {
theList.add(index, element);
}
#Override
public TreeItem<DataObject> remove(int index) {
return theList.remove(index);
}
#Override
public void addListener(InvalidationListener invalidationListener) {
invalidationListeners.add(invalidationListener);
}
#Override
public void removeListener(InvalidationListener invalidationListener) {
invalidationListeners.remove(invalidationListener);
}
private void fireValueChangedEvent(ListChangeListener.Change<? extends TreeItem<DataObject>> change) {
for (ListChangeListener<? super TreeItem<DataObject>> listener : changeListeners) {
listener.onChanged(change);
}
}
#Override
public void handleEvent(Event event) {
// Here I add or remove TreeItem<DataObject> instances to the list based on event.
//
// At this point, onChanged() gets called above in my listener, but my changeListeners list is empty. There is
// no one to pass the Change on to.
}
}
Thanks for any help.
I figured out what's going on here after looking through the JavaFX source.
It turns out that the listening on the ObservableList of children is all set up in the TreeItem itself, not the TreeView as I had somehow assumed. This means that any subclass of TreeView that overrides getChildren() must call super.getChildren() and add its children to the resulting list. This means that using a custom ObservableList implementation is not possible as TreeItem is hardcoded to use FXCollections.observableArrayList() to create the list.
I am taking a different approach to this now where I call super.getChildren(), add my children, and then instantiate another object that holds a reference to that list and does all of my app's event handling business, operating on the list as needed. So my getChildren() method looks something like this now.
private MyEventHandler eventHandler;
private ObservableList<TreeItem<DataObject>> children;
#Override
public ObservableList<TreeItem<DataObject>> getChildren() {
if (needChildren) {
needChildren = false;
children = super.getChildren();
eventHandler = new MyEventHandler(children); // handles app events
}
return children;
}
I have built a custom component button, but somehow the action is not invoked. When debugging the getAction-Method within the component and invoking the supplied MethodeExpression the Bean-Method is called as expected. But due to some reason, the Expression is not invoked when pressing the button in the browser.
Is there some kind of additional Interface necessary to pass the action to the embedded button-component?
Any help is very appreciated since I am stuck at this issue for some days now
MyClass:
public class MyClass extends UIPanel implements SystemEventListener
{
private UIForm form;
private HtmlCommandButton buttonOk;
public MyClass()
{
FacesContext context = getFacesContext();
UIViewRoot root = context.getViewRoot();
root.subscribeToViewEvent(PostAddToViewEvent.class, this);
}
#Override
public void processEvent(SystemEvent event)
{
this.form = new UIForm();
this.buttonOk = new HtmlCommandButton();
this.buttonOk.setId("okButtonId");
this.buttonOk.setActionExpression(getAction());
this.buttonOk.setValue("OK");
this.form.getChildren().add(this.buttonOk);
getChildren().add(this.form);
}
private enum PropertyKeys
{
action, text, titel
}
public MethodExpression getAction()
{
return (MethodExpression) getStateHelper().eval(PropertyKeys.action);
}
public void setAction(MethodExpression actionExpression)
{
getStateHelper().put(PropertyKeys.action, actionExpression);
}
public String getText()
{
return (String) getStateHelper().eval(PropertyKeys.text);
}
public void setText(String text)
{
getStateHelper().put(PropertyKeys.text, text);
}
public String getTitel()
{
return (String) getStateHelper().eval(PropertyKeys.titel);
}
public void setTitel(String titel)
{
getStateHelper().put(PropertyKeys.titel, titel);
}
#Override
public void encodeAll(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
writer.startElement(HTML.DIV_ELEM, this);
writer.writeText(getText(), null);
this.form.encodeAll(context);
writer.endElement(HTML.DIV_ELEM);
}
#Override
public void encodeChildren(FacesContext context) throws IOException
{
}
#Override
public boolean isListenerForSource(Object source)
{
return (source instanceof MyClass);
}
}
MyClassHandler:
public class MyClassHandler extends ComponentHandler
{
public MyClassHandler(ComponentConfig config)
{
super(config);
}
#SuppressWarnings("rawtypes")
#Override
protected MetaRuleset createMetaRuleset(Class type)
{
return super.createMetaRuleset(type).addRule(new MethodRule("action", String.class, new Class[] { ActionEvent.class }));
}
}
myView Method:
...
public String myMethod()
{
System.err.println("myMethod");
return "/some/path/yadayada.xhtml";
}
...
MyView.xhtml
<myTag action="#{myView.myMethod}" id="id1" titel="bla" text="bleh" />
Exdending UICommand is enough, since you only want one action to be executed.
You have to provide two additional MethodExpressions via the tag-attributes and within the decode-method you can check which button has been pressed and redirect the particular MethodExpression to the standard-action provided by UICommand. This way, you dont have to worry about the legacy-interface ActionSource, or how Events are broadcasted.
public void decode(FacesContext contex)
{
Map<String,String> map = context.getExternalContext.getRequestParameterMap();
// your rendered buttons need a name you check for
final boolean okPressed = map.containsKey( getClientId + ":ok" );
final boolean cancelPressed = map.containsKey( getClientId + ":cancel" );
if(okPressed || cancelPressed)
{
MethodExpression exp = null;
if(okPressed)
{
exp = getActionOk();
}
else
{
exp = getActionCancel();
}
// redirect to standard action
setActionExpression(exp);
queueEvent(new ActionEvent(this));
}
}
In order to make use of of this you need two attributes (actionOk and actionCancel) which use Method Expressions (setter and getter). Those have to be configured by a ComponentHandler as you did for the action-attribute.