org.jboss.tools.jst.web.ui.palette.html.wizard.AbstractNewHTMLWidgetWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.jst.web.ui.palette.html.wizard.AbstractNewHTMLWidgetWizardPage.java

Source

/******************************************************************************* 
 * Copyright (c) 2013 Red Hat, Inc. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is made available under the terms of the 
 * Eclipse Public License v1.0 which accompanies this distribution, 
 * and is available at http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/
package org.jboss.tools.jst.web.ui.palette.html.wizard;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.SystemUtils;
import org.eclipse.compare.Splitter;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
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.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.jboss.tools.common.model.options.SharableConstants;
import org.jboss.tools.common.model.ui.editors.dnd.ValidationException;
import org.jboss.tools.common.model.ui.views.palette.IPositionCorrector;
import org.jboss.tools.common.model.ui.views.palette.PaletteInsertManager;
import org.jboss.tools.common.ui.widget.editor.IFieldEditor;
import org.jboss.tools.common.util.FileUtil;
import org.jboss.tools.common.util.SwtUtil;
import org.jboss.tools.jst.web.ui.WebUiPlugin;

/**
 * 
 * @author Viacheslav Kabanovich
 *
 */
public class AbstractNewHTMLWidgetWizardPage extends AbstractWizardPageWithPreview {
    protected Map<String, IFieldEditor> editors = new HashMap<String, IFieldEditor>();

    protected StyledText text;
    protected Browser browser;
    protected File sourceFile = null;
    protected String sourceURL = null;

    public AbstractNewHTMLWidgetWizardPage(String pageName, String title) {
        super(pageName, title);
    }

    public AbstractNewHTMLWidgetWizardPage(String pageName, String title, ImageDescriptor titleImage) {
        super(pageName, title, titleImage);
    }

    @Override
    public AbstractNewHTMLWidgetWizard getWizard() {
        return (AbstractNewHTMLWidgetWizard) super.getWizard();
    }

    protected void createWarningMessage() {
        String palettePath = getWizard().getCommandProperties().getProperty(SharableConstants.PALETTE_PATH);
        IPositionCorrector corrector = PaletteInsertManager.getInstance().createCorrectorInstance(palettePath);
        if (corrector != null) {
            ITextSelection s = (ITextSelection) getWizard().getWizardModel().getDropData().getSelectionProvider()
                    .getSelection();
            IDocument doc = getWizard().getWizardModel().getDropData().getSourceViewer().getDocument();
            IStructuredModel model = null;
            try {
                model = StructuredModelManager.getModelManager().getExistingModelForRead((IStructuredDocument) doc);
                if (model instanceof IDOMModel) {
                    warningMessage = corrector.getWarningMessage(((IDOMModel) model).getDocument(), s);
                }
            } finally {
                if (model != null) {
                    model.releaseFromRead();
                }
            }
        }
    }

    String warningMessage;

    public void validate() throws ValidationException {
        if (warningMessage != null) {
            throw new ValidationException(warningMessage, true);
        }
    }

    @Override
    protected void createPreview() {
        if (hasVisualPreview()) {
            Splitter previewPanel = new Splitter(panel, SWT.VERTICAL);
            GridData d = new GridData(GridData.FILL_BOTH);
            previewPanel.setLayoutData(d);
            previewPanel.setLayout(new GridLayout());

            createTextPreview(previewPanel);

            Composite browserPanel = createBrowserPanel(previewPanel);
            browser = WebUiPlugin.createBrowser(browserPanel, getPreferredBrowser());

            if (browser != null) {
                browser.setLayoutData(new GridData(GridData.FILL_BOTH));
                browser.pack();
            }
            createDisclaimer(browserPanel);
            previewPanel.setWeights(new int[] { 4, 6 });
            this.previewPanel = previewPanel;
        } else {
            createTextPreview(panel);
            previewPanel = text;
        }

    }

    protected void startPreview() {
        Display.getCurrent().asyncExec(new Runnable() {
            public void run() {
                if (text == null || text.isDisposed()) {
                    return;
                }
                updatePreviewPanel(true, true);
                updatePreviewContent();
                runValidation();
                text.addControlListener(new ControlAdapter() {
                    @Override
                    public void controlResized(ControlEvent e) {
                        if (textLimit < 0 || textLimit == getTextLimit())
                            return;
                        resetText();
                    }
                });
            }
        });
    }

    protected void onCreateControl() {
        Display.getDefault().addFilter(SWT.FocusOut, focusReturn);
        Display.getDefault().addFilter(SWT.MouseDown, focusReturn);
        Display.getDefault().addFilter(SWT.KeyDown, focusReturn);
        Display.getDefault().addFilter(SWT.Modify, focusReturn);
        createWarningMessage();
    }

    void createTextPreview(Composite parent) {
        text = new StyledText(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL);
        text.setFont(JFaceResources.getTextFont());
        text.setLayoutData(new GridData(GridData.FILL_BOTH));
        /**
         * We set some initial content to the text widget to provide a reasonable default width
         * for that widget and for browser. We avoid setting width hint or other ways to 
         * provide the default width, because text widget and browser should be resizable 
         * and their content will be formatted to the available width. Also, initial width
         * is to depend on system font size so that initial content serves best to that purpose. 
         */
        text.setText(
                "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<html><body>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</body></html>");
    }

    protected static final boolean isLinux = SystemUtils.IS_OS_LINUX;

    protected int getPreferredBrowser() {
        return WebUiPlugin.getPreferredBrowser();
    }

    protected boolean hasVisualPreview() {
        return true;
    }

    public String getBrowserType() {
        return browser == null ? null : browser.getBrowserType();
    }

    protected static final String SECTION_NAME = "InsertTag";
    public static final String ADD_JS_CSS_SETTING_NAME = "addJSCSS";

    private Composite createBrowserPanel(Composite previewPanel) {
        Composite browserPanel = new Composite(previewPanel, SWT.BORDER);
        GridData g = new GridData();
        g.horizontalAlignment = SWT.FILL;
        g.verticalAlignment = SWT.FILL;
        g.grabExcessHorizontalSpace = true;
        g.grabExcessVerticalSpace = true;
        browserPanel.setLayoutData(g);
        GridLayout l = new GridLayout();
        l.verticalSpacing = 0;
        l.marginWidth = 0;
        l.marginHeight = 0;
        browserPanel.setLayout(l);
        return browserPanel;
    }

    private void createDisclaimer(Composite browserPanel) {
        Label disclaimer = new Label(browserPanel, SWT.NONE);
        disclaimer.setText(WizardMessages.previewDisclaimer);
        GridData disclaimerData = new GridData();
        disclaimerData.horizontalAlignment = SWT.CENTER;
        disclaimer.setLayoutData(disclaimerData);
        FontData fd = disclaimer.getFont().getFontData()[0];
        fd.setStyle(SWT.ITALIC);
        fd.setHeight(8);
        Font font = new Font(null, fd);
        disclaimer.setFont(font);
        SwtUtil.bindDisposal(font, disclaimer);
    }

    public void addEditor(IFieldEditor editor) {
        editors.put(editor.getName(), editor);
    }

    public void addEditor(IFieldEditor editor, Composite parent) {
        if (parent != null)
            editor.doFillIntoGrid(parent);
        editor.addPropertyChangeListener(this);
        addEditor(editor);
        Combo c = (parent != null) ? findCombo(editor) : null;
        if (c != null) {
            new ComboContentProposalProvider(c);
        }
    }

    private Combo findCombo(IFieldEditor editor) {
        for (Object o : editor.getEditorControls()) {
            if (o instanceof Combo) {
                return (Combo) o;
            }
        }
        return null;
    }

    public void addEditor(IFieldEditor editor, Composite parent, boolean expandCombo) {
        addEditor(editor, parent);
        if (expandCombo && parent != null) {
            expandCombo(editor);
        }
    }

    /**
     * Utility method expanding combo
     * @param name
     * @return
     */
    public void expandCombo(IFieldEditor editor) {
        if (left == null)
            return;
        Control c = (Control) (editor.getEditorControls()[1]);
        GridData d = (GridData) c.getLayoutData();
        d.horizontalAlignment = SWT.FILL;
        d.grabExcessHorizontalSpace = true;
        c.setLayoutData(d);
    }

    public IFieldEditor getEditor(String name) {
        return editors.get(name);
    }

    public String getEditorValue(String name) {
        return !editors.containsKey(name) ? null : getEditor(name).getValueAsString();
    }

    public void setEditorValue(String name, String value) {
        if (editors.containsKey(name)) {
            getEditor(name).setValue(value);
        }
    }

    File getFile() {
        if (sourceFile == null) {
            try {
                sourceFile = File.createTempFile("jquery_preview", ".html");
                sourceURL = sourceFile.toURI().toURL().toString();
            } catch (IOException e) {
                WebUiPlugin.getDefault().logError(e);
            }
        }
        return sourceFile;
    }

    @Override
    protected void updatePreviewContent() {
        resetText();
        if (browser == null) {
            return;
        }
        File f = getFile();
        FileUtil.writeFile(f, getWizard().getTextForBrowser());

        focusReturn.init();

        if (browser.getUrl() == null || !browser.getUrl().endsWith(f.getName())
                || "mozilla".equals(getBrowserType())) {
            browser.setUrl(sourceURL);
        } else {
            browser.refresh();
        }
    }

    boolean isFocusInBrowser() {
        Control c = Display.getDefault().getFocusControl();
        while (c != null && c != browser) {
            c = c.getParent();
        }
        return c == browser;
    }

    FocusReturn focusReturn = new FocusReturn();

    class FocusReturn implements Listener {
        Control c;
        long t;
        Point s;
        StringBuilder missed = new StringBuilder();

        void clear() {
            c = null;
            s = null;
            t = 0;
            missed.setLength(0);
        }

        private Point getSelection() {
            return (c instanceof Combo) ? ((Combo) c).getSelection()
                    : (c instanceof Text) ? ((Text) c).getSelection() : null;
        }

        private String getText() {
            return (c instanceof Combo) ? ((Combo) c).getText() : (c instanceof Text) ? ((Text) c).getText() : null;
        }

        private void setText(String t) {
            if (c instanceof Combo) {
                ((Combo) c).setText(t);
            } else if (c instanceof Text) {
                ((Text) c).setText(t);
            }
        }

        private void setSelection() {
            if (c instanceof Combo) {
                ((Combo) c).setSelection(s);
            } else if (c instanceof Text) {
                ((Text) c).setSelection(s);
            }
        }

        void init() {
            clear();
            c = Display.getDefault().getFocusControl();
            if (c != null) {
                t = System.currentTimeMillis();
                s = getSelection();
            }
        }

        boolean isReady() {
            if (c == null) {
                return false;
            }
            if (System.currentTimeMillis() - t > 2000) {
                clear();
                return false;
            }
            return true;
        }

        void apply() {
            if (!isReady()) {
                return;
            }
            Display.getCurrent().asyncExec(new Runnable() {
                public void run() {
                    if (c != null && c != Display.getCurrent().getFocusControl() && isFocusInBrowser()) {
                        if (s != null && missed.length() > 0) {
                            String t = getText();
                            t = t.substring(0, s.x) + missed.toString() + t.substring(s.y);
                            s.x += missed.length();
                            s.y = s.x;
                            setText(t);
                        }
                        c.forceFocus();
                        if (s != null) {
                            setSelection();
                        }
                    }
                    clear();
                }
            });
        }

        @Override
        public void handleEvent(Event event) {
            if (event.type == SWT.MouseDown) {
                clear();
            } else if (event.type == SWT.Modify) {
                if (isReady() && c == Display.getDefault().getFocusControl() && c == event.widget) {
                    s = getSelection();
                }
            } else if (event.type == SWT.KeyDown) {
                if (isReady() && c == Display.getDefault().getFocusControl()) {
                    t = System.currentTimeMillis();
                }
                if (isReady() && event.widget == browser) {
                    char ch = event.character;
                    if ((int) ch >= 32 && (int) ch <= 128) {
                        missed.append(ch);
                    }
                }
            } else if (event.type == SWT.FocusOut) {
                apply();
            }
        }
    }

    int getTextLimit() {
        int c = text.getSize().x - 2;
        if (text.getVerticalBar() != null) {
            int w = text.getVerticalBar().getSize().x;
            if (w > 0) {
                c -= w + 5;
            }
        }
        return c < 20 ? 20 : c;
    }

    int textLimit = -1;

    protected String formatText(String text) {
        return formatText(text, this.text, textLimit = getTextLimit());
    }

    /**
     * Formats xml text for styled text widget with given maximum symbols in line.
     * @param text
     * @param styledText
     * @param max
     * @return
     */
    public static String formatText(String text, StyledText styledText, int max) {
        GC gc = new GC(styledText);
        gc.setFont(styledText.getFont());
        StringBuilder sb = new StringBuilder();
        boolean inQuota = false;
        boolean inTag = false;
        int offset = 0;
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            if (ch == '<' && !inQuota) {
                int n = lookUp(text, i, inTag, false);
                int w = gc.stringExtent(sb.substring(offset, sb.length()) + text.substring(i, n)).x;
                if (w > max) {
                    sb.append("\n");
                    offset = sb.length();
                }
            }
            sb.append(ch);
            if (inTag && ch == '"') {
                inQuota = !inQuota;
            } else if (ch == '<' && !inQuota) {
                inTag = true;
            } else if (ch == '>' && !inQuota) {
                inTag = false;
            } else if (ch == '\n') {
                offset = sb.length();
            }
            if (sb.length() > offset /*&& !inQuota*/ && (ch == ' ' || ch == '>')) {
                int l = lookUp(text, i + 1, inTag, inQuota);
                int w = gc.stringExtent(sb.substring(offset, sb.length()) + text.substring(i, l)).x;
                if (l > i + 1 && w > max) {
                    sb.append("\n");
                    offset = sb.length();
                    if (inTag) {
                        String indent = "        ";
                        if (inQuota)
                            indent += "    ";
                        sb.append(indent);
                    }

                }
            }
        }
        gc.dispose();
        return sb.toString();
    }

    protected static int lookUp(String text, int pos, boolean inTag, boolean inQuota) {
        int res = pos;
        for (; res < text.length(); res++) {
            char ch = text.charAt(res);
            if (ch == '\n')
                return res;
            if (ch == '"' && inTag) {
                inQuota = !inQuota;
            }
            if (!inQuota) {
                if (ch == ' ' || (res > pos && ch == '<'))
                    return res;
                if (ch == '>')
                    return res + 1;
            } else {
                if (ch == ' ' && res > pos + 1)
                    return res;
            }
        }
        return res;
    }

    @Override
    public void dispose() {
        if (sourceFile != null) {
            sourceFile.delete();
            sourceFile = null;
        }
        Display.getDefault().removeFilter(SWT.FocusOut, focusReturn);
        Display.getDefault().removeFilter(SWT.MouseDown, focusReturn);
        Display.getDefault().removeFilter(SWT.KeyDown, focusReturn);
        Display.getDefault().removeFilter(SWT.Modify, focusReturn);
        //      valueColor.dispose();
        //      tagColor.dispose();
        //      attrColor.dispose();
        super.dispose();
    }

    private void resetText() {
        String text = formatText(getWizard().getTextForTextView());
        this.text.setStyleRanges(new StyleRange[0]);
        this.text.setText(text);
        this.text.setStyleRanges(getRanges(text));
        this.text.update();
        this.text.layout();
    }

    static Color valueColor = new Color(null, 42, 0, 255);
    static Color tagColor = new Color(null, 63, 127, 127);
    static Color attrColor = new Color(null, 127, 0, 127);

    /**
     * Creates elementary coloring of xml.
     * @param text
     * @return
     */
    public static StyleRange[] getRanges(String text) {
        ArrayList<StyleRange> regionList = new ArrayList<StyleRange>();
        boolean inQuota = false;
        boolean inTag = false;
        int offset = 0;
        StringBuilder name = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            if (inTag && ch == '"') {
                inQuota = !inQuota;
                if (!inQuota) {
                    addRange(offset, 1, valueColor, false, regionList);
                    if (i - offset > 1) {
                        addRange(offset + 1, i - offset - 1, valueColor, true, regionList);
                    }
                    addRange(i, 1, valueColor, false, regionList);
                } else {
                    offset = i;
                }
            } else if (ch == '>' && !inQuota) {
                inTag = false;
                if (name.length() > 0) {
                    addRange(offset, name.length(), tagColor, false, regionList);
                    name.setLength(0);
                }
                addRange(i, 1, tagColor, false, regionList);
            } else if (ch == '<' && !inQuota) {
                inTag = true;
                name.setLength(0);
                name.append(ch);
                offset = i;
            } else if (!inQuota && inTag && (Character.isLetterOrDigit(ch) || ch == '-' || ch == '/')) {
                if (name.length() == 0) {
                    offset = i;
                }
                name.append(ch);
            } else if (name.length() > 0) {
                Color c = name.charAt(0) == '<' ? tagColor : attrColor;
                addRange(offset, name.length(), c, false, regionList);
                name.setLength(0);
            }

        }
        return (StyleRange[]) regionList.toArray(new StyleRange[0]);
    }

    static void addRange(int offset, int length, Color c, boolean italic, ArrayList<StyleRange> regionList) {
        StyleRange region = new StyleRange(offset, length, c, null);
        if (italic)
            region.fontStyle = SWT.ITALIC;
        regionList.add(region);
    }
}