Skip to main content

Home/ GWT - MVP/ Group items tagged widget

Rss Feed Group items tagged

Esfand S

Large scale application development and MVP - Part II - 0 views

  • segment the code that declares the UI from the code that drives the UI.
  • we want the our ContactsPresenter to implement a Presenter interface that allows our ContactsView to callback into the presenter when it receives a click, select or other event. The Presenter interface defines the following:   public interface Presenter<T> {    void onAddButtonClicked();    void onDeleteButtonClicked();    void onItemClicked(T clickedItem);    void onItemSelected(T selectedItem);  }
  • The first part of wiring everything up is to have our ContactsPresenter implement the Presenter interface, and then register itself with the underlying view. To register itself, we'll need our ContactsView to expose a setPresenter() method:   private Presenter<T> presenter;  public void setPresenter(Presenter<T> presenter) {    this.presenter = presenter;  }
  • ...8 more annotations...
  • With the ColumnDefinition(s) in place, we will start to see the fruits of our labor. Mainly in the way we pass model data to the view. As mentioned above we were previously dumbing down the model into a list of Strings. With our ColumnDefinition(s) we can pass the model untouched.   public class ContactsPresenter implements Presenter,    ...    private void fetchContactDetails() {      rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() {        public void onSuccess(ArrayList<ContactDetails> result) {            contactDetails = result;            sortContactDetails();            view.setRowData(contactDetails);        }        ...      });    }    ...  } And our ContactsViewImpl has the following setRowData() implementation:   public class ContactsViewImpl<T> extends Composite implements ContactsView<T> {    ...    public void setRowData(List<T> rowData) {      contactsTable.removeAllRows();      this.rowData = rowData;      for (int i = 0; i < rowData.size(); ++i) {        T t = rowData.get(i);        for (int j = 0; j < columnDefinitions.size(); ++j) {          ColumnDefinition<T> columnDefinition = columnDefinitions.get(j);          contactsTable.setWidget(i, j, columnDefinition.render(t));        }      }    }    ...  } A definite improvement; the presenter can pass the model untouched and the view has no rendering code that we would otherwise need to test.
  • Note that our ContactsView is now ContactsViewImpl<T> and implements ContactsView<T>. This is so that we can pass in a mocked ContactsView instance when testing our ContactsPresenter. Now in our AppController, when we create the ContactsView, we can initialize it with the necessary ColumnDefinition(s).
  • Our current solution is to have our presenters pass a dumbed down version of the model to our views. In the case of our ContactsView, the presenter takes a list of DTOs (Data Transfer Objects) and constructs a list of Strings that it then passes to the view. public ContactsPresenter implements Presenter {  ...  public void onSuccess(ArrayList<ContactDetails> result) {    contactDetails = result;    sortContactDetails();    List<String> data = new ArrayList<String>();    for (int i = 0; i < result.size(); ++i) {      data.add(contactDetails.get(i).getDisplayName());    }    display.setData(data);  }  ...} The "data" object that is passed to the view is a very (and I mean very) simplistic ViewModel — basically a representation of a more complex data model using primitives. This is fine for a simplistic view, but as soon as you start to do something more complex, you quickly realize that something has to give. Either the presenter needs to know more about the view (making it hard to swap out views for other platforms), or the view needs to know more about the data model (ultimately making your view smarter, thus requiring more GwtTestCases). The solution is to use generics along with a third party that abstracts any knowledge of a cell's data type, as well as how that data type is rendered.
  • We've figured out how to create the foundation for complex UIs while sticking to our requirement that the view remain as dumb (and minimally testable) as possible, but that's no reason to stop. While functionality is decoupled, there is still room for optimization. Having the ColumnDefinition create a new widget for each cell is too heavy, and can quickly lead to performance degradation as your application grows. The two leading factors of this degradation are: Inefficiencies related to inserting new elements via DOM manipulation Overhead associated with sinking events per Widget To overcome this we will update our application to do the following (in respective order): Replace our FlexTable implementation with an HTML widget that we'll populate by calling setHTML(), effectively batching all DOM manipulation into a single call. Reduce the event overhead by sinking events on the HTML widget, rather than the individual cells. The changes are encompassed within our ContactsView.ui.xml file, as well as our setRowData() and onTableClicked() methods. First we'll need to update our ContactsView.ui.xml file to use a HTML widget rather than a FlexTable widget.
  • The above code is similar to our original setRowData() method, we iterate through the rowData and for each item ask our column definitions to render accordingly. The main differences being that a) we're expecting each column definition to render itself into the StringBuilder rather than passing back a full-on widget, and b) we're calling setHTML on a HTML widget rather than calling setWidget on a FlexTable. This will decrease your load time, especially as your tables start to grow.
  • To reiterate, we're reducing the overhead of sinking events on per-cell widgets, and instead sinking on a single container, our HTML widget. The ClickEvents are still wired up via our UiHandler annotations, but with this approach, we're going to get the Element that was clicked on and walk the DOM until we find a parent TableCellElement. From there we can determine the row, and thus the corresponding rowData.
  • Code Splitting is the act of wrapping segmented pieces of your application into "split" points by declaring them within a runAsync() call. As long as the split portion of your code is purely segmented, and not referenced by other parts of the app, it will be downloaded and executed at the point that it needs to run.
  •         // TODO: Really total hack! There's gotta be a better way...        Element child = cell.getFirstChildElement();        if (child != null) {          Event.sinkEvents(child, Event.ONFOCUS | Event.ONBLUR);        }
Marco Antonio Almeida

GWT MVP Development with Activities and Places - Google Web Toolkit - Google Code - 2 views

  • An activity in GWT 2.1 is analogous to a presenter in MVP terminology. It contains no Widgets or UI code. Activities are started and stopped by an ActivityManager associated with a container Widget. A powerful new feature in GWT 2.1 is that an Activity can automatically display a warning confirmation when the Activity is about to be stopped (such as when the user navigates to a new Place). In addition, the ActivityManager warns the user before the window is about to be closed.
  • A place in GWT 2.1 is a Java object representing a particular state of the UI. A Place can be converted to and from a URL history token (see GWT's History object) by defining a PlaceTokenizer for each Place, and the PlaceHistoryHandler automatically updates the browser URL corresponding to each Place in your app.
  • A key concept of MVP development is that a view is defined by an interface.
  • ...23 more annotations...
  • It is useful for views to extend IsWidget if they do in fact provide a Widget.
  • more complicated view that additionally defines an interface for its corresponding presenter (activity)
  • The Presenter interface and setPresenter method allow for bi-directional communication between view and presenter,
  •   @UiHandler("goodbyeLink")        void onClickGoodbye(ClickEvent e) {                presenter.goTo(new GoodbyePlace(name));        }
  • Because Widget creation involves DOM operations, views are relatively expensive to create. It is therefore good practice to make them reusable, and a relatively easy way to do this is via a view factory, which might be part of a larger ClientFactory.
  • Note the use of @UiHandler that delegates to the presenter
  • Another advantage of using a ClientFactory is that you can use it with GWT deferred binding to use different implementation classes based on user.agent or other properties. For example, you might use a MobileClientFactory to provide different view implementations than the default DesktopClientFactory.
  • ClientFactory A ClientFactory is not strictly required in GWT 2.1; however, it is helpful to use a factory or dependency injection framework like GIN to obtain references to objects needed throughout your application like the event bus.
  • Specify the implementation class in .gwt.xml:     <!-- Use ClientFactoryImpl by default -->    <replace-with class="com.hellomvp.client.ClientFactoryImpl">    <when-type-is class="com.hellomvp.client.ClientFactory"/>    </replace-with> You can use <when-property-is> to specify different implementations based on user.agent, locale, or other properties you define.
  • Activities Activity classes implement com.google.gwt.app.place.Activity. For convenience, you can extend AbstractActivity, which provides default (null) implementations of all required methods.
  • The first thing to notice is that HelloActivity makes reference to HelloView. This is a view interface, not an implementation.
  • The HelloActivity constructor takes two arguments: a HelloPlace and the ClientFactory
  • In GWT 2.1, activities are designed to be disposable, whereas views, which are more expensive to create due to the DOM calls required, should be reusable. In keeping with this idea, ClientFactory is used by HelloActivity to obtain a reference to the HelloView as well as the EventBus and PlaceController.
  • Finally, the goTo() method invokes the PlaceController to navigate to a new Place. PlaceController in turn notifies the ActivityManager to stop the current Activity, find and start the Activity associated with the new Place, and update the URL in PlaceHistoryHandler.
  • The non-null mayStop() method provides a warning that will be shown to the user when the Activity is about to be stopped due to window closing or navigation to another Place. If it returns null, no such warning will be shown.
  • In order to be accessible via a URL, an Activity needs a corresponding Place. A Place extends com.google.gwt.app.place.Place and must have an associated PlaceTokenizer which knows how to serialize the Place's state to a URL token.
  • It is convenient (though not required) to declare the PlaceTokenizer as a static class inside the corresponding Place. However, you need not have a PlaceTokenizer for each Place. Many Places in your app might not save any state to the URL, so they could just extend a BasicPlace which declares a PlaceTokenizer that returns a null token.
  • For even more control, you can instead implement PlaceHistoryMapperWithFactory and provide a TokenizerFactory that, in turn, provides individual PlaceTokenizers.
  • For more control of the PlaceHistoryMapper, you can use the @Prefix annotation on a PlaceTokenizer to change the first part of the URL associated with the Place
  • PlaceHistoryMapper PlaceHistoryMapper declares all the Places available in your app. You create an interface that extends PlaceHistoryMapper and uses the annotation @WithTokenizers to list each of your tokenizer classes.
  • ActivityMapper Finally, your app's ActivityMapper maps each Place to its corresponding Activity. It must implement ActivityMapper, and will likely have lots of code like "if (place instanceof SomePlace) return new SomeActivity(place)".
  • How it all works The ActivityManager keeps track of all Activities running within the context of one container widget. It listens for PlaceChangeRequestEvents and notifies the current activity when a new Place has been requested.
  • To navigate to a new Place in your application, call the goTo() method on your PlaceController.
Esfand S

What's Coming in GWT 2.1? - Google Web Toolkit - Google Code - 1 views

  • MVP Framework The MVP Framework is an app framework that makes it easy for you to connect Data Presentation Widgets with backend data. Using this framework you create views that are focused on displaying data, Activities and an AcivityManager which are the "presenters", responsible for handling self-contained actions, and RequestFactories that fetch and propagate model changes throughout your app. To make developing apps of this style easier, the 1.1 M1 release of Spring Roo, can generate and maintain the boilerplate code associated with connecting your app's components with GWT's MVP Framework.
  • the data presentation widgets use a 'flyweight' design. Rather than being a container of other widgets, which can tend to be heavy, they build up chunks of HTML that is injected into the DOM. This not only speeds up initialization, but also reduces the event handling overhead that can slow down user experience when there are hundreds of widgets within a view.
  • To upgrade to 2.1 M1, simply do the following Download GWT 2.1 M1 from the download page and unpack it to the directory of your choice. If you use Eclipse to develop, you should also download the Google Plugin for Eclipse from the same download page. Update your GWT project build path to use the latest gwt-user.jar and gwt-dev.jar (and any other GWT jars that you included on your classpath). Replace references to gwt-dev-<platform>.jar with the location of the new gwt-dev.jar (there is no longer a platform specific suffix). Update any run configurations or application compile and shell scripts to include the latest JARs in the classpath (same JARs as mentioned in step 2). Run a GWT compilation over your project to generate the latest GWT application files for your project. Deploy the latest GWT application files to your web server.
Esfand S

GWT 2.1 Places & Activities - What changed between M3 and RC1 - tbroyer's posterous - 0 views

  • PlaceHistoryHandler has been split into a concrete PlaceHistoryHandler and the PlaceHistoryMapper interface, which you're free to implement yourself or use as before, giving your sub-interface to GWT.create() so that it generates the implementation from the @WithTokenizers annotation (and/or factory if you're using PlaceHistoryMapperWithFactory); this approach is similar to the ActivityManager vs. ActivityMapper, with the added generator for the mapper based on PlaceTokenizers and @Prefix.
  • Activity.Display now is com.google.gwt.user.client.ui.AcceptsOneWidget, which is implemented by SimplePanel (showActivityWidget is thus renamed as setWidget). IsWidget has been moved to com.google.gwt.user.client.ui and is now implemented by Widget (which returns itself); this means that if your view classes extends Widget (most views extend it through Composite) you no longer have to implement the asWidget method. In addition, all widgets now accept IsWidget as argument where they already accepted Widget.
Esfand S

What's Coming in GWT 2.1? - Google Web Toolkit - Google Code - 1 views

  • the data presentation widgets use a 'flyweight' design. Rather than being a container of other widgets, which can tend to be heavy, they build up chunks of HTML that is injected into the DOM. This not only speeds up initialization, but also reduces the event handling overhead that can slow down user experience when there are hundreds of widgets within a view.
  • The MVP Framework is an app framework that makes it easy for you to connect Data Presentation Widgets with backend data. Using this framework you create views that are focused on displaying data, Activities and an AcivityManager which are the "presenters", responsible for handling self-contained actions, and RequestFactories that fetch and propagate model changes throughout your app.
  • To make developing apps of this style easier, the 1.1 M1 release of Spring Roo, can generate and maintain the boilerplate code associated with connecting your app's components with GWT's MVP Framework.
  • ...1 more annotation...
  • To upgrade to 2.1 M1, simply do the following Download GWT 2.1 M1 from the download page and unpack it to the directory of your choice. If you use Eclipse to develop, you should also download the Google Plugin for Eclipse from the same download page. Update your GWT project build path to use the latest gwt-user.jar and gwt-dev.jar (and any other GWT jars that you included on your classpath). Replace references to gwt-dev-<platform>.jar with the location of the new gwt-dev.jar (there is no longer a platform specific suffix). Update any run configurations or application compile and shell scripts to include the latest JARs in the classpath (same JARs as mentioned in step 2). Run a GWT compilation over your project to generate the latest GWT application files for your project. Deploy the latest GWT application files to your web server.
Esfand S

GWT MVP Development with Activities and Places - Google Web Toolkit - Google Code - 1 views

  • Views A key concept of MVP development is that a view is defined by an interface. This allows multiple view implementations based on client characteristics (such as mobile vs. desktop) and also facilitates lightweight unit testing by avoiding the time-consuming GWTTestCase. There is no View interface or class in GWT which views must implement or extend; however, GWT 2.1 introduces an IsWidget interface that is implemented by most Widgets as well as Composite. It is useful for views to extend IsWidget if they do in fact provide a Widget. Here is a simple view from our sample app. public interface GoodbyeView extends IsWidget {    void setName(String goodbyeName);} The corresponding implementation extends Composite, which keeps dependencies on a particular Widget from leaking out. public class GoodbyeViewImpl extends Composite implements GoodbyeView {    SimplePanel viewPanel = new SimplePanel();    Element nameSpan = DOM.createSpan();    public GoodbyeViewImpl() {        viewPanel.getElement().appendChild(nameSpan);        initWidget(viewPanel);    }    @Override    public void setName(String name) {        nameSpan.setInnerText("Good-bye, " + name);    }}
  • A place in GWT 2.1 is a Java object representing a particular state of the UI. A Place can be converted to and from a URL history token (see GWT's History object) by defining a PlaceTokenizer for each Place, and the PlaceHistoryHandler automatically updates the browser URL corresponding to each Place in your app.
  • Place
  • ...2 more annotations...
  • new GoodbyePlace(name)
  • view factory
Esfand S

Issue 5275 - google-web-toolkit - All widgets should implement some kind of interface f... - 0 views

  • if your concern is testing your presenter, then how about changing your MVP from the "Passive View" pattern (the one showed by Ray Ryan at I/0 2009) to the "Supervising Controller" pattern (the one used by Cell widgets internally and by applications generated by Spring Roo): http://martinfowler.com/eaaDev/uiArchs.html Sure you test a bit less things as you leave more of the logic into the view than with a "Passive View", but in my experience it also makes tests much more easier to write and more readable, as you need far less mocks and stubs (no MockButton, MockTextBox, etc. only a MockView).
Esfand S

An MVP-compatible EnumListBox for GWT « TurboManage - 2 views

  • If you start thinking about the different kinds of viewers you can create you’ll see that most of them behave in the same way. Whether you display your list of boolean values (in this case) as a single select listbox (with one value being true at a time) or as a group of radio buttons or as a multiselect list (all selected are true) or as a group of check boxes the only thing separating the class ListBoxViewer from GroupViewer (for lack of a better name) would be what widgets they choose to use. They can both inherit SelectableListViewer which holds most of the logic and a setMultiSelect(boolean enabled) method. Later on when you want to create a table with a check box on each row that selects the row for some future action it’s just more of the same old.
  • So you have a ListBoxViewer that holds the listBox and has a getWidget() to give the widget to your panel.The viewer takes an instance of the interface ListBoxFormat in its constructor. The format implementation has a getValue(E element) that returns the value to display in the llistbox. The viewer has the required methods to set the values of the listbox and get a list of the currently selected values and so on. Probably along the way of what you’re planning to do next. By using viewers and formats you can do the same thing for other widgets like tables as well. So populating a table with values is as easy as tableViewer.setSource(aListOfTableRowObjects) where the objects in the list can by of any type that you can write a TableFormat for (with a getColumnValue(int column, E element) method). GlazedLists does this for the desktop (Swing and SWT/JFace). The cool thing there is that the viewer is aware of changes to the actual input list outside of the viewer, I don’t think that’s possible in GWT yet
  • the constructor uses an EnumTranslator to populate the labels in the ListBox. This allows you to use a standard GWT ConstantsWithLookup inteface to supply localized text for the enum values instead of the constant names. ConstantsWithLookup is just like Constants, but with the important ability to find a value dynamically without invoking a method corresponding to the property name.
Esfand S

Feedback on "Large scale app development MVP article" - Google Web Toolkit | Google Groups - 0 views

  • It however clarify things about how Google sees MVP in GWT. They're even adding some MVP "framework" to GWT 2.1 (IsWidget and Activities, where an Activity is more or less your presenter, from what I understood).
  • RequestFactory on the other hand is a new thing for efficient CRUD operations on entity objects, which plugs more-or-less directly into the new Data widgets. Those widgets do blur the line a bit, but they're not really about presentation "logic", and they're somehow MVP- based themselves.
Esfand S

Testing complex Widgets without interface ? - Google Web Toolkit | Google Groups - 0 views

  • Have a look at the Cell widgets' internals, they use MVP internally so the presenter can be tested independently from the views.
Esfand S

new GWT MVP article (part 2) - Google Web Toolkit | Google Groups - 0 views

  • In our app, in effect, each "parent presenter" also plays the role of "app controller"; but because we have the presenter/view dichotomy, the view exposes setSomeWidget(...) methods that the presenter calls; e.g. setHeader(...), setBody(...), setFooter(...).
  • > 3- what do you think of "presenter.go(container)" ? We do it the other way around: our presenters have a getView() method and the parent calls container.add((Widget) child.getView()). This is actually split between the presenter and the view, see above: view.setHeader(childPresenter.getView()) in the presenter, and containerWidget.add((Widget) child) in the view. The only "issue" with presenter.go(container) is that container must be a "simple" container, which means that when it's meant to be a dock (layout) panel, tab panel, or some other complex panel (or an absolute panel and you want to add with coordinates), you actually have to add a SimplePanel first and pass it as the "container" to the go() method. Otherwise, I can't see a problem with presenter.go(container).
  • navigation/ > history token inside multiple IF statements ? I'm using a very similar approach as the one in bikeshed: http://code.google.com/p/google-web-toolkit/source/browse/trunk/bikes...
Esfand S

new GWT MVP article (part 2) - Google Web Toolkit | Google Groups - 0 views

  • > 2- when google wants to address problem of Nested/Layered presenters ? > header/body/footer, and body having its own dockpanellayout structure. We use the technique described in part II. Composite views are responsible for instantiating their own children, and making them available for the parallel composite presenters.
  • If you're referring to the ColumnDefinitions, we know they'll scale. One, it requires minimal widget overhead and is fast. No more embedding hundreds of widgets within a table. Two, it's extensible, and testable. As your model grows, your ColumnDefinitions grow, not your views.  ColumnDefinitions are quite trivial, the bulk of the code dedicated to generating HTML, and don't require a GwtTestCase.
Esfand S

ValueStoreAndRequestFactory - google-web-toolkit - Discussion of ValueStore and Request... - 1 views

  • Databinding is about making two properties in sync. The target property could be a JPA entity, but also another widget property. From a Databinding framework perspective, a JPA entity object of any RPC interface should not be tied to the framework.
  • The intent is that ValueBox? would also be useful for data binding of plain old client side JavaBeans?, without any need for the Id and Property classes. I can define a ValueBox? interface tied to a set of bean classes and have it move their fields to and from HasValue? instances, enforcing validations in the process. I can set up this binding myself via calls like valueBox.setSubcription(bean, fieldNameString). Or I can GWT.create an EditorSupport? object to make those calls for me (which is why they didn't appear in the sketch).
  • Re: why re-invent a wheel, we want our new data backed widgets to play very nice in an asynchronous world — I'll tell you what values I want, you push them into me when they show up, and as they get updated. My impression of the existing frameworks is that they don't play naturally in that world.
  • ...1 more annotation...
  • RequestFactory? is intended as another, optional layer on top of this, to aid in dealing with server side ORM. Shared Id instances refer to server side Entities. They and Property instances are used as arguments to command objects (Requests) to make asynchronous RPC calls for the values of fields on these objects, and to edit them. (The @ServerType? annotation is to simplify the use of the ids server side.) ValueBox? and EditorSupport? can also be used to bind these objects and the UI that displays them. I figure we'll provide a script and a servlet that can grovel through JPA service interfaces and generate / maintain the Id and Property definitions, and that others can easily be spun for other persistence frameworks.
Esfand S

MVP with EventBus question - Google Web Toolkit | Google Groups - 0 views

  • Yeah, the one problem with UiBinder and MVP is this pattern collision.... UiBinder says, "view are directly attached to views". MVP says, "view's are attached to presenters, if you want to chain views the presenters control this". Consequently, you can't get UiBinder to create your @UiFields (i.e. empty constructor) and you can't get Gin to @Inject them into the view either... because they are in the presenter. Unless of course you use @Named+Singleton bindings in Gin and then both presenter and view will be injected with the same object. This is the one bit of boilerplate we're still writing.
  • I looked into that, and (unless I'm wrong), I think that @UiField(provided=true) will cause the UiBinder to look in the .ui.xml file for argument to satisfy Foo. In my case I am trying to "inject" an EventBus into the widget, not a visual element.
Esfand S

MVP multiple buttons/fields - Google Web Toolkit | Google Groups - 0 views

  • Start moving the code of addStock to the view. Try not to use widget code on the presenter. Then create an interface and implement in the presenter: class SomeViewHandlers {     void deleteStock(Stock code); } You already have the deleteStock method... so just add "implements SomeViewHandlers" to it. Then you need to give to the display that interface (generally in the constructor): display.setViewHandlers(this); Then in the presenter lease the method as: private void addStock(JsArray<Stock> stocks) { display.addStock(stocks); } And in the view copyPaste the code of the method and change this:  removeButton.addClickHandler(new ClickHandler() {        @Override        public void onClick(ClickEvent event) {          *viewHandlers.*deleteStock(code);        }      });
1 - 20 of 26 Next ›
Showing 20 items per page