I am stuck in getting an absolute position of DialogBox. I know it is the common problem (and strange workaround) for PopupPanel (which is parent to DialogBox) to set it, but what if I want to get it, what is the exact moment when the box attached to DOM? Neither overriding show nor onAttach nor show does not help:
class MyDialog extends DialogBox {
public MyDialog(. . .) {
ComplexPanel vert = new VerticalPanel();
vert.add("Test");
vert.add(new Button("Close", new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
MyDialog.this.hide();
}
}));
setWidget(vert);
this.addAttachHandler(new AttachEvent.Handler() {
#Override
public void onAttachOrDetach(AttachEvent event) {
if (event.isAttached()) Log.debug("attach:"+MyDialog.this.getAbsoluteLeft() +";"+
MyDialog.this.getAbsoluteTop());
}
});
}
#Override
protected void onLoad() {
super.onLoad();
Log.debug("load:"+this.getAbsoluteLeft() +";"+this.getAbsoluteTop());
}
#Override
public void show() {
super.show();
Log.debug("show:"+this.getAbsoluteLeft() +";"+this.getAbsoluteTop());
}
}
So when I call new MyDialog().show();, all this lines do log 0;0, however dialog is positioned in center of a page. But what I want is the sum of the chain of offsetParent positions. (And they are 0 in these moments even in JavaScript, if use JSNI to check this)
Again, setPopupPositionAndShow allows to set position but not get it :(
Finally, I've got this to work:
#Override
public void setPopupPosition(int left, int top) {
super.setPopupPosition(left, top);
if (this.isAttached()) Log.debug("setPos:"+this.getAbsoluteLeft() +";"+this.getAbsoluteTop());
}
It gets the proper position and I hope it is the right way to do it and setPopupPosition is called every time. You will even call it manually when using setPopupPositionAndShow.
I think it will be wise to let this question stay at SO "for future generations".
Upd. If you plan to call center(...) or some similar method of your dialog, be aware that setPopupPosition will be called twice or more times (may be first time with 0, 0), even if you'll check if it isAttached(). Add some additional check to ensure that positions are correct in current call.
Related
I'm currently recoding a TableViewer to work fully virtual. So far I'm pretty content with the results, but I still have a problem, that all visible elements in the table are refreshed on a fixed timer. The model changes continously though. This means, that if I click on an entry before a periodic update happens, the table loads in the actual value for that position, but leaves all other elements untouched. Since this is how the LazyContentProvider works that is set for the TableViewer this is not much of a problem.
Since my TableViewer is a Live-Viewer of incoming events, with the newest entry shifting all other items one down, I'd like to refresh all visible elements on adding a new event.
I've tried to use TableViewer.refresh() on adding a new item, but that does not seem to do anything.
Since the full code is pretty complex, and part of a bigger piece of code I'll provide a basic representation of the code:
public class MyClass{
public TableViewer liveViewer;
public List<String> myItems=new ArrayList<>();
void init(){
liveViewer = new TableViewer(liveComp, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
liveViewer.setContentProvider(new LiveViewerContentProvider(liveViewer));
liveViewer.setLabelProvider(someLabelProvider);
liveViewer.setUseHashlookup(true);
ClassThatProvidesItems.addListener(new ItemAddedListener(){
#Override
void itemAdded(String item){
myItems.add(0,item);
}
}
}
}
public class LiveViewerContentProvider implements ILazyContentProvider{
private TableViewer viewer;
private List<String> input;
public LiveViewerContentProvider(TableViewer viewer) {
this.viewer = viewer;
}
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.input = (List<String>) newInput;
}
#Override
public void updateElement(int index) {
viewer.replace(input.get(index), index);
}
}
I'm aware, that an ArrayList is probably not the best choice, for always adding an element at the head, but please ignore it for now. I've tried to perform a liveViewer.refresh(); at the end of the listener callback, but it didn't seem to refresh my elements. What could I do to force a refresh for all visible items on adding a new one?
Thanks in advance.
I've just noticed, that my solution was almost working. The problem was, that the whole code was somewhere within a weird try-catch-block that just silently swallowed Exceptions, and didn't give me the invalid-Thread-access exception that I should have gotten for not performing the liveViewer.refresh within the Display-Thread. Wrapping the line like this fixed the issue:
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
liveViewer.refresh();
}
});
I am calling java from java-script to close the date picker pop Up using following method.
private native void attachInternal() /*-{+
$wnd.jQuery("div.datePickerDay.datePickerDayIsValue").on( "Click", function() {
this.#com.booxi.admin.client.common.ui.text.DateFormatter::uiDatePickerPopup.hide();
console.log("OK");
});
}-*/;
this method is again called in the method attached.
The problem is that date picker doesn't closes after selecting same date which is already selected, but on value change it closes.I want to close it even after selecting same date as earlier.
The attach method is following
public void attach() {
attachInternal();
datePickerValueChangeRegistration = uiDatePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
#Override
public void onValueChange(ValueChangeEvent<Date> event) {
uiDatePickerPopup.hide();
uiTextDate.setErrorVisible(false);
uiTextDate.setTextNoFormat(Moment.moment(event.getValue()).format("L"));
}
});
textDateClickRegistration = uiTextDate.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
//if (uiTextDate.isReadOnly())
// return;
if (!uiTextDate.isEnabled())
return;
showPopup();
}
});
It's a bit late, but maybe it helps if anybody has the same problem.
I made the same error. The problem is, the change event only fires if a different value is selected. If the user selects the same value again, then there is no value change, the event does not fire, your code is not executed and the popup does not hide.
You have to use a click event instead of the value change event. Then by every click, even on the old value, the code is executed. But if you just replace the change event with the click event, then the code also is executed when the user clicks on the header of the date picker, for example when he clicks on the arrows to choose a different month. This would brake the functionality of the date picker.
So in the click event you have to check if the click is really in a date cell and not in the header. This can be done with Element.as(event.getNativeEvent().getEventTarget()) and check the element's content, easiest check if the inner text is a date number between 1 and 31.
So the code is like this
uiDatePickerPopup.addDomHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Element target = Element.as(event.getNativeEvent().getEventTarget());
String targetContent = target.getInnerText();
try {
int d = Integer.parseInt(targetContent);
if (d >= 1 && d <= 31) {
uiDatePickerPopup.hide();
...
enter the rest of your code here
...
}
} catch (Exception e) {
/* ignore, click was not on a date cell */
}
}
}, ClickEvent.getType());
(As far as I know there is no more elegant solution. The other possible events are not useful, and you can't restrict the click event only to the date cells, because the getView() method is protected and the underlying CalendarView is final and can't be extended to a subclass providing the necessary check for the content.)
Your JSNI is wrong: you're getting a method reference to the hide() method, but not actually calling it. Also, the this inside the callback is probably the HTML element, and not the class this method pertains to (and finally, click might have to be all lowercase –I don't know jQuery though, so I might be wrong).
It should thus read:
private native void attachInternal() /*-{
var that = this;
$wnd.jQuery("div.datePickerDay.datePickerDayIsValue").on( "click", function() {
that.#com.booxi.admin.client.common.ui.text.DateFormatter::uiDatePickerPopup.hide()();
console.log("OK");
});
}-*/;
I have this behavior added to a component(MarkupContainer)
AjaxSelfUpdatingTimerBehavior updateBehavior = new AjaxSelfUpdatingTimerBehavior(Duration.seconds(3))
{
#Override
public void onEvent(Component component, IEvent<?> event) {
// some business logic
}
};
Somewhere , on the same page I have an AjaxLink which redirects to another page(in whom constructor I pass the actual page as a parameter) and on that page I have a "Back" AjaxLink which redirects me back , calling setResponsePage(myFirstPage) .
The problem is that even though , when rendering the page the behavior updates once , it stops updating once at 3 seconds , as was constructed for.No problem faced with the behavior until leaving the page.
Probably not the best solution , but I managed to fix it by removing the behavior onBeforeRender() of the page and adding again . I declared a field on the page private int autoUpdateBehaviorId = -1;
public void addUpdateBehavior(Component c)
{
if(autoUpdateBehaviorId >= 0)
c.remove(c.getBehaviorById(autoUpdateBehaviorId));
AjaxSelfUpdatingTimerBehavior updateBehavior = new AjaxSelfUpdatingTimerBehavior(Duration.seconds(3))
{
#Override
public void onEvent(Component component, IEvent<?> event) {
// bussines logic
}
};
c.add(updateBehavior);
autoUpdateBehaviorId = c.getBehaviorId(updateBehavior);
}
#Override
protected void onBeforeRender() {
super.onBeforeRender();
addUpdateBehavior(myContainer);
}
Not necessarily the solution to your problem; but I have implemented the behavior by overriding onConfigure method of the AjaxSelfUpdatingTimerBehavior as below.
In my case, I had to update label with a count of current records in queue every 10 seconds.
Following is code snippet:
labelToBeUpdated.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(configurableDelay)) {
#Override
public void onConfigure(Component component) {
String inProgressOutOfTotal = "10/100"; //Business logic to get total count and inprogress count
labelToBeUpdated.setDefaultModel(Model.of(inProgressOutOfTotal));
//Set visibility of the component if needed
}
}
labelToBeUpdated.setOutputMarkupId(true);
Just curious; is it that onEvent is waiting on an event on the component in order to refresh? Since onConfigure is called before the rendering cycle has begun, it is working for me.
But as Sven Meier has mentioned, you might still want to work on his advise to get your code with onEvent.
I have a textbox and one suggestbox. I attach a value change and key up handler to the text box such that whatever the user types (or pastes) into the text box is echo-ed inside the suggestbox. I can get the suggestbox to display the suggestion list by calling showSuggestionList on each value change and key up event.
Now, how do I get the suggestbox to automatically choose the first item in the suggestion list?
One of the methods I tried is to programatically simulate key presses, i.e
suggestBox.setFocus(true);
NativeEvent enterEvent = Document.get().createKeyPressEvent(false, false, false, false, KeyCodes.KEY_ENTER);
DomEvent.fireNativeEvent(enterEvent, suggestBox);
textBox.setFocus(true);
This doesn't work at all. The enter key isn't simulated. Another possible solution is to extend SuggestionBox.SuggestionDisplay, but I'm not too sure how to that. Any pointers appreciated.
Update: I'm still working on this and trying various methods.
Here, I tried to implement my own SuggestionDisplay by subclassing DefaultSuggestionDisplay and overriding getCurrentSelection() to make accessible from my class. This doesn't work either. Null is returned.
private class CustomSuggestionDisplay extends DefaultSuggestionDisplay {
#Override
protected Suggestion getCurrentSelection() {
return super.getCurrentSelection();
}
}
suggestBox.setAutoSelectEnabled(true);
textBox.addKeyUpHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
suggestBox.setValue(textBox.getText(), true);
suggestBox.showSuggestionList();
if (suggestBox.isSuggestionListShowing()) {
String s = ((CustomSuggestionDisplay) suggestBox.getSuggestionDisplay()).getCurrentSelection().getDisplayString();
Window.alert(s);
}
}
});
Here, I tried to attach a value change handler to the SuggestBox, and casting the event type to SuggestOracle.Suggestion. Again, null is returned.
suggestBox.addValueChangeHandler(new ValueChangeHandler<String>() {
public void onValueChange(ValueChangeEvent<String> event) {
String s = ((SuggestOracle.Suggestion) event).getDisplayString();
Window.alert(s);
}
});
Use suggesBox.setAutoSelectEnabled(true)
Here more info about the SuggestBox of GWT:
You could try using addSelectionHandler in conjunction with setAutoSelectEnabled to receive an event whenever a suggestion is selected. You could also have your Oracle send a message when it suggests something, or your Display send a message when it displays a list:
public class AutomaticallySelectingSuggestionDisplay extends SuggestBox.DefaultSuggestionDisplay {
#Override
protected void showSuggestions(SuggestBox box, Collection<? extends SuggestOracle.Suggestion> suggestions, boolean isDisplayHtml, boolean isAutoSelectEnabled, SuggestBox.SuggestionCallback callback) {
super.showSuggestions(box, suggestions, isDisplayHtml, isAutoSelectEnabled, callback);
fireValueChangeEventWithFirstSuggestion(suggestions);
}
}
This idea feels a little muddled to me, so I hope you can find a solution just using event handlers.
I've got a gwt application and I want to scroll to the top of a page using this method:
public static native void scrollTop() /*-{
$wnd.scroll(0, 0);
}-*/;
The method is called in the onClick-method of a TreeNodeListenerAdapter:
new TreeNodeListenerAdapter() {
#Override
public void onClick(Node node, EventObject e) {
scrollTop();
}
}
This does not work and I don't know why. When I put an alert inside my method:
$wnd.alert("Treenode clicked");
I get to see the alert but the page is not scrolled. What am I missing here?
If you want to scroll to the top of a page just do:
Window.scrollTo (0 ,0);
Just be sure that you are importing the correct package com.google.gwt.user.client.Window