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