How to group gwt composite widgets change events as one change event - gwt

If i have a GWT composite widget with three text boxes like for SSN, and i need to fire change event only when focus is lost from the widget as a whole, not from individual text boxes how to go about doing that?

If you want just the event when your whole widget loses focus (not the text boxes), then make the top level of your widget be a FocusPanel, and expose the events that it gives you.

You need to implement the Observer Pattern on your composite, and trigger a new notification everytime:
the focus is lost on a specific text box AND
the focus was not transferred to any of the other text boxes.

Couldn't you use a timer? On lost focus from a text box, start a 5ms (or something small) timer that when it hits, will check focus on all 3 TextBox instances. If none have focus, then you manually notify your observers. If one has focus, do nothing.
Put this in your Composite class:
private Map<Widget, Boolean> m_hasFocus = new HashMap<Widget, Boolean>();
And then add this to each one of your TextBox instances:
new FocusListener() {
public void onFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.TRUE);
}
public void onLostFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.FALSE);
new Timer() {
public void run() {
for (Boolean bool : m_hasFocus.values()) {
if (bool) { return; }
}
notifyObservers();
}
};
}
};

Related

Is it possible/how to display a message on the FeedbackPanel more than one time

I have a org.apache.wicket.markup.html.panel.FeedbackPanel in my panelA class. The feedback panel is instantiated in a panelA constructor with one message to display -> feedbackPanel.info("displayFirstTime"). I am navigating to a new page and later to the previous panelA with a command
target.getPage().get(BasePage.CONTENT_PANEL_ID).replaceWith(panelA);
but the message "displayFirstTime" won't be displayed on the feedback panel again.
I have made it with overriding a panel onBeforeRender method
#Override
public void onBeforeRender() {
super.onBeforeRender();
if (again_displayCondition) {
this.info("displayFirstTime");
}
}
but it's not a clean solution.
Is it possible or how to make it, that when moving to a panelA page for the 2nd time the feedback message will be also displayed ?
Wicket uses application.getApplicationSettings().getFeedbackMessageCleanupFilter() to delete the feedback messages at the end of the request cycle.
By default it will delete all already rendered messages.
You can setup a custom cleanup filter that may leave some of the messages, e.g. if they implement some interface. For example:
component.info(new DoNotDeleteMe("The actual message here."));
and your filter will have to check:
#Override
public boolean accept(FeedbackMessage message)
{
if (message.getMessage() instanceOf DoNotDeleteMe) {
return false;
}
return message.isRendered();
}
Make sure you implement DoNotDeleteMe#toString() so that it renders properly. Or you will have to use a custom FeedbackPanel too.
DoNotDeleteMe must implement java.io.Serializable!

how to stop firing unrelated event of event bus

My problem is with how to stop firing unrelated event of event bus. as I got this solution for Dialog box.
but it does not work in case of where one instance already initialize and try to create new instance of same class.
Just example: A below scroll panel has handler initialized. it used for document preview.
class TestScroll extends ScrollPanel
{
public TestScroll(){
}
implemented onload()
{
// eventBus.addHandler code here.
//here some preview related code
}
unload() method
{
//eventBus remove handler code
}
}
This preview has some data which contains some links that open different preview but with same class and different data structure,
Now The problem is like onUnload ( which contains code of remove handler) event does not load , because other panel opened. that does not mean previous panel unload.
So in that case, twice event handler registered. when one event fired then other event also fired.
Due to that, Preview 1 data shows properly, but after that Preview2 opened and when I close it, I find Preview1=Preview2.
so how can I handle such situation?
As per no of instance created each event fired. but I have to check some unique document id with if condition in event itself.
is there any other ways to stop unrelated event firing?
Edit:
public class Gwteventbus implements EntryPoint {
int i=0;
#Override
public void onModuleLoad() {
TestApp panel=new TestApp();
Button button=new Button("Test Event");
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
TestApp panel=new TestApp();
int j=i;
new AppUtils().EVENT_BUS.fireEventFromSource(new AuthenticationEvent(),""+(j));
i++;
}
});
panel.add(button);
RootPanel.get().add(panel);
}
}
public class AppUtils {
public static EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);
}
public class TestApp extends VerticalPanel{
String testString="";
public TestApp( ) {
AppUtils.EVENT_BUS.addHandler(AuthenticationEvent.TYPE, new AuthenticationEventHandler() {
#Override
public void onAuthenticationChanged(AuthenticationEvent authenticationEvent) {
System.out.println("helloworld"+authenticationEvent.getSource());
}
});
}
}
These are wild guesses as it's difficult to really answer it without code and a clear description.
I'm guessing you have one eventbus for all the panels. So when you register a handler it is registered with that one eventbus. In case you fire an event from one of the panels to the eventbus all panels will receive the event.
To fix this you can either create a new eventbus per panel or check who fired the event with event.getSource().
If this doesn't make sense you probably are reusing a variable or use a static variable which actually should be a new instance or none static variable.
You can use the GwtEventService-Library to fire specific events over a unique domain and every receiver that is registered at this domain receives that events then. You can handle as many different events/domains as you want.
In order to remove a handler attached to the EventBus, you must first store a reference to the HandlerRegistration returned by the addHandler method:
HandlerRegistration hr = eventBus.addHandler(new ClickHandler(){...});
Then you can remove the handler with the removeHandler method:
hr.removeHandler();
A final note worth mentioning is that when using singleton views, like is typical with MVP and GWT Activities and Places, it is best practice to make use of a ResettableEventBus. The eventBus passed to an activity's start() is just such a bus. When the ActivityManager stops the activity, it automatically removes all handlers attached to the ResettableEventBus.
I would strongly recommend reading the GWT Project's documentation on:
Activities and Places
Large scale application development and MVP

GWT ListBox detect when value is re-selected

I'm having a problem using a GWT listbox. I have a case where the user selects a value from a listBox, but it can become invalidated if they change data in a related field. To validate the listBox, the user has to either select a new value, or confirm their old selection by selecting the same value again. I can't figure out how to determine if they have selected the same value so that I can restyle the listBox to look validated.
The valueChanged handler only detects if a new value is selected. The clickHandler and focusHandler fire too often because they fire when the user isn't selecting a value. Any ideas?
You can improve the clickHandler with something like this :
ignoreClick = true;
lastSelection = -1 ;
....
listBox.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
if (!ignoreClick) {
lastSelection = listBox.getSelectedIndex();
}
ignoreClick = !ignoreClick;
}
});
I tried it and the event was only fired if you selected an item. But you should rethink your user interface , like said above.

Add SuggestBox to CellTable as an editable cell

Is there any way to SuggestBox to CellTable? Maybe there is another solution then SuggestBox?
I need to get an editable cell with suggestion feature?
I'm using GWT 2.4.
I don't think you can add it directly in. Try using a ClickableTextCell as the cell for that column. Then code your ValueUpdater (which will be called when the cell is clicked) to open up a DialogBox. Put your SuggestBox, and other widgets (OK button, Cancel button, and such), inside that DialogBox. Initialize the SelectionBox with the current contents of the cell. The DialogBox will likely be a DialogBox subclass with extra state data you initialize with the object for that CellTable row as well as the field for that column, so that the OK action knows what field on what object to update with the new contents of the SuggestBox. Essentially it's a popup editor. Not ideal, because users will expect the editor to be embedded in the CellTable, but there are only a few cell editors available (EditTextCell, DatePickerCell, SelectionCell and CheckboxCell, and maybe another variant of text editing), but I've used this technique, and really, it's not too bad.
I ended up using FlexTable instead of CellTable. With FlexTable you may put any widget inside a table cell.
I needed this also and found a solution (under testing, but solong it is working):
I copied the Code from TextInputCell into a new Class SuggestBoxTextInputCell
public class SuggestBoxTextInputCell extends AbstractInputCell<String, SuggestBoxTextInputCell.ViewData> {
MySuggestBox suggestBox;
and added some lines to the onBrowserEvent method:
// Ignore events that don't target the input.
InputElement input = getInputElement(parent);
String eventType = event.getType();
if (BrowserEvents.FOCUS.equals(eventType)) {
TextBox textBox = new MyTextBox(input);
suggestBox = new MySuggestBox(getSuggestOracle(), textBox);
suggestBox.onAttach();
}
Element target = event.getEventTarget().cast();
The classes MySuggestBox and MyTextbox exist only to make the needed constructor and methods public:
private class MyTextBox extends TextBox {
public MyTextBox(Element element) {
super(element);
}
}
private class MySuggestBox extends SuggestBox {
public MySuggestBox(SuggestOracle suggestOracle, TextBox textBox) {
super(suggestOracle, textBox);
}
#Override
public void onAttach() {
super.onAttach();
}
}
getSuggestOracle() only delivers the needed SuggestOracle. Hope someone can use this solution.
I needed this as a solution so I play around with the solution provided by Ande Hofer.
The exact same issue met by Ankit Singla, when the suggestbox is working fine when I press "Enter" key, but not from the "Mouse Click".
I go on further and add-on this onto the solution.
if (BrowserEvents.FOCUS.equals(eventType)) {
...
...
suggestbox.addSelectionHandler(new SelectionHandler<Suggestion>() {
#Override
public void onSelection(SelectionEvent<Suggestion> event) {
Suggestion selectedSuggestion = event.getSelectedItem();
String selectedValue = selectedSuggestion.getReplacementString();
onSuggestSelected(input, selectedValue, valueUpdater);
}
});
suggestbox.onAttach();
}
and a private function
private void onSuggestSelected(Element input, String value,
ValueUpdater<String> valueUpdater) {
input.blur();
suggestbox.onDetach();
if (suggestbox.getSuggestionDisplay().isSuggestionListShowing()) {
((DefaultSuggestionDisplay) suggestbox.getSuggestionDisplay()).hideSuggestions();
}
valueUpdater.update(value);
}
So far so good.

GWT: handling more than one events on Label

I want handle events on a Label when user holds down some key (Ctrl) and then clicks the mouse button together (Ctrl + mouse click), like open some window etc...
How could i do that in GWT? Should i get add two handlers or can do it with one?
thank you.
al
In your click handler you can check if the Ctrl key is pressed when the event was fired, see example below. You also might want to check for the specific mouse button the user clicked on. I've also added that to the example:
yourLabel.addClickHandler(new ClickHandler() {
if(NativeEvent.BUTTON_LEFT == event.getNativeButton() &&
event.isControlKeyDown()) {
//do what you want
}
});
Or for older version of GWT instead of event.isControlKeyDown use event.getNativeEvent().getCtrlKey(), which returns a boolean value true if the control key is pressed when this event is fired.
Edit: this code is buggy, please look at Hilbrand's answer
To be honest, I don't think you can do it with 1 or 2 handlers. I think you would need 3 handler.
A KeyDownHandler that sets a boolean you can later read form the MouseDownHandler
A MouseDownHandler that does what you want
A KeyUpHandler that resets the value of the boolean in the KeyDownHandler
boolean ctrlPressed;
yourLabel.addDomHandler(new KeyDownHandler() {
public void onKeyDown(KeyDownEvent event) {
if(event.getAssociatedType().equals(KeyCodes.KEY_CTRL))
ctrlPressed=true;
}
}, KeyDownEvent.getType());
yourLabel.addDomHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
if(event.getAssociatedType().equals(KeyCodes.KEY_CTRL))
ctrlPressed=false;
}
}, KeyUpEvent.getType());
yourLabel.addClickHandler(new ClickHandler() {
if(ctrlPressed) {
//do what you want
}
});