Java tutorial
/** * 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(); } } }