net.sf.eclipsefp.haskell.ui.internal.views.worksheet.EvalComposite.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.eclipsefp.haskell.ui.internal.views.worksheet.EvalComposite.java

Source

/**
 *  Copyright (c) 2014 by JP Moresmau
 * This code is made available under the terms of the Eclipse Public License,
 * version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html
 */
package net.sf.eclipsefp.haskell.ui.internal.views.worksheet;

import java.util.ArrayList;
import java.util.List;
import net.sf.eclipsefp.haskell.buildwrapper.types.EvalHandler;
import net.sf.eclipsefp.haskell.buildwrapper.types.EvalResult;
import net.sf.eclipsefp.haskell.ui.internal.util.UITexts;
import net.sf.eclipsefp.haskell.ui.util.HaskellUIImages;
import net.sf.eclipsefp.haskell.ui.util.IImageNames;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * This composite displays one evaluation expression and it result or error
 * Double clicking allow edition of the expression
 * There is also a button to delete the expression
 * @author JP Moresmau
 *
 */
public class EvalComposite extends Composite implements EvalHandler {
    /**
     * the expression to evaluate
     */
    private final EvalExpression expression;
    /**
     * the current result UI
     */
    private IControlProvider lResult;
    /**
     * result icon: ok/error
     */
    private final Label lResultIcon;
    /**
     * the listener to edit expression
     */
    private final MouseListener dblListener;
    /**
     * the parent page
     */
    private final WorkSheetViewPage page;

    public EvalComposite(final WorkSheetViewPage page, final EvalExpression expression) {
        super(page.getMainComposite(), SWT.NONE);
        this.page = page;
        this.expression = expression;
        GridLayout gl = new GridLayout(3, false);
        this.setLayout(gl);
        final Text lExpr = new Text(this, SWT.WRAP | SWT.MULTI);
        lExpr.setEditable(false);
        lExpr.setBackground(getBackground());
        lExpr.setFont(JFaceResources.getFontRegistry().getItalic(lExpr.getFont().getFontData()[0].getName()));
        GridData gdExpr = new GridData(GridData.FILL_HORIZONTAL);
        gdExpr.horizontalSpan = 2;
        gdExpr.widthHint = getBounds().width - 20;
        lExpr.setLayoutData(gdExpr);
        lExpr.setText(getExpression());

        ToolBar tb = new ToolBar(this, SWT.FLAT);
        ToolItem tiRemove = new ToolItem(tb, SWT.PUSH);
        tiRemove.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ELCL_REMOVE));
        tiRemove.setToolTipText(UITexts.worksheet_removeexpression_tooltip);

        lResultIcon = new Label(this, SWT.NONE);
        lResultIcon.setBackground(getBackground());
        lResultIcon.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));

        dblListener = new MouseAdapter() {

            @Override
            public void mouseDoubleClick(final MouseEvent event) {
                EvalExpressionDialog id = new EvalExpressionDialog(getShell(),
                        UITexts.worksheet_editexpression_title, UITexts.worksheet_addexpression_message,
                        expression);
                if (id.open() == Window.OK) {
                    expression.setExpression(id.getValue());
                    expression.setResultType(id.getResultType());
                    expression.setLastResult(null);
                    lExpr.setText(getExpression());
                    page.save();
                    page.eval();
                }

            }
        };

        buildEmptyControl();

        tiRemove.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final org.eclipse.swt.events.SelectionEvent arg0) {
                String msg = NLS.bind(UITexts.worksheet_removeexpression_message, expression.getExpression());
                if (MessageDialog.openConfirm(getShell(), UITexts.worksheet_removeexpression_title, msg)) {
                    page.remove(EvalComposite.this);
                }
            }
        });

        lExpr.addMouseListener(dblListener);
        lResultIcon.addMouseListener(dblListener);
        this.addMouseListener(dblListener);

        setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
    }

    public EvalExpression getEvalExpression() {
        return expression;
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
     */
    @Override
    public void setBackground(final Color arg0) {
        super.setBackground(arg0);
        for (Control c : getChildren()) {
            c.setBackground(arg0);
        }
    }

    /**
     * @return the expression
     */
    @Override
    public String getExpression() {
        return expression.getExpression();
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.widgets.Control#setToolTipText(java.lang.String)
     */
    @Override
    public void setToolTipText(final String arg0) {
        super.setToolTipText(arg0);
        for (Control c : getChildren()) {
            if (!(c instanceof ToolBar)) {
                c.setToolTipText(arg0);
            }
        }
    }

    /* (non-Javadoc)
     * @see net.sf.eclipsefp.haskell.buildwrapper.types.EvalHandler#handleResult(net.sf.eclipsefp.haskell.buildwrapper.types.EvalResult)
     */
    @Override
    public void handleResult(final EvalResult er) {
        if (expression.getLastResult() != null && expression.getLastResult().equals(er)) {
            return;
        }
        expression.setLastResult(er);
        if (this.isDisposed()) {
            return;
        }
        getDisplay().syncExec(new Runnable() {
            /* (non-Javadoc)
             * @see java.lang.Runnable#run()
             */
            @Override
            public void run() {
                setToolTipText("");

                buildControl(er);
                if (er.getType() != null && er.getType().length() > 0) {
                    setToolTipText(er.getType());
                }
                layout(true);
                page.layout();

            }
        });

    }

    private void buildControl(final EvalResult er) {
        if (er.getResult() != null && er.getResult().length() > 0) {
            buildResultControl(er.getResult());
        } else if (er.getError() != null && er.getError().length() > 0) {
            buildErrorControl(er.getError());
        } else {
            buildEmptyControl();
        }
    }

    private void buildResultControl(final String re) {
        switch (expression.getResultType()) {
        case HTML:
            buildHTML(re);
            break;
        case JSON:
            buildJSON(re);
            break;
        default:
            buildText(re);
        }

        lResultIcon.setImage(HaskellUIImages.getImage(IImageNames.WORKSHEET_OK));
    }

    private void setCurrentControl(final IControlProvider c) {
        lResult = c;
        GridData gdResult = new GridData(GridData.FILL_HORIZONTAL);
        gdResult.horizontalSpan = 2;
        gdResult.widthHint = getBounds().width - 40;
        lResult.getControl().setLayoutData(gdResult);
        lResult.getControl().setBackground(getBackground());
    }

    private void buildHTML(final String html) {
        IControlProvider cp = null;
        Browser b = null;
        if (lResult == null || !(lResult.getControl() instanceof Browser)) {
            if (lResult != null) {
                lResult.getControl().dispose();
                lResult = null;
            }
            final Browser fb = new Browser(this, SWT.TOP | SWT.RESIZE);
            b = fb;
            b.addProgressListener(new ProgressListener() {
                @Override
                public void completed(final ProgressEvent event) {
                    int contentHeight = ((Double) fb.evaluate("return document.body.scrollHeight")).intValue();
                    int contentWidth = ((Double) fb.evaluate("return document.body.scrollWidth")).intValue();
                    GridData gdResult = new GridData(GridData.FILL_HORIZONTAL);
                    gdResult.horizontalSpan = 2;
                    gdResult.heightHint = contentHeight;
                    gdResult.widthHint = contentWidth;
                    fb.setLayoutData(gdResult);

                    EvalComposite.this.layout(true);
                    EvalComposite.this.getParent().layout(true);
                }

                @Override
                public void changed(final ProgressEvent arg0) {
                    EvalComposite.this.layout(true);
                    EvalComposite.this.getParent().layout(true);
                }
            });
            b.addMouseListener(dblListener);
            cp = new ControlProvider(b);
        } else {
            cp = lResult;
            b = (Browser) lResult.getControl();
        }
        setCurrentControl(cp);
        b.setText(html);

    }

    private void buildText(final String txt) {
        IControlProvider cp = null;
        StyledText t = null;
        if (lResult == null || !(lResult.getControl() instanceof StyledText)) {
            if (lResult != null) {
                lResult.getControl().dispose();
                lResult = null;
            }
            // styled text wraps even if no text
            t = new StyledText(this, SWT.MULTI | SWT.WRAP);
            t.setEditable(false);
            t.addMouseListener(dblListener);
            cp = new ControlProvider(t);
        } else {
            cp = lResult;
            t = (StyledText) lResult.getControl();
        }
        setCurrentControl(cp);
        t.setText(txt);
    }

    private void buildErrorControl(final String error) {
        buildText(error);
        lResultIcon
                .setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK));

    }

    private void buildEmptyControl() {
        lResultIcon.setImage(null);
        buildText("");
    }

    private void buildJSON(final String json) {
        Object root = null;
        try {
            root = new JSONObject(json);
        } catch (JSONException je) {
            try {
                root = new JSONArray(json);
            } catch (JSONException je2) {
                root = JSONObject.stringToValue(json);
            }
        }
        if (root == null || root instanceof String) {
            buildText(json);
        } else {
            TreeControlProvider tcp;
            List<List<String>> names = null;
            if (lResult == null || !(lResult instanceof TreeControlProvider)) {
                if (lResult != null) {
                    lResult.getControl().dispose();
                    lResult = null;
                }
                TreeViewer tv = new TreeViewer(this, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL);
                tcp = new TreeControlProvider(tv);
                tcp.viewer.setContentProvider(new JSONContentProvider());
                tcp.viewer.setComparator(new JSONContentProvider.JSONComparator());
                Listener l = new Listener() {
                    /* (non-Javadoc)
                    * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
                    */
                    @Override
                    public void handleEvent(final Event arg0) {
                        // let the tree expand, then layout
                        getDisplay().asyncExec(new Runnable() {

                            @Override
                            public void run() {
                                EvalComposite.this.layout(true);
                                EvalComposite.this.page.layout();

                            }
                        });

                    }
                };
                tcp.viewer.getTree().addListener(SWT.Expand, l);
                tcp.viewer.getTree().addListener(SWT.Collapse, l);
                tcp.getControl().addMouseListener(dblListener);
            } else {
                tcp = (TreeControlProvider) lResult;
                // converts tree path to simple string paths
                TreePath[] exp = tcp.viewer.getExpandedTreePaths();
                if (exp != null && exp.length > 0) {
                    names = new ArrayList<>(exp.length);
                    LabelProvider lp = new LabelProvider();
                    for (TreePath tp : exp) {
                        if (tp.getSegmentCount() > 0) {
                            List<String> names1 = new ArrayList<>(tp.getSegmentCount());
                            for (int a = 0; a < tp.getSegmentCount(); a++) {
                                names1.add(lp.getText(tp.getSegment(a)));
                            }
                            names.add(names1);
                        }
                    }
                }
            }
            tcp.viewer.setInput(root);
            setCurrentControl(tcp);
            // expand the tree by reconverting name paths into tree paths
            if (names != null) {
                LabelProvider lp = new LabelProvider();
                JSONContentProvider cp = (JSONContentProvider) tcp.viewer.getContentProvider();
                List<TreePath> tps = new ArrayList<>();
                for (Object r : cp.getElements(root)) {
                    String rn = lp.getText(r);
                    for (List<String> names1 : names) {
                        if (names1.size() > 0 && names1.get(0).equals(rn)) {
                            List<Object> path = new ArrayList<>();
                            path.add(r);
                            addToPath(path, r, names1.subList(1, names1.size()), lp, cp);
                            tps.add(new TreePath(path.toArray()));
                        }
                    }
                }
                if (tps.size() > 0) {
                    tcp.viewer.setExpandedTreePaths(tps.toArray(new TreePath[tps.size()]));
                }
            }
        }
    }

    /**
     * converts one level name path into a path of proper objects
     * @param path the path of objects as given by the content provider
     * @param parent the parent objects
     * @param names1 the current name path
     * @param lp the label provider
     * @param cp the content provider
     */
    private void addToPath(final List<Object> path, final Object parent, final List<String> names1,
            final LabelProvider lp, final JSONContentProvider cp) {
        if (names1.size() > 0) {
            Object[] cs = cp.getChildren(parent);
            if (cs != null && cs.length > 0) {
                for (Object c : cs) {
                    String cn = lp.getText(c);

                    if (names1.get(0).equals(cn)) {
                        path.add(c);
                        addToPath(path, c, names1.subList(1, names1.size()), lp, cp);
                    }
                }
            }
        }
    }

    /**
     * Simple interface to use as wrapper around a control
     * @author JP Moresmau
     *
     */
    private interface IControlProvider {
        Control getControl();
    }

    /**
     * Simple wrapper
     * @author JP Moresmau
     *
     */
    private class ControlProvider implements IControlProvider {
        private final Control ctrl;

        public ControlProvider(final Control ctrl) {
            super();
            this.ctrl = ctrl;
        }

        @Override
        public Control getControl() {
            return ctrl;
        }
    }

    /**
     * we need to do things on the tree viewer, so wrap the viewer instead
     *
     * @author JP Moresmau
     *
     */
    private class TreeControlProvider implements IControlProvider {
        private final TreeViewer viewer;

        public TreeControlProvider(final TreeViewer viewer) {
            this.viewer = viewer;
        }

        /* (non-Javadoc)
         * @see net.sf.eclipsefp.haskell.ui.internal.views.worksheet.EvalComposite.IControlProvider#getControl()
         */
        @Override
        public Control getControl() {
            return viewer.getControl();
        }
    }
}