Suggest a PlaceController Enhancement with the Delegate overriding

193 views
Skip to first unread message

Brandon Donnelson

unread,
Apr 21, 2012, 11:11:45 PM4/21/12
to google-we...@googlegroups.com
I'd like to suggest a PlaceController Enhancement with the Delegate overriding so I can have the place controller check if the warning has been cleared.

I'd like to build my own popup dialog as the delegate which is non blocking, and goto the newPlace when my saving data is done, instead of asking for the person to cancel an go do the saving manually. Basically, I'd like to tell the Place Controller via event that its ok now, or easier would be to say, check the warning message again, b/c it should be cleared. 

Currently the confirmation dialog is blocking and returns boolean in the place controller and I'd like to control the maybeGotoPlace with events. 

Thoughts?


public class PlaceController {
//...
 
public void goTo(Place newPlace) {
    log
().fine("goTo: " + newPlace);

   
if (getWhere().equals(newPlace)) {
      log
().fine("Asked to return to the same place: " + newPlace);
     
return;
   
}

// NOTE: delegate.confirm(warning) is blocking until dialog comes back true|false
   
String warning = maybeGoTo(newPlace);
   
if (warning == null || delegate.confirm(warning)) {
     
where = newPlace;
      eventBus
.fireEvent(new PlaceChangeEvent(newPlace));
   
}
 
}
//...
}

Thomas Broyer

unread,
Apr 22, 2012, 4:56:24 AM4/22/12
to google-we...@googlegroups.com
And how would you handle navigation (via bookmarks or the browser's history) while your popup is showing? (with the edge-case: what if I go back to the place I'm leaving? e.g. click the "back" button of your browser, the app shows the popup  , and now click "forward")

That being said, PlaceController is a so simple and "decoupled" class that the idea (and goal) was that if it doesn't fit your needs, then simply don't use it and make your own instead.

Brandon Donnelson

unread,
Apr 22, 2012, 2:27:18 PM4/22/12
to google-we...@googlegroups.com
Your right about it being simple. I love that part. 

My goal is to intercept the place change, save the data in the editor then move to the new place with out user intervention. I'd rather dispense with the formality of actually asking the person to save the data before changing to the new place. 

Here is what I've done using the delegate todo this job. 

1. I setup my Delegate 
  private PlaceControllerPopupMessage delegate = new PlaceControllerPopupMessage(this);
 
private final PlaceController placeController = new PlaceControllerEnhanced(this, eventBus, delegate);

2. I override Goto, so I can keep track of maybeGoto

package org.gonevertical.client.app;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;

public class PlaceControllerEnhanced extends PlaceController {

 
private ClientFactory clientFactory;

 
public PlaceControllerEnhanced(ClientFactory clientFactory, EventBus eventBus, Delegate delegate) {
   
super(eventBus, delegate);
   
this.clientFactory = clientFactory;
 
}

 
@Override
 
public void goTo(Place newPlace) {
   
this.clientFactory.setMaybeGoto(newPlace);
   
super.goTo(newPlace);
 
}
}

3. My Delegate
package org.gonevertical.client.widgets.placecontrollerdelegate;

import org.gonevertical.client.app.ClientFactory;
import org.gonevertical.client.app.editors.events.saving.SaveItEvent;
import org.gonevertical.client.app.editors.events.saving.SavedEvent;
import org.gonevertical.client.app.editors.events.saving.SavedEventHandler;
import org.gonevertical.core.client.loading.LoadingWidget;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.Widget;

public class PlaceControllerPopupMessage extends DialogBox implements PlaceController.Delegate {
 
 
interface Binder extends UiBinder<Widget, PlaceControllerPopupMessage> {}
 
 
private static final Binder binder = GWT.create(Binder.class);
 
@UiField HTML message;
 
@UiField PushButton cancel;
 
@UiField LoadingWidget loading;
 
 
private ClientFactory clientFactory;
 
private boolean confirmation;

 
public PlaceControllerPopupMessage(ClientFactory clientFactory) {
   
super(false, true);
   
   
this.clientFactory = clientFactory;
   
    setWidget
(binder.createAndBindUi(this));
    loading
.showLoading(false);
   
    clientFactory
.getEventBus().addHandler(SavedEvent.TYPE, new SavedEventHandler() {
     
public void onEditEvent(SavedEvent event) {
       
// only do this when its snowing, other wise all the save events will be coming in
       
if (isShowing() == true) {        
          gotoPlace
();
       
}
     
}
   
});
   
    cancel
.setVisible(false);
   
   
//setGlassEnabled(true);
 
}

 
private void gotoPlace() {
    confirmation
= true;
    loading
.showLoading(false);
    hide
();
    clientFactory
.getPlaceController().goTo(clientFactory.getMaybeGoto());
 
}

 
@UiHandler("cancel")
 
void onCancelClick(ClickEvent event) {
    hide
();
    loading
.showLoading(false);
    fireEvent
(new Window.ClosingEvent());
 
}

 
@Override
 
public HandlerRegistration addWindowClosingHandler(ClosingHandler handler) {
   
return Window.addWindowClosingHandler(handler);
 
}

 
@Override
 
public boolean confirm(String message) {
   
   
if (message != null) {
      centerIt
(message);
   
}

   
return confirmation;
 
}

 
private void centerIt(String message) {
   
this.message.setHTML(message);
    center
();
    loading
.showLoading(true);
    clientFactory
.getEventBus().fireEvent(new SaveItEvent());
 
}

}

4. In the editor workflow observing for SaveIt
clientFactory.getEventBus().addHandler(SaveItEvent.TYPE, new SaveItEventHandler() {
     
public void onEditEvent(SaveItEvent event) {
       
if (LearningPlanEditWorkFlow.this.presenter != null && LearningPlanEditWorkFlow.this.presenter.isFocused() == true) {
          save
();
       
}
     
}
   
});

5. And after the editor work flow saves, it resets the presenter, so the maybeGoto will be null, but setting Running to false. And asking the Delegate to goto new place.
  private Receiver<? super LearningPlanJdoProxy> getReciever() {
   
Receiver<LearningPlanJdoProxy> r = new Receiver<LearningPlanJdoProxy>() {
     
public void onSuccess(LearningPlanJdoProxy response) {
       
if (brandNew == true) {
         
EntityProxyId<LearningPlanJdoProxy> id = (EntityProxyId<LearningPlanJdoProxy>) response.stableId();
          presenter
.goTo(new LearningPlanEditPlace(id));
       
} else {
          edit
(response);
          saved
();
       
}
     
}
     
public void onFailure(ServerFailure error) {
        setState
(State.EDITING);
        wError
.showError(5000, "Server Error, please try again.");
        clientFactory
.sendError(error);
       
super.onFailure(error);
     
}
     
public void onConstraintViolation(Set<ConstraintViolation<?>> violations) {
        setState
(State.EDITING);
        wError
.showError(5000, "Server Error, please try again.");
       
super.onConstraintViolation(violations);
     
}
   
};
   
return r;
 
}
 
 
private void saved() {
    presenter
.setRunning(false);
    clientFactory
.getEventBus().fireEvent(new SavedEvent());
 
}

6. Here is the activity, for reference on how the warning message is derived. I don't put all my loading logic in here, b/c it over complicates it for me. I put it in the workflow, b/c it makes more sense to use the paths there for me. 
import org.gonevertical.client.app.ClientFactory;
import org.gonevertical.client.app.requestfactory.dto.LearningPlanJdoProxy;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;

public class LearningPlanEditActivity extends AbstractActivity implements LearningPlanEditViewImpl.LearningPlanViewPresenter {

 
private LearningPlanEditViewImpl view;
 
private ClientFactory clientFactory;
 
private boolean running;
 
private EntityProxyId<LearningPlanJdoProxy> id;
 
private boolean focused;
 
 
public LearningPlanEditActivity(LearningPlanEditPlace place, ClientFactory clientFactory) {
   
this.clientFactory = clientFactory;
    id
= place.getId();
 
}

 
/**
   * Invoked by the ActivityManager to start a new Activityz
   */

 
@Override
 
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
    focused
= true;
   
if (view == null) {
      view
= new LearningPlanEditViewImpl();
   
}
    view
.setClientFactory(clientFactory);
    view
.setPresenter(this);
    containerWidget
.setWidget(view.asWidget());
    view
.start(id);
 
}

 
@Override
 
public String mayStop() {
   
String s = null;
   
if (running == true) {
      s
= "Waiting to save data.";
   
}
   
return s;
 
}
 
 
/**
   * Navigate to a new Place in the browser
   */

 
public void goTo(Place place) {
    clientFactory
.getPlaceController().goTo(place);
 
}
 
 
/**
   * setting this running, and activity move, then a warning dailog will popup
   */

 
public void setRunning(boolean running) {
   
this.running = running;
 
}
 
 
public boolean isRunning() {
   
return running;
 
}
 
 
@Override
 
public void onCancel() {
    focused
= false;
 
}

 
@Override
 
public void onStop() {
    focused
= false;
 
}

 
@Override
 
public boolean isFocused() {
   
return focused;
 
}
}

Maybe something like this would be handy, adding the maybeGoto method?
public void goTo(Place newPlace) {
   
this.newPlace = newPlace;

    log
().fine("goTo: " + newPlace);

   
if (getWhere().equals(newPlace)) {
      log
().fine("Asked to return to the same place: " + newPlace);
     
return;
   
}


   
String warning = maybeGoTo(newPlace);

   
if (warning == null || delegate.confirm(warning)) {
     
where = newPlace;
      eventBus
.fireEvent(new PlaceChangeEvent(newPlace));
   
}
 
}

 
 
public maybeGoto() {
   
if (newPlace == null)  {
     
return;

   
}
   
where = newPlace;
    eventBus
.fireEvent(new PlaceChangeEvent(newPlace));
 
}

I'm sure there are 15 ways to do what I'm doing better :). This is probably more than you need, but I was hoping to ease the context of my thoughts. :)

The files that are attached show my Delegate/Confirmation of the PlaceController 
delegate. After saving the data, then it can goto a new place. 

Screen shot 2012-04-22 at 11.13.48 AM.png
Screen shot 2012-04-22 at 11.13.55 AM.png
Reply all
Reply to author
Forward
0 new messages