// ============================================================================ // // Copyright (C) 2006-2016 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package com.amalto.workbench.widgets; import java.util.LinkedHashMap; import java.util.Map; import java.util.regex.Pattern; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.forms.widgets.FormToolkit; import com.amalto.workbench.dialogs.AnnotationLanguageLabelsDialog; import com.amalto.workbench.editors.AMainPageV2; import com.amalto.workbench.i18n.Messages; import com.amalto.workbench.image.EImage; import com.amalto.workbench.image.ImageCache; import com.amalto.workbench.utils.Util; /** * This class is meant to work out a composite populated with label, button, text which stand next to each other the * composite will in the parent composite holder * * @author fliu * */ public class DescAnnotationComposite implements SelectionListener { private Button annotationButton; private Text descriptionText; private Composite descAntionHolder; private AMainPageV2 accommodation; private String descriptionValue; private String dlgTitle; private LinkedHashMap<String, String> dataStore = new LinkedHashMap<String, String>(); private TableColumn column; private GridData textGD; private static final String REGEXP_METACHARACTERS = "\\[([\\w]+)[\\s]*:[\\s]*([^]]*)\\]";//$NON-NLS-1$ private static final Pattern DESC_PATTERN = Pattern.compile(REGEXP_METACHARACTERS); public DescAnnotationComposite(String labelName, String buttonName, FormToolkit toolkit, Composite parent, AMainPageV2 dialog, boolean isBtnRight) { descAntionHolder = toolkit.createComposite(parent); descAntionHolder.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1)); GridLayout layout = new GridLayout(3, false); layout.marginWidth = 0; layout.marginLeft = 0; layout.marginTop = 0; layout.marginHeight = 0; layout.marginBottom = 0; descAntionHolder.setLayout(layout); if (labelName != null && labelName.length() > 0) { Label descriptionLabel = toolkit.createLabel(descAntionHolder, labelName, SWT.NULL); descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true, 1, 1)); } if (isBtnRight) { descriptionText = toolkit.createText(descAntionHolder, "", SWT.BORDER);//$NON-NLS-1$ textGD = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); descriptionText.setLayoutData(textGD); descriptionText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if (accommodation != null && descriptionValue != null && !descriptionValue.equals(descriptionText.getText())) { accommodation.markDirtyWithoutCommit(); } descriptionValue = descriptionText.getText(); fillDataStore(descriptionText.getText()); } }); annotationButton = toolkit.createButton(descAntionHolder, "", SWT.PUSH);//$NON-NLS-1$ annotationButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); annotationButton.addSelectionListener(this); annotationButton.setImage(ImageCache.getCreatedImage(EImage.DOTS_BUTTON.getPath())); annotationButton.setToolTipText(Messages.DescAnnotationComposite_AnnoBtnDesc); } else { annotationButton = toolkit.createButton(descAntionHolder, "", SWT.PUSH);//$NON-NLS-1$ annotationButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); annotationButton.addSelectionListener(this); annotationButton.setImage(ImageCache.getCreatedImage(EImage.DOTS_BUTTON.getPath())); annotationButton.setToolTipText(Messages.DescAnnotationComposite_AnnoBtnDesc); descriptionText = toolkit.createText(descAntionHolder, "", SWT.BORDER);//$NON-NLS-1$ textGD = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); descriptionText.setLayoutData(textGD); descriptionText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if (accommodation != null && descriptionValue != null && !descriptionValue.equals(descriptionText.getText())) { accommodation.markDirtyWithoutCommit(); } descriptionValue = descriptionText.getText(); fillDataStore(descriptionText.getText()); } }); } // Util.createCompDropTarget(descriptionText); accommodation = dialog; dlgTitle = Messages.DescAnnotationComposite_AnnoBtnDesc; } public void setAnnotationDialogTitle(String title) { dlgTitle = title; } public void setText(String text) { descriptionText.setText(text); descriptionValue = text; fillDataStore(text); } public static boolean isLetter(char c) { boolean result = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); return result; } /** * Parse a multiple language string. * * s is expected to be in the following format: * * [en:...][fr:...][zh:...] * * Characters ] and \ can be escaped in these using backslash escapes, for example * * [en: a message with a \] character in the middle] * * A message for a language can also be embedded anywhere in the string, for example * * abcd[en:...]abcd[fr:...]abcd * * The map between language code and message is stored in m. * * @param s Multiple language message string to be parsed * @param m Map between language codes and messages in which to store results */ public static void parseMultiLanguageString(String s, Map<String, String> m) { if (s != null && m != null) { // Parse states final byte PARSE_ERROR = 0; final byte LOOKING_FOR_OPENING_BRACKET = 1; final byte LOOKING_FOR_COUNTRY_CODE_FIRST_CHAR = 2; final byte LOOKING_FOR_COUNTRY_CODE_SECOND_CHAR = 3; final byte LOOKING_FOR_COLON = 4; final byte LOOKING_FOR_CLOSING_BRACKET = 5; final byte ENCOUNTERED_FIRST_BACKSLASH = 6; byte parseState = LOOKING_FOR_OPENING_BRACKET; StringBuffer countryCodeBuffer = new StringBuffer(); // string buffer for constructing current country code StringBuffer messageBuffer = new StringBuffer(); // string buffer for constructing current error message for (int i = 0, l = s.length(); i < l && parseState != PARSE_ERROR; ++i) { char c = s.charAt(i); switch (parseState) { case LOOKING_FOR_OPENING_BRACKET: if (c == '[') { parseState = LOOKING_FOR_COUNTRY_CODE_FIRST_CHAR; } break; case LOOKING_FOR_COUNTRY_CODE_FIRST_CHAR: if (isLetter(c)) { countryCodeBuffer.append(c); parseState = LOOKING_FOR_COUNTRY_CODE_SECOND_CHAR; } else { parseState = LOOKING_FOR_OPENING_BRACKET; } break; case LOOKING_FOR_COUNTRY_CODE_SECOND_CHAR: if (isLetter(c)) { countryCodeBuffer.append(c); parseState = LOOKING_FOR_COLON; } else { countryCodeBuffer = new StringBuffer(); parseState = LOOKING_FOR_OPENING_BRACKET; } break; case LOOKING_FOR_COLON: if (c == ':') { parseState = LOOKING_FOR_CLOSING_BRACKET; } else { countryCodeBuffer = new StringBuffer(); parseState = LOOKING_FOR_OPENING_BRACKET; } break; case LOOKING_FOR_CLOSING_BRACKET: if (c == ']') { String countryCode = countryCodeBuffer.toString().toLowerCase(); if (Util.iso2lang.get(countryCode) != null) { m.put(countryCode, messageBuffer.toString()); } countryCodeBuffer = new StringBuffer(); messageBuffer = new StringBuffer(); parseState = LOOKING_FOR_OPENING_BRACKET; } else if (c == '\\') { parseState = ENCOUNTERED_FIRST_BACKSLASH; } else { messageBuffer.append(c); } break; case ENCOUNTERED_FIRST_BACKSLASH: if (c == '\\' || c == ']') { messageBuffer.append(c); } parseState = LOOKING_FOR_CLOSING_BRACKET; break; default: parseState = PARSE_ERROR; } } } } /** * Encode multi-language message as a string using format [cc:mmm][cc:mmm] where cc is the language code and mmm is * the user specified message. ']' and '\' are automatically backslash escaped. * * @param m Map between two letter language code and message in that language * @return Multi-language message encoded as a string, with ']' and '\' escaped */ public static String escapeMultiLanguageString(Map<String, String> m) { StringBuffer resultBuffer = new StringBuffer(); if (m != null) { for (Map.Entry<String, String> entry : m.entrySet()) { String k = entry.getKey(); String v = entry.getValue(); if (k != null) { k = k.toLowerCase(); if (Util.iso2lang.get(k) != null) { resultBuffer.append('['); resultBuffer.append(k.toUpperCase()); resultBuffer.append(':'); if (v != null) { for (int i = 0, l = v.length(); i < l; ++i) { char c = v.charAt(i); if (c == '\\' || c == ']') { resultBuffer.append('\\'); } resultBuffer.append(c); } } resultBuffer.append(']'); } } } } return resultBuffer.toString(); } private void fillDataStore(String text) { dataStore.clear(); parseMultiLanguageString(text, dataStore); } public String getText() { return descriptionText.getText(); } public Text getTextWidget() { return descriptionText; } public void widgetSelected(SelectionEvent e) { AnnotationLanguageLabelsDialog dlg = new AnnotationLanguageLabelsDialog(dataStore, new DescAnnotationListener(), descriptionText.getShell(), dlgTitle); dlg.setBlockOnOpen(true); dlg.open(); if (dlg.getReturnCode() == Window.OK) { dlg.close(); } } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { }; public String commitChange() { return descriptionText.getText(); } public Composite getComposite() { return descAntionHolder; } private class DescAnnotationListener implements SelectionListener { public DescAnnotationListener() { super(); } public void widgetSelected(SelectionEvent e) { AnnotationLanguageLabelsDialog dlg = (AnnotationLanguageLabelsDialog) ((Widget) e.getSource()).getData("dialog");//$NON-NLS-1$ if (dlg.getReturnCode() == Window.OK) { String outPut = "";//$NON-NLS-1$ outPut = DescAnnotationComposite.escapeMultiLanguageString(dataStore); if (!outPut.equals(descriptionText.getText())) { descriptionText.setText(outPut); if (accommodation != null) { accommodation.markDirtyWithoutCommit(); } } } dlg.close(); } public void widgetDefaultSelected(SelectionEvent e) { }; } public TableColumn getColumn() { return column; } public void setColumn(TableColumn column) { this.column = column; resetWidth(); } public void resetWidth() { if (column != null) { textGD.widthHint = column.getWidth() - 35; } } public void setEnable(boolean enable) { annotationButton.setEnabled(enable); descriptionText.setEnabled(enable); } }