6.5. FactPanel

FactPanel displays FactItem in a HorizontalPanel as shown in figure.

FactPanel
Figure 6.4. FactPanel

FactItem is a widget with two Labels, one for text and another for value, and FactPanel holds the FactItems. Instead of UiBinder template, FactPanel and FactItem directly extends HorizontalPanel.

in.fins.client.widget/FactItem.java

public class FactItem extends HorizontalPanel {

        private Label label;
        private String[] matchs;
        private Label value;
        private String category;

        @UiConstructor
        public FactItem(String category, String text, String match) {
                this.category = category;
                this.matchs = match.split("[,]+");

                label = new Label(text);
                label.setStyleName("fins-KeyValuePanel-Label-Key");
                add(label);

                value = new Label();
                value.setStyleName("fins-KeyValuePanel-Label-Value");
                add(value);
        }

....

FactItem uses @UiConstructor annotation for constructor as Snapshot’s UiBinder requires this to instantiate the FactItem.

Following UI template, in Snapshot.ui.xml, instantiate FactPanel and FactItems.

in.fins.client.content/Snapshot.ui.xml

        <g:layer left="2%" width="96%" top='6%' height='7%'>
                <f:FactPanel>
                        <f:FactItem category="Quote" text="FV" match="FV" />
                        <f:FactItem category="Quote" text="BV" match="BV" />
                        <f:FactItem category="Quote" text="High/Low" 
                                                match="52 Wk High,52 Wk Low" />
                        <f:FactItem category="Quote" text="EPS" match="EPS" />
                        <f:FactItem category="Quote" text="DIV" match="DIV (%)" />
                        <f:FactItem category="Quote" text="DY" match="DY (%)" />
                        <f:FactItem category="Quote" text="MC" match="Mk.Cap" />
                        <f:FactItem category="Quote" text="Ind. PE" match="Ind. PE" />
                </f:FactPanel>
        </g:layer>

UiBinder creates FactItems through constructor marked with @UiConstructor and then add them to FactPanel as child widgets and then add FactPanel to layer of LayoutPanel. This is the first time we are adding custom widget as the children of another custom widget. This is allowed only if parent widget, in this case FactPanel, implements HasWidgets interface. Then how come UiBinder is able to add FactItem to FactPanel without implementing HasWidgets and reasons being, FactPanel extends HorizontalPanel which implements HasWidgets. In case we use UiBinder for FactPanel then we have to implement HasWidgets, and we will do this for another widget in a later section.

UI entry <f:FactItem category="Quote" text="High/Low" match="52 Wk High,52 Wk Low" /> is bit different which has two keys in match, 52 Wk High and 52 Wk Low delimited with a comma. This FactItem takes the value from two Facts and displays them in a single FactItem. Constructor splits string variable, match, into String[] and which is used later to match against Fact with key “52 Wk High” and another Fact with “52 Wk Low”.

Next we have to pass the selected Symbol to FactPanel so that it displays the fact values.

 
 
SymbolEvent and SymbolAction

When user selects a name in AutoSuggest, it has to fetch the Symbol from SymbolDatabase and fire a SymbolEvent so that any interested client may retrieve the Symbol from SymbolEvent. Symbol holds data in DataGroup, Data and Fact, and FactPanel has to iterate over the received Symbol, and display the Facts.

AutoSuggest is a component of view layer whereas, task of fetching a Symbol is an aspect of domain/model layer and therefore dealing with SymbolEvent in AutoSuggest is not a good design practice, and instead a mediator has to handle this task. SymbolAction acts as mediator between AutoSuggest and clients like FactPanel, and it fetches a Symbol from server, encapsulate it in SymbolEvent and fires the event.

 

Propagation of events from AutoSuggest to FactPanel happens in two stages as shown in the figure. AutoSuggest fires NameEvent on name selection and SymbolAction handles this event, and once SymbolAction fetches Symbol it fires a SymbolEvent, and FactPanel handles it to display facts.

Event Propagation
Figure 6.5. Event Propagation

First instantiate SymbolAction and let it handle NameEvent.

in.fins.client.content/Snapshot.java

        public Snapshot() {

               ....

                SymbolAction symbolAction = new SymbolAction(getFilterMap());
                symbolAction.setEventSource(this);
                EventBus.get().addHandlerToSource(NameEvent.TYPE, this, symbolAction);
        }

....

        private static Map<String, String[]> getFilterMap() {
                Map<String, String[]> filterMap = new HashMap<String, String[]>();
                filterMap.put("Quote", getFilter("Quote"));
                return filterMap;
        }

        private static String[] getFilter(String cat) {
                if (cat.equals("Quote")) {
                        return new String[] { "Price", "PB", "P/E", "BV", "DY (%)",
                                        "DIV (%)", "FV", "EPS", "Mk.Cap", "Ind. PE", 
                                        "52 Wk High","52 Wk Low" };
                }
                return null;
        }

Snapshot creates SymbolAction and adds it as handle for NameEvent. Snapshot is set as eventSource for both SymbolAction and AutoSuggest. Static method Snapshot.getFilter() returns keys and SymbolDatabase generate Facts for those keys. Initially getFilter() returns keys for only one category i.e. Quote, as FactPanel displays Facts from that category, and later more categories are added. With this code, SymbolAction receives the NameEvent and fetches Symbol which contains Facts as specified by filterMap().

Next job is to fire SymbolEvent from SymbolAction and let the FactPanel handle the SymbolEvent.

in.fins.client.action/SymbolAction.java

        @Override
        public void onNameChange(NameEvent nameEvent) {
                getSymbol(nameEvent.getName());
        }

        private void getSymbol(String symbolName) {
                Symbol symbol = SymbolDatabase.getSymbol(symbolName, filterMap);
                for (String category : SymbolHelper.getCategories(symbol)) {
                        SymbolHelper.setPositionDate(symbol, category,
                                        SymbolHelper.getLastDate(symbol, category));
                }
                EventBus.get().fireEventFromSource(
                               new SymbolEvent(symbol),eventSource);
                log.fine("Fired SymbolEvent " + symbol.getName());
        }

in.fins.client.widget/FactPanel.java

        @Override
        public void onSymbolChange(SymbolEvent event) {
                setVisible(true);
                Symbol symbol = event.getSymbol();
                for (int c = 0; c < getWidgetCount(); c++) {
                        Widget widget = getWidget(c);
                        if (widget instanceof FactItem) {
                                FactItem item = (FactItem) widget;
                                Date date = SymbolHelper.getPositionDate(symbol,
                                                item.getCategory());
                                List<Fact> facts = SymbolHelper.getFacts(symbol,
                                                item.getCategory(), date);
                                item.setValue(getValue(facts, item.getMatchs()));
                        }
                }
        }

ComplexPanel.getWidget() returns the children, and if it is the instance of FactItem then its value is set. SymbolHelper method is used to get the List<Fact>. Private method getValue() on match returns the value from the List<Fact>. FactPanel is hidden with setVisible(false) in the constructor and made visible only when SymbolEvent is received else FactPanel is visible even before user selects a name.

Finally, make FactPanel as a handler for SymbolEvent

in.fins.client.content/Snapshot.java

        @UiFactory
        public FactPanel factPanelFactory() {
                FactPanel fp = new FactPanel();
                EventBus.get().addHandlerToSource(SymbolEvent.TYPE, this, fp);
                return fp;
        }
 
 

FilterMap

SymbolDatabase populates the Symbol with Fact based on keys in FilterMap and this makes the job of minting new Symbols with random values quite easy. Its real purpose is not that instead it reduces the data transmitted over the network. In actual data store, there are more than 200 financial data points for each symbol. In case, SymbolAction fetches the unfiltered Symbol with all these data point then bloated Symbol uses unnecessary bandwidth. Instead, FilterMap is sent to sever to trim down the symbol before transmission to save network resources but more about this in the next part when we cover the RPC calls.

This pattern of event handling is used extensively for the custom widget from now onwards.