GWT is making an unexpected event call - gwt

My code is below: I am seeing that on running the app the loadWidget method gets invoked even when the adminLink is not clicked. This is not want I want, but I'm not sure what is causing the issue. Please advise
public class LoginModule implements EntryPoint {
LoginPopup loginPopup;
private class LoginPopup extends PopupPanel {
public LoginPopup() {
super(true);
}
public void loadWidget(){
System.out.println("I am called 1");
CommonUi cUi = new CommonUi();
//#342 moved code to common area
FormPanel loginForm = cUi.getLoginFormUi();
setWidget(loginForm);
}
}
#Override
public void onModuleLoad() {
//#251 improved login popup ui.
final Anchor adminLink = new Anchor("User Login");
// final Label adminLink = new Label("User Login");
adminLink.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
loginPopup = new LoginPopup();
loginPopup.loadWidget();
loginPopup.showRelativeTo(adminLink);
loginPopup.show();
}
});
if(RootPanel.get("admin") !=null)
RootPanel.get("admin").add(adminLink);
}
}

Running Dev Mode, set a breakpoint in that method in your Java IDE, and take a look at the current stack, what code is calling that method. If that is the only code in your app, then this only appears to be invokable from that onClick handlers, so it is a matter of figuring out why that is being invoked.

Related

Pushing data from one user to another in Vaadin web app

I get the fact that it might take more than 10 lines of code (hopefully not more than 50), but I was wondering if you could help me anyway.
I'm trying to update one user's UI thread at runtime, based on another user's input. I've created a basic project which implements three predefined users (jim, tom and threeskin). I'd like to send a message from jim to tom and have it appear as a new Label object in tom's UI, without threeskin ever knowing about it, even though they're all logged in. Oh, and jim shouldn't have to refresh his page. The label should just spawn on screen out of it's own accord.
To say that I'd appreciate some help would be the understatement of the decade.
public class User {
public String nume;
public User(String nume) {
super();
this.nume = nume;
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public class Engine implements ServletContextListener {
public static ArrayList<User>userbase;
public void contextDestroyed(ServletContextEvent arg0) { }
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("This code is running at startup");
userbase =new ArrayList<User>();
userbase.add(new User("jim"));userbase.add(new User("tom"));userbase.add(new User("threeskin"));
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public class InfigeUI extends UI {
User us3r;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = InfigeUI.class)
public static class Servlet extends VaadinServlet {}
protected void init(VaadinRequest request) {
VerticalLayout everything=new VerticalLayout();
setContent(everything);
if (us3r==null){everything.addComponent(auth());}else{everything.addComponent(main());}
}
ComponentContainer auth(){
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
TextField userField=new TextField();
Button login = new Button("Log in");
login.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
us3r=login(userField.getValue());
if (us3r!=null){
saveValue(InfigeUI.this, us3r);
layout.removeAllComponents();
layout.addComponent(main());
}else{Notification.show("I only know jim, tom and threeskin. Which one are you?");}}
});
layout.addComponent(userField);
layout.addComponent(login);
return layout;
}
User login(String nume){
for (int i=0;i<Engine.userbase.size();i++){
if (nume.equals(Engine.userbase.get(i).nume)){return Engine.userbase.get(i);}
}
return null;
}
static void saveValue(InfigeUI ui,User value){
ui.us3r=value;
ui.getSession().setAttribute("something", value);
VaadinService.getCurrentRequest().getWrappedSession().setAttribute("something", value);
}
ComponentContainer main(){
VerticalLayout vl=new VerticalLayout();
Label label=new Label("This is the post-login screen");
String name=new String(us3r.nume);
Label eticheta=new Label(name);
TextField to=new TextField("Send to");
TextField message=new TextField("Message");
Button sendNow=new Button("Send now!");
vl.addComponent(eticheta);
vl.addComponent(label);
vl.addComponent(eticheta);
vl.addComponent(to);
vl.addComponent(message);
vl.addComponent(sendNow);
return vl ;
}
}
Basically you want three things
UI updates for a user which does no action himself, or in other words a message sent from the server to the browser. To enable this, you need to annotate the UI class using #Push. Otherwise, the update will only be shown when the user does something which causes a server visit, e.g. clicks a button
Some way of sending messages between UI instances (there is one UI instance per user). You can use some message bus implementation for this (CDI, Spring, ...) or you can make a simple on using a static field (static fields are shared between all users). See e.g. https://github.com/Artur-/SimpleChat for one way of doing it. It's also a good idea here to avoid all *.getCurrent methods as they in many cases will refer to another UI than you think (e.g. sender when you are in the receiver code), and you will do something else than you intend.
Safely update a UI when a message arrives. This is done using UI.access, also visible in the chat example.
First of all you need to enable the server push on your project help
based on Vaadin Documentation.
However, below code example will give what you want:
Create an Broadcast Listener Interface:
public interface BroadcastListener {
public void receiveBroadcast(final String message);
}
The Broadcaster Class:
public class Broadcaster {
private static final List<BroadcastListener> listeners = new CopyOnWriteArrayList<BroadcastListener>();
public static void register(BroadcastListener listener) {
listeners.add(listener);
}
public static void unregister(BroadcastListener listener) {
listeners.remove(listener);
}
public static void broadcast(final String message) {
for (BroadcastListener listener : listeners) {
listener.receiveBroadcast(message);
}
}
}
Your UI with Push Enalbed (via Annotation):
#Push
public class BroadcasterUI extends UI implements BroadcastListener {
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
final TextArea message = new TextArea("",
"The system is going down for maintenance in 10 minutes");
layout.addComponent(message);
final Button button = new Button("Broadcast");
layout.addComponent(button);
button.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Broadcaster.broadcast(message.getValue());
}
});
// Register broadcast listener
Broadcaster.register(this);
}
#Override
public void detach() {
Broadcaster.unregister(this);
super.detach();
}
#Override
public void receiveBroadcast(final String message) {
access(new Runnable() {
#Override
public void run() {
Notification n = new Notification("Message received",
message, Type.TRAY_NOTIFICATION);
n.show(getPage());
}
});
}
you can find the full link here.

Close Eclipse ViewPart tab when createPartControl function fails when launched from "Quick Access"?

The default behaviour when creating a new Eclipse ViewPart is to show the new tab regardless of what happens in the createPartControl function. For example, if didn't create anything, no widgets, nothing, a blank tab will be shown. I don't like this behaviour. I want to close that tab if initialization in createPartControl fails.
Now, I have a mouse-button-context-menu handler that can do this, e.g.
public class MyPartMB3Handler extends AbstractHandler {
#Override
public Object execute(final ExecutionEvent event)
throws ExecutionException {
// Create a view and show it.
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
IWorkbenchPage page = window.getActivePage();
try {
MyPart viewPart = (MyPart)page.showView(MyPart.ID);
if(!viewPart.isCreated()) {
page.hideView(viewPart);
}
}
catch(PartInitException e) {
e.printStackTrace();
}
return null;
}
}
The isCreated function is a little hack that lets me know if my ViewPart initialization fails, e.g.
public class MyPart extends ViewPart {
public static final String ID = "com.myplugin.MyPart";
private Composite _parent = null;
#Override
public void createPartControl(Composite parent) {
if(!MyPlugin.createPartControl(parent) { // Some common part creation code I use.
//PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().hideView(this);
return;
}
_parent = parent;
}
#Override
public void setFocus() {
}
public boolean isCreated() {
return _parent != null;
}
}
The problem arises when I launch this ViewPart from the Eclipse "Quick Access" field. I don't own the handler now. From an exception I forced, the handler might be org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.createPartControl or org.eclipse.ui.internal.e4.compatibility.CompatibilityView.createPartControl or org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.create.
I tried hiding the view inside the createPartControl function (see the commented line above), but Eclipse did not like that and spewed a pile of exceptions.
I thought maybe I could throw a PartInitException in createPartControl, but Eclipse tells me I'm not allowed to do that.
So, how do I get my menu handler behaviour when launching from "Quick Access"?
An underlying question might be, is there a better/proper way to achieve this behaviour?
You can close the view by running the hideView asynchronously after the createPartControl has finished - like this:
#Override
public void createPartControl(Composite parent) {
parent.getDisplay().asyncExec(new Runnable() {
#Override
public void run()
{
getSite().getPage().hideView(MyPart.this);
}
});

GWT - Reference to a global variable set by callback method

Please help me, as I will go mad with this soon:
When I run the code, on first occasion loadNewPoint() is executed and displays some data from global variable - allPointsAndPlaces
However when I click a button (from a child class), the same method loadNewPoint() gives me null pointer for allPointsAndPlaces.
I have changed the code structure a lot from an original trying to solve this issue, and moved this method (loadNewPoint()) to a parent class to see, if it would solve the issue.
Parent class:
public class CabbieApp implements EntryPoint {
private GetLocationsServiceAsync getAllLocationsService = GWT.create(GetLocationsService.class);
CabbiePoint[] allPointsAndPlaces;
PointsQuiz quiz;
/**
* Entry point method.
*/
public void onModuleLoad() {
//Get all the required data from DB
getAllPointsAndLocations();
}
private void loadAppPages(){
// Associate the Main panel with the HTML host page.
RootPanel rootPanel = RootPanel.get("pointsList");
quiz = new PointsQuiz();
rootPanel.setStyleName("GWTapp");
rootPanel.add(quiz.getMainPanel());
loadNewPoint();
}
private void getAllPointsAndLocations() {
// Initialize the service proxy.
if (getAllLocationsService == null) {
getAllLocationsService = GWT.create(GetLocationsService.class);
}
// Set up the callback object.
AsyncCallback<CabbiePoint[]> callback = new AsyncCallback<CabbiePoint[]>() {
public void onFailure(Throwable caught) {
System.out.println(caught.getMessage());
}
public void onSuccess(CabbiePoint[] result) {
//allPointsAndPlaces = result;
System.out.println(result.length);
allPointsAndPlaces = result;
loadAppPages();
}
};
// Make the call to the service.
getAllLocationsService.getLocations(callback);
}
void loadNewPoint(){
int r = Random.nextInt(allPointsAndPlaces.length);
quiz.CurrentPlace = allPointsAndPlaces[r].getPlaceName();
quiz.CurrentLocation = allPointsAndPlaces[r].getPlaceLocation();
quiz.point.setText(quiz.CurrentPlace);
quiz.location.setText(quiz.CurrentLocation);
quiz.location.setStyleName("invisibleText");
}
}
Child class:
public class PointsQuiz extends CabbieApp{
VerticalPanel mainPanel = new VerticalPanel();
HorizontalPanel navigation = new HorizontalPanel();
TextBox point = new TextBox();
TextBox location = new TextBox();
Button showLocation = new Button("Show Location");
Button nextPoint = new Button("Next Point");
String CurrentPlace, CurrentLocation;
public PointsQuiz() {
// Assemble Add Stock panel.
navigation.add(showLocation);
navigation.add(nextPoint);
navigation.setCellHorizontalAlignment(nextPoint, HasHorizontalAlignment.ALIGN_RIGHT);
navigation.addStyleName("addPanel");
mainPanel.setSpacing(5);
mainPanel.setStyleName("body");
mainPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
mainPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
// Assemble Main panel.
mainPanel.add(point);
point.setWidth("200px");
mainPanel.add(location);
location.setWidth("200px");
mainPanel.add(navigation);
navigation.setWidth("200px");
// Move cursor focus to the input box.
showLocation.setFocus(true);
// Listen for mouse events on the show location button.
showLocation.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
showCurrentLocation();}
});
// Listen for mouse events on the next point button.
nextPoint.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
loadNewPoint();
}
});
}
private void showCurrentLocation(){
location.setStyleName("visibleText");
}
public VerticalPanel getMainPanel() {
return mainPanel;
}
}
I managed to find a solution to this problem with Bhumika's help.
To make this work I had to change CabbiePoint[] allPointsAndPlaces to static.
This would solve the reference problem one way - from child to parent.
Also I managed to find out trough debugging, that this reference
quiz = new PointsQuiz();
is also null on a second run of loadNewPoint(). So this child reference (PointsQuiz quiz;) and any other references to children were set also to static.
You are getting null pointer error because of allPointsAndPlaces is null. As per your coding The value of allPointsAndPlaces is assigned after completion of RPC call in getAllPointsAndLocations() method. so the allPointsAndPlaces has some assigned values.
Here you try to directly access loadNewPoint() method in child class. At a time, allPointsAndPlaces is not assigned.

DialogBox in GWT isn't draggable or centred

I'm new to GWT programming. So far I have a DialogBox which is supposed to collect a login and a password, which can if required launch another DialogBox that allows someone to create a new account.
The first of these two DialogBoxes always appears at the top left of the browser screen, and can't be dragged, although part of the definition of a DialogBox is that it can be dragged. However, the second DialogBox can be dragged about the screen without any problem.
What I'd really like is for the first DialogBox to appear in the middle of the screen & be draggable, both of which I thought would happen automatically, but there's not.
So, what things can stop a DialogBox from being draggable? There is nothing on the RootPanel yet. Does that make a difference?
Code fragments available if they help, but perhaps this general outline is enough for some pointers.
Thanks
Neil
Use dialogBox.center() This will center your DialogBox in the middle of the screen. Normally a DialogBox is by default draggable.
Just tried it out and it doens't matter if your RootPanel is empty our not. When I just show the DialogBox on ModuleLoad it is draggable and it is centered. Probably the problem is situated somewhere else.
This is the example of google itself:
public class DialogBoxExample implements EntryPoint, ClickListener {
private static class MyDialog extends DialogBox {
public MyDialog() {
// Set the dialog box's caption.
setText("My First Dialog");
// DialogBox is a SimplePanel, so you have to set its widget property to
// whatever you want its contents to be.
Button ok = new Button("OK");
ok.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
MyDialog.this.hide();
}
});
setWidget(ok);
}
}
public void onModuleLoad() {
Button b = new Button("Click me");
b.addClickListener(this);
RootPanel.get().add(b);
}
public void onClick(Widget sender) {
// Instantiate the dialog box and show it.
new MyDialog().show();
}
}
Here more information about the DialogBox.
Without seeing any of your code it's hard to tell what's going wrong. The following code works for me (ignore the missing styling...):
public void onModuleLoad() {
FlowPanel login = new FlowPanel();
Button create = new Button("create");
login.add(new TextBox());
login.add(new TextBox());
login.add(create);
create.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
final DialogBox box = new DialogBox();
FlowPanel panel = new FlowPanel();
Button close = new Button("close");
close.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
box.hide();
}
});
panel.add(new Label("some content"));
panel.add(close);
box.setWidget(panel);
box.center();
}
});
DialogBox firstBox = new DialogBox(false, true);
firstBox.setWidget(login);
firstBox.center();
}
Both boxes are draggable and shown in the center of your browser window.
Looks like you're overriding this method in Widget:
public void fireEvent(GwtEvent<?> event) {
if (handlerManager != null) {
handlerManager.fireEvent(event);
}
}
In Widget, handlerManager refers to a private HandlerManager.
Either add super.fireEvent(event) to your method or as you have done rename it.
Well, with vast amounts of trial and error I have found the problem, which was just this: I had a method in an object I'd based on DialogBox called fireEvent, which looked like this:
public void fireEvent(GwtEvent<?> event)
{
handlerManager.fireEvent(event);
}
Then, when a button was clicked on the DialogBox, an event would be created and sent off to the handlerManager to be fired properly.
And it turns out that if I change it to this (LoginEvent is a custom-built event):
public void fireEvent(LoginEvent event)
{
handlerManager.fireEvent(event);
}
... or to this ....
public void fireAnEvent(GwtEvent<?> event)
{
handlerManager.fireEvent(event);
}
the DialogBox is draggable. However, if the method begins with the line
public void fireEvent(GwtEvent<?> event)
then the result is a DialogBox which can't be dragged.
I'm a bit unsettled by this, because I can't fathom a reason why my choice of name of a method should affect the draggability of a DialogBox, or why using a base class (GwtEvent) instead of a custom class that extends it should affect the draggability. And I suspect there are dozens of similar pitfalls for a naive novice like me.
(Expecting the DialogBox to centre itself was simply my mistake.)

Drag and Drop in GWT using gwt dnd

I have been really struggling to get Drag and Drop working in GWT. Last 3 days, I was trying to create a basic drag and drop application and failed. Currently I can drag it around, but I am unable to drop to any location.
How can we solve it? Do we need to modify onDragEnd - I am under the impression that unless I specifically have to do something, I dont have to? I am quite confused.
Also, how do I limit the drop to any single area? I do understand that we can do it using DropController. But I have defined the panels using UiBinder, so how do I get that panel back to link in the DropController? i.e. RootPanel.get() gives me the basic root panel and not the actual panel I want. I tried RootPanel.get("field-id"), but that is showing null even if that id is available. What am I doing wrong?
The code I have written is as follows:
public class TestPanel extends Composite implements
DragHandler, HasMouseDownHandlers, HasMouseUpHandlers, HasMouseMoveHandlers, HasMouseOutHandlers {
interface Binder extends UiBinder<Widget, TestPanel> { }
private static final Binder binder = GWT.create(Binder.class);
#UiField AbsolutePanel absolutePanel;
private PickupDragController TestDragController;
private Image img = new Image("./testicon.png");
public TestPanel(){
initWidget(binder.createAndBindUi(this));
absolutePanel.add(img);
TestDragController = new PickupDragController(RootPanel.get(), false);
AbsolutePositionDropController dropController = new AbsolutePositionDropController(
RootPanel.get());
TestDragController.registerDropController(dropController);
TestDragController.addDragHandler(this);
TestDragController.makeDraggable(this, getDragHandle());
}
private Widget getDragHandle() {
return img;
}
#Override
public void onDragEnd(DragEndEvent event) { }
#Override
public void onDragStart(DragStartEvent event) { }
#Override
public void onPreviewDragEnd(DragEndEvent event) throws VetoDragException { }
#Override
public void onPreviewDragStart(DragStartEvent event) throws VetoDragException { }
#Override
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
return addDomHandler(handler, MouseDownEvent.getType());
}
#Override
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
return addDomHandler(handler, MouseUpEvent.getType());
}
#Override
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
return addDomHandler(handler, MouseMoveEvent.getType());
}
#Override
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
return addDomHandler(handler, MouseOutEvent.getType());
}
}
and the testpanel uibinder looks like the following:
<g:AbsolutePanel ui:field="absolutePanel" styleName="{style.panel}">
</g:AbsolutePanel>
If somebody can help me out, I will be very much obliged.
K
P.S: To explain more: I was able to solve the first question by updating onDragEnd as the following:
#Override
public void onDragEnd(DragEndEvent event) {
DragContext context = event.getContext();
RootPanel.get().add(context.draggable, context.desiredDraggableX, context.desiredDraggableY);
}
but, I am not sure whether this is the correct solution - since I think I should not be doing the positioning myself.
If you're new to GWT dnd, why don't you try the working demo ?
There is a lot of examples and all the source code is available.
(And no, you're not supposed to do the positionning yourself)
You have to add a DragOverHandler on the drop target(s): even if it does nothing, it defines the component as a drop target.
Of course, you still need to define the DropHandler too on this component (and optionally, DragEnterHandler and DragLeaveHandler for visual feedback, in general).
The DragEndHandler is called even if the target isn't reached (drag abandoned in a non-drop area), it is used to change the state of the dragged object, you might need to set a way for the DropHandler to communicate success on dropping to the DragEndHandler (shared variable, EventBus, etc.).