fr.esrf.icat.manager.core.part.EntityEditDialog.java Source code

Java tutorial

Introduction

Here is the source code for fr.esrf.icat.manager.core.part.EntityEditDialog.java

Source

package fr.esrf.icat.manager.core.part;

/*
 * #%L
 * icat-manager :: core
 * %%
 * Copyright (C) 2014 ESRF - The European Synchrotron
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import net.sf.swtaddons.autocomplete.AutocompleteContentProposalProvider;
import net.sf.swtaddons.autocomplete.AutocompleteSelectorContentProposalProvider;
import net.sf.swtaddons.autocomplete.combo.AutocompleteCombo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposalListener2;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.nebula.widgets.cdatetime.CDT;
import org.eclipse.nebula.widgets.cdatetime.CDateTime;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
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.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.esrf.icat.client.SimpleICATClient;
import fr.esrf.icat.client.wrapper.WrappedEntityBean;
import fr.esrf.icat.manager.core.icatserver.EntityLabelProvider;
import fr.esrf.icat.manager.core.icatserver.EntityListProposalContentProvider;
import fr.esrf.icat.manager.core.icatserver.ICATEntity;

public class EntityEditDialog extends Dialog {

    private final static Logger LOG = LoggerFactory.getLogger(EntityEditDialog.class);

    private final static char[] DEFAULT_ACTIVATION_CHARS = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_12345679890"
            + SWT.BS + SWT.DEL).toCharArray();
    private final static KeyStroke DEFAULT_KEYSTROKE = KeyStroke.getInstance(SWT.CTRL, ' ');
    public final static Image WARNING_IMAGE;
    public final static Image ERROR_IMAGE;
    public final static Image MULTI_IMAGE;

    static {
        Bundle bundle = FrameworkUtil.getBundle(EntityEditDialog.class);
        URL url = FileLocator.find(bundle, new Path("icons/warning.gif"), null);
        WARNING_IMAGE = ImageDescriptor.createFromURL(url).createImage();
        url = FileLocator.find(bundle, new Path("icons/fail.gif"), null);
        ERROR_IMAGE = ImageDescriptor.createFromURL(url).createImage();
        url = FileLocator.find(bundle, new Path("icons/morph2.gif"), null);
        MULTI_IMAGE = ImageDescriptor.createFromURL(url).createImage();
    }

    private List<WrappedEntityBean> entities;
    private final boolean isSingle;
    private SimpleICATClient client;
    private Map<String, Pair<Object[], Combo>> comboMapping;
    private Map<String, Object> fieldValues;

    public EntityEditDialog(final Shell parentShell, final List<WrappedEntityBean> beans,
            final SimpleICATClient client) {
        super(parentShell);
        this.entities = beans;
        this.client = client;
        this.isSingle = (beans.size() == 1);
    }

    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        StringBuilder b = new StringBuilder();
        b.append("Editing ");
        if (isSingle) {
            WrappedEntityBean bean = entities.get(0);
            b.append(bean.getWrapped().getClass().getSimpleName());
            b.append(" ");
            b.append(new EntityLabelProvider().getText(bean));
        } else if (entities.size() > 0) {
            WrappedEntityBean bean = entities.get(0);
            b.append(entities.size());
            b.append(" ");
            b.append(bean.getWrapped().getClass().getSimpleName());
            b.append('s'); // plural
        }
        shell.setText(b.toString());
    }

    @Override
    protected Control createDialogArea(final Composite parent) {
        final Composite container = (Composite) super.createDialogArea(parent);
        GridLayout layout = new GridLayout(3, false);
        layout.marginRight = 5;
        layout.marginLeft = 10;
        container.setLayout(layout);
        comboMapping = new HashMap<>();
        fieldValues = new HashMap<>();
        // we are sure we have at least one entity, use the 1st one for anything general (field types, etc.)
        final WrappedEntityBean firstEntity = entities.get(0);
        for (final String field : firstEntity.getMutableFields()) {
            Label lblAuthn = new Label(container, SWT.NONE);
            lblAuthn.setText(StringUtils.capitalize(field) + ":");
            final Button checkEdit = new Button(container, SWT.CHECK);
            checkEdit.setEnabled(false);
            checkEdit.setVisible(false);
            final Class<?> clazz = firstEntity.getReturnType(field);
            Object initialValue = null;
            boolean notSet = true;
            for (WrappedEntityBean entity : entities) {
                try {
                    Object value = entity.get(field);
                    if (notSet) {
                        initialValue = value;
                        notSet = false;
                    } else if ((null == value && null != initialValue)
                            || (null != value && !value.equals(initialValue))) {
                        initialValue = null;
                        checkEdit.setImage(MULTI_IMAGE);
                        checkEdit.setSelection(false);
                        checkEdit.setEnabled(true);
                        checkEdit.setVisible(true);
                        break;
                    }
                } catch (Exception e) {
                    LOG.error("Error getting initial value for " + field, e);
                }
            }
            final boolean hasInitialValue = initialValue != null;
            if (firstEntity.isEntity(field)) {
                final Combo combo = new Combo(container, SWT.DROP_DOWN | SWT.BORDER);
                new Label(container, SWT.NONE); //empty left label
                final Label label = new Label(container, SWT.RIGHT);
                label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, false));
                label.setImage(WARNING_IMAGE);
                final Label warningLabel = new Label(container, SWT.LEFT);
                warningLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false));
                combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
                final EntityListProposalContentProvider proposalProvider = new EntityListProposalContentProvider(
                        client, firstEntity.getReturnType(field).getSimpleName(), initialValue, label, warningLabel,
                        container);
                warningLabel.setText(proposalProvider.getCurrentFilter());
                final ContentProposalAdapter contentProposalAdapter = new ContentProposalAdapter(combo,
                        new ComboContentAdapter(), proposalProvider, DEFAULT_KEYSTROKE, DEFAULT_ACTIVATION_CHARS);
                contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
                contentProposalAdapter.setPropagateKeys(true);
                contentProposalAdapter.setAutoActivationDelay(1000);
                contentProposalAdapter.addContentProposalListener(new IContentProposalListener2() {
                    @Override
                    public void proposalPopupOpened(ContentProposalAdapter adapter) {
                    }

                    @Override
                    public void proposalPopupClosed(ContentProposalAdapter adapter) {
                        // when the proposal popup closes we set the content of the combo to the proposals
                        final String[] currentItems = proposalProvider.getCurrentItems();
                        if (currentItems != null && currentItems.length > 0) {
                            combo.setItems(currentItems);
                        }
                        final String currentText = proposalProvider.getCurrentText();
                        final int caretPosition = proposalProvider.getCaretPosition();
                        combo.setText(currentText);
                        combo.setSelection(new Point(caretPosition, caretPosition));
                    }
                });
                combo.setItems(proposalProvider.getInitialItems());
                if (hasInitialValue) {
                    combo.select(0);
                }
                comboMapping.put(field,
                        new ImmutablePair<Object[], Combo>(new Object[] { proposalProvider }, combo));
                if (checkEdit.isEnabled()) {
                    combo.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            combo.setEnabled(checkEdit.getSelection());
                        }
                    });
                }

            } else if (Enum.class.isAssignableFrom(clazz)) {
                final Combo combo = new Combo(container, SWT.DROP_DOWN | SWT.BORDER);
                final Object[] c = clazz.getEnumConstants();
                final String[] s = new String[c.length];
                int selected = -1;
                for (int i = 0; i < c.length; i++) {
                    s[i] = c[i].toString();
                    if (initialValue != null && c[i].equals(initialValue)) {
                        selected = i;
                    }
                }
                // replacement for AutocompleteComboSelector to avoid selecting the 1st value in the combo when
                // no proposal is accepted (or field is emptied)
                new AutocompleteCombo(combo) {
                    @Override
                    protected AutocompleteContentProposalProvider getContentProposalProvider(String[] proposals) {
                        return new AutocompleteSelectorContentProposalProvider(proposals, this.combo);
                    }

                };
                combo.setItems(s);
                if (selected >= 0) {
                    combo.select(selected);
                }
                combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
                comboMapping.put(field, new ImmutablePair<Object[], Combo>(c, combo));
                if (checkEdit.isEnabled()) {
                    combo.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            combo.setEnabled(checkEdit.getSelection());
                        }
                    });
                }

            } else if (clazz.equals(Boolean.class) || clazz.equals(boolean.class)) {
                final Button btn = new Button(container, SWT.CHECK);
                btn.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
                if (null == initialValue) {
                    if (isSingle) {
                        try {
                            firstEntity.set(field, Boolean.FALSE);
                        } catch (Exception e) {
                            LOG.error("Error setting " + field + " to " + Boolean.FALSE);
                        }
                    }
                } else {
                    btn.setSelection((Boolean) initialValue);
                }
                btn.addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        boolean value = btn.getSelection();
                        fieldValues.put(field, value);
                    }
                });
                if (checkEdit.isEnabled()) {
                    btn.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            final boolean selected = checkEdit.getSelection();
                            btn.setEnabled(selected);
                            if (selected) {
                                fieldValues.put(field, btn.getSelection());
                            } else {
                                fieldValues.remove(field);
                            }
                        }
                    });
                }

            } else if (Calendar.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz)
                    || XMLGregorianCalendar.class.isAssignableFrom(clazz)) {

                final CDateTime cdt = new CDateTime(container,
                        CDT.BORDER | CDT.SPINNER | CDT.TAB_FIELDS | CDT.DATE_MEDIUM | CDT.TIME_MEDIUM);
                cdt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
                if (null != initialValue) {
                    Date initialDate = null;
                    if (initialValue instanceof Calendar) {
                        initialDate = ((Calendar) initialValue).getTime();
                    } else if (initialValue instanceof XMLGregorianCalendar) {
                        initialDate = ((XMLGregorianCalendar) initialValue).toGregorianCalendar().getTime();
                    } else if (initialValue instanceof Date) {
                        initialDate = (Date) initialValue;
                    }
                    cdt.setSelection(initialDate);
                }

                cdt.addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        fieldValues.put(field, makeCorrectDateValue(clazz, cdt.getSelection()));
                    }
                });
                if (checkEdit.isEnabled()) {
                    cdt.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            final boolean selected = checkEdit.getSelection();
                            cdt.setEnabled(selected);
                            if (selected) {
                                fieldValues.put(field, makeCorrectDateValue(clazz, cdt.getSelection()));
                            } else {
                                fieldValues.remove(field);
                            }
                        }
                    });
                }

            } else if (Number.class.isAssignableFrom(clazz)) {
                final Text text = new Text(container, SWT.BORDER);
                text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
                if (null != initialValue) {
                    text.setText(initialValue.toString());
                }
                final Color original = text.getForeground();
                text.addModifyListener(new ModifyListener() {
                    @Override
                    public void modifyText(ModifyEvent e) {
                        text.setForeground(original);
                        String value = text.getText();
                        if (null == value) {
                            value = ICATEntity.EMPTY_STRING;
                        }
                        final Object numVal = makeCorrectNumericValue(clazz, value);
                        if (null == numVal) {
                            text.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
                        } else {
                            fieldValues.put(field, numVal);
                        }
                    }
                });
                if (checkEdit.isEnabled()) {
                    text.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            final boolean selected = checkEdit.getSelection();
                            text.setEnabled(selected);
                            if (selected) {
                                fieldValues.put(field, makeCorrectNumericValue(clazz, text.getText()));
                            } else {
                                fieldValues.remove(field);
                            }
                        }
                    });
                }

            } else { // Assumes String
                final Text text = new Text(container, SWT.BORDER);
                text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
                if (null == initialValue) {
                    if (isSingle) {
                        try {
                            firstEntity.set(field, ICATEntity.EMPTY_STRING);
                        } catch (Exception e) {
                            LOG.error("Error setting " + field + " to EMPTY_STRING");
                        }
                    }
                } else {
                    text.setText(initialValue.toString());
                }
                text.addModifyListener(new ModifyListener() {
                    @Override
                    public void modifyText(ModifyEvent e) {
                        String value = text.getText();
                        if (null == value) {
                            value = ICATEntity.EMPTY_STRING;
                        }
                        fieldValues.put(field, value);
                    }
                });
                if (checkEdit.isEnabled()) {
                    text.setEnabled(false);
                    checkEdit.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            final boolean selected = checkEdit.getSelection();
                            text.setEnabled(selected);
                            if (selected) {
                                fieldValues.put(field, text.getText());
                            } else {
                                fieldValues.remove(field);
                            }
                        }
                    });
                }
            }
        }
        return container;
    }

    @Override
    protected void cancelPressed() {
        comboMapping = null;
        fieldValues = null;
        super.cancelPressed();
    }

    @Override
    protected void okPressed() {
        for (Entry<String, Pair<Object[], Combo>> entry : comboMapping.entrySet()) {
            final Pair<Object[], Combo> pair = entry.getValue();
            final Combo combo = pair.getRight();
            // added: skip value for disabled combos
            // needed to not apply changed values on multi value field
            // when disabled after change
            if (!combo.isEnabled()) {
                continue;
            }
            final String field = entry.getKey();
            final Object[] left = pair.getLeft();
            final Object[] objects = left[0] instanceof EntityListProposalContentProvider
                    ? ((EntityListProposalContentProvider) left[0]).getCurrentObjects()
                    : left;
            final int index = combo.indexOf(combo.getText());
            Object value = null;
            if (index >= 0) {
                value = objects[index];
            }
            for (WrappedEntityBean entity : entities) {
                try {
                    entity.set(field, value);
                } catch (Exception e) {
                    LOG.error("Error setting " + field + " to " + value, e);
                }
            }
        }
        for (Entry<String, Object> entry : fieldValues.entrySet()) {
            for (WrappedEntityBean entity : entities) {
                try {
                    entity.set(entry.getKey(), entry.getValue());
                } catch (Exception e) {
                    LOG.error("Error setting " + entry.getKey() + " to " + entry.getValue(), e);
                }
            }
        }
        comboMapping = null;
        fieldValues = null;
        super.okPressed();
    }

    private Object makeCorrectDateValue(final Class<?> clazz, final Date date) {
        // null date do not change
        if (null == date)
            return null;
        // calendar
        if (Calendar.class.isAssignableFrom(clazz)) {
            Calendar c = GregorianCalendar.getInstance();
            c.setTime(date);
            return c;
        }
        // xml calendar
        if (clazz.equals(XMLGregorianCalendar.class)) {
            GregorianCalendar c = (GregorianCalendar) GregorianCalendar.getInstance();
            c.setTime(date);
            try {
                return DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
            } catch (DatatypeConfigurationException e) {
                LOG.error("Unable to create XMLGregorianCalendar", e);
                return null;
            }
        }
        // anything else we do not convert
        return date;
    }

    private Object makeCorrectNumericValue(final Class<?> clazz, final String value) {
        if (null == clazz || null == value)
            return null;
        try {
            return clazz.getMethod("valueOf", new Class<?>[] { String.class }).invoke(null, value);
        } catch (Exception e) {
            LOG.error("Error getting {} value from {}", clazz.getSimpleName(), value);
            return null;
        }
    }

}