org.primordion.xholon.service.timeline.TimelineViewerChapJSON.java Source code

Java tutorial

Introduction

Here is the source code for org.primordion.xholon.service.timeline.TimelineViewerChapJSON.java

Source

/* Xholon Runtime Framework - executes event-driven & dynamic applications
 * Copyright (C) 2014 Ken Webb
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

package org.primordion.xholon.service.timeline;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayMixed;
import com.google.gwt.i18n.shared.DateTimeFormat;

import java.util.Date;

import org.primordion.xholon.base.IMessage;
import org.primordion.xholon.base.IXholon;
import org.primordion.xholon.base.Message;
import org.primordion.xholon.io.gwt.HtmlScriptHelper;

/**
 * <p>Capture data, and display the data in a web browser as a Chap Links timeline.</p>
 * <p>Example of invoking this class from a JavaScript environment (such as Firebug/Dev Tools):</p>
 * <pre>
//------------------- start of part 1
var service = xh.service("TimelineService-ChapJSON");
var root = xh.root();
// init
service.call(-3898, [null, "Hello World", root], root);
// capture (months are 0-indexed)
service.call(-3896, ["3018,0,6", "One"], root);
service.call(-3896, ["3018,1,7", "Two"], root);
service.call(-3896, ["3018,2,8", "Three"], root);
service.call(-3896, ["3018,3,9", "Four"], root);
service.call(-3896, ["3018,10,10", "Five"], root);
//------------------- end of part 1
    
//------------------- start of part 2
// draw (wait until timeline .js .css have loaded)
service.call(-3895, null, root);
//------------------- end of part 2
 * </pre>
 * 
 * <p>As a Xholon script in a XholonConsole (in two parts):</p>
 * <pre>
    
<script><![CDATA[
//------------------- start of part 1
var service = $wnd.xh.service("TimelineService-ChapJSON");
var root = $wnd.xh.root();
// init
service.call(-3898, [null, "Hello World", root], root);
// capture (months are 0-indexed)
service.call(-3896, ["3018,0,6", "One"], root);
service.call(-3896, ["3018,1,7", "Two"], root);
service.call(-3896, ["3018,2,8", "Three"], root);
service.call(-3896, ["3018,3,9", "Four"], root);
service.call(-3896, ["3018,10,10", "Five"], root);
$wnd.xh.tlSrvc = service;
//------------------- end of part 1
]]></script>
    
<script><![CDATA[
//------------------- start of part 2
// draw (wait until timeline .js .css have loaded)
var service = $wnd.xh.tlSrvc;
var root = $wnd.xh.root();
$wnd.console.log(service);
service.call(-3895, null, root);
//------------------- end of part 2
]]></script>
    
 * </pre>
 *
 * @author <a href="mailto:ken@primordion.com">Ken Webb</a>
 * @see <a href="http://www.primordion.com/Xholon">Xholon Project website</a>
 * @see <a href="http://almende.github.io/chap-links-library/timeline.html">Chap Links timeline website</a>
 * @since 0.9.0 (Created on January 5, 2014)
 */
@SuppressWarnings("serial")
public class TimelineViewerChapJSON extends AbstractTimelineViewer implements ITimelineViewer {

    /** StringBuilder initial capacity. */
    protected static final int SB_INITIAL_CAPACITY = 1000; // default is 16

    private String outFileName;
    private String outPath = "./ef/chtimeline/";
    private String modelName;
    private IXholon root;

    /** Current date and time. */
    private Date timeNow;
    private long timeStamp;

    // options
    protected String width = "100%";
    protected String height = "600px";
    protected String editable = "true";
    protected String style = "box";

    // startDate must be Y,M,D or Y,M,D,H,M,S  examples: "2010,7,23" "2010,7,23,23,0,0"
    DateTimeFormat dateFmt = DateTimeFormat.getFormat("yyyy,MM,dd,HH,mm,ss");

    /**
     * HTML element ID where Timeline will be displayed.
     */
    protected String viewElementId = "networkview";

    /**
     * Start of the CHAP Timeline script.
     */
    protected StringBuilder startSb = null;

    /**
     * The accumulating text for all CHAP Timeline JSON data.
     */
    protected StringBuilder dataSb = null;

    /**
     * CHAP Timeline options.
     */
    protected StringBuilder optionsSb = null;

    /**
     * End of the CHAP Timeline script.
     */
    protected StringBuilder endSb = null;

    /**
     * default constructor
     */
    public TimelineViewerChapJSON() {
    }

    @Override
    public IMessage processReceivedSyncMessage(IMessage msg) {
        Object response = null;
        Object data = msg.getData();

        switch (msg.getSignal()) {
        case SIG_INITIALIZE_REQ: {
            // the data is an array of three items
            String outFileName = null;
            String modelName = null;
            Object root = null;
            if (data instanceof JavaScriptObject) {
                JavaScriptObject jso = (JavaScriptObject) data;
                JsArrayMixed arr = jso.cast();
                outFileName = arr.getString(0);
                modelName = arr.getString(1);
                root = (Object) arr.getObject(2);
            } else if (data instanceof Object[]) {
                Object[] iobj = (Object[]) data;
                outFileName = (String) (iobj[0]);
                modelName = (String) (iobj[1]);
                root = (Object) (iobj[2]);
            } else {
                break;
            }
            initialize(outFileName, modelName, (IXholon) root);
            break;
        }
        case SIG_PARAMETERS_REQ:
            // there are no parameters yet
            break;
        case SIG_CAPTURE_REQ: {
            Object dateTimeObj = null;
            String content = null;
            if (data instanceof JavaScriptObject) {
                JavaScriptObject jso = (JavaScriptObject) data;
                JsArrayMixed arr = jso.cast();
                // dateTimeObj can be a String or Date; for now assume it's a String
                dateTimeObj = arr.getString(0);
                content = arr.getString(1);
            } else if (data instanceof Object[]) {
                Object[] cobj = (Object[]) data;
                dateTimeObj = cobj[0];
                content = (String) (cobj[1]);
            }
            capture(dateTimeObj, content);
            break;
        }
        case SIG_DRAW_REQ:
            drawTimeline();
            break;
        default:
            return super.processReceivedSyncMessage(msg);
        }
        return new Message(SIG_PROCESS_RSP, response, this, msg.getSender());
    }

    @Override
    public void initialize(String outFileName, String modelName, IXholon root) {
        timeNow = new Date();
        timeStamp = timeNow.getTime();
        if (outFileName == null) {
            this.outFileName = outPath + root.getXhcName() + "_" + root.getId() + "_" + timeStamp + ".js";
        } else {
            this.outFileName = outFileName;
        }
        this.modelName = modelName;
        this.root = root;

        this.startSb = new StringBuilder(128).append("var timeline = null;\n").append("var data = null;\n")
                .append("function draw() {\n");

        this.dataSb = new StringBuilder(SB_INITIAL_CAPACITY).append("// Create a JSON data table\n")
                .append("data = [") // don't use a trailing \n here
        ;

        this.optionsSb = new StringBuilder(SB_INITIAL_CAPACITY).append("// options\n").append("var options = {\n")
                .append("  'width': '" + width + "',\n").append("  'height': '" + height + "',\n")
                .append("  'editable': " + editable + ",\n").append("  'style': '" + style + "'\n").append("};\n");

        this.endSb = new StringBuilder(128).append("timeline = new links.Timeline(document.getElementById('")
                .append(viewElementId).append("'));\n").append("timeline.draw(data, options);\n").append("}\n")
                .append("draw();\n");

        if (!isDefinedChapLinksTimeline()) {
            //root.consoleLog("about to call loadChapLinksTimeline()");
            loadChapLinksTimeline();
        }
    }

    @Override
    public void capture(Object dateTimeObj, String content) {
        String startDate = null;
        if (dateTimeObj instanceof Date) {
            startDate = "new Date(" + dateFmt.format((Date) dateTimeObj) + ")";
        } else if (dateTimeObj instanceof String) {
            // assume that the String is in the right format
            startDate = "new Date(" + dateTimeObj + ")";
        } else {
            startDate = "new Date(" + dateFmt.format(new Date()) + ")"; // current date and time
        }

        dataSb.append("\n{\n").append("  \"start\": ").append(startDate).append(",\n").append("  \"content\": \"")
                .append(content).append("\"\n").append("},");
    }

    @Override
    public void drawTimeline() {
        if (!isDefinedChapLinksTimeline()) {
            return;
        }

        // JSON does not allow dangling commas
        // if existing last char == ',' then replace that last char
        int len = dataSb.length();
        if (dataSb.charAt(len - 1) == ',') {
            dataSb.setCharAt(len - 1, ' ');
        }
        dataSb.append("\n];\n");

        StringBuilder sb = new StringBuilder().append("// ").append(modelName).append("\n\n")
                .append(startSb.toString()).append(dataSb.toString()).append(optionsSb.toString())
                .append(endSb.toString());

        writeToTarget(sb.toString(), outFileName, outPath, root);

        if (root.getApp().isUseGwt()) {
            pasteScript("tvScript", sb.toString());
        } else {
            // TODO possibly write to a new browser window; open window and then write data
            System.out.println(sb.toString());
        }
    }

    protected void pasteScript(String scriptId, String scriptContent) {
        HtmlScriptHelper.fromString(scriptContent, true);
    }

    /**
     * Load CHAP Links Timeline library asynchronously.
     */
    protected void loadChapLinksTimeline() {
        loadCss("xholon/lib/timeline.css");
        require(this);
    }

    /**
     * use requirejs
     */
    protected native void require(final ITimelineViewer tv) /*-{
                                                            $wnd.requirejs.config({
                                                            enforceDefine: false,
                                                            paths: {
                                                            timeline: [
                                                            "xholon/lib/timeline-min"
                                                            ]
                                                            }
                                                            });
                                                            $wnd.require(["timeline"], function(timeline) {
                                                            //tv.@org.primordion.xholon.service.timeline.ITimelineViewer::drawTimeline()();
                                                            });
                                                            }-*/;

    /**
     * Is $wnd.links.Network defined.
     * @return it is defined (true), it's not defined (false)
     */
    protected native boolean isDefinedChapLinksTimeline() /*-{
                                                          return (typeof $wnd.links != "undefined") && (typeof $wnd.links.Timeline != "undefined");
                                                          }-*/;

    protected native void loadCss(String url) /*-{
                                              var link = $doc.createElement("link");
                                              link.type = "text/css";
                                              link.rel = "stylesheet";
                                              link.href = url;
                                              $doc.getElementsByTagName("head")[0].appendChild(link);
                                              }-*/;

}