org.eclipse.richbeans.generator.TableWidgetBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.richbeans.generator.TableWidgetBuilder.java

Source

/*-
 * Copyright  2016 Diamond Light Source Ltd.
 *
 * This file is part of GDA.
 *
 * GDA is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License version 3 as published by the Free
 * Software Foundation.
 *
 * GDA is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with GDA. If not, see <http://www.gnu.org/licenses/>.
 */

package org.eclipse.richbeans.generator;

import static org.eclipse.richbeans.generator.RichbeansAnnotationsInspector.DELETE_METHOD;
import static org.eclipse.richbeans.generator.RichbeansAnnotationsInspector.MAXIMUM_VALUE;
import static org.eclipse.richbeans.generator.RichbeansAnnotationsInspector.MINIMUM_VALUE;
import static org.metawidget.inspector.InspectionResultConstants.ACTION;
import static org.metawidget.inspector.InspectionResultConstants.HIDDEN;
import static org.metawidget.inspector.InspectionResultConstants.NAME;
import static org.metawidget.inspector.InspectionResultConstants.TRUE;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.beans.IBeanValueProperty;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.metawidget.swt.SwtMetawidget;
import org.metawidget.util.ClassUtils;
import org.metawidget.util.WidgetBuilderUtils;
import org.metawidget.util.XmlUtils;
import org.metawidget.widgetbuilder.iface.WidgetBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TableWidgetBuilder implements WidgetBuilder<Control, SwtMetawidget> {

    private final Logger logger = LoggerFactory.getLogger(TableWidgetBuilder.class);

    @Override
    public Control buildWidget(String elementName, Map<String, String> attributes, SwtMetawidget metawidget) {

        // If hidden or an action, return null
        if (TRUE.equals(attributes.get(HIDDEN)) || ACTION.equals(elementName)) {
            return null;
        }

        // Otherwise get the type and if a List, build a table
        Class<?> container = WidgetBuilderUtils.getActualClassOrType(attributes, Object.class);
        String contained = WidgetBuilderUtils.getComponentType(attributes);
        Class<?> containedClazz = loadContainedClass(contained);
        Method deleteMethod = getMethod(metawidget.getToInspect(), containedClazz, attributes);

        if (List.class.isAssignableFrom(container) && contained != null && containedClazz != null) {
            TableViewer tableViewer = new TableViewer(metawidget);
            Table table = tableViewer.getTable();
            table.setHeaderVisible(true);
            table.setLinesVisible(true);
            tableViewer.setContentProvider(new ListStructuredContentProvider());

            List<TableColumnModel> columns = readPropertiesFromType(metawidget, contained);
            createColumns(columns, tableViewer);
            createDeleteButtons(tableViewer, deleteMethod, metawidget.getToInspect());

            setupDataInput(containedClazz, columns, attributes, metawidget, tableViewer);

            return tableViewer.getControl();
        }
        return null;
    }

    private Method getMethod(Object toInspect, Class<?> contained, Map<String, String> attributes) {
        String methodName = attributes.get(DELETE_METHOD);
        if (toInspect != null && contained != null && methodName != null) {
            try {
                return toInspect.getClass().getMethod(methodName, contained);
            } catch (NoSuchMethodException | SecurityException e) {
                logger.warn("couldn't find specified delete method", e);
            }
        }
        return null;
    }

    private Class<?> loadContainedClass(String contained) {
        if (contained != null) {
            return ClassUtils.niceForName(contained);
        }
        return null;
    }

    private void setupDataInput(Class<?> containedClazz, List<TableColumnModel> columns,
            Map<String, String> attributes, SwtMetawidget metawidget, TableViewer tableViewer) {
        Object toInspect = metawidget.getToInspect();

        String propertyName = attributes.get(NAME);
        IBeanValueProperty value = BeanProperties.value(toInspect.getClass(), propertyName);

        Realm realm = DisplayRealm.getRealm(metawidget.getDisplay());
        IObservableValue observableValue = value.observe(realm, toInspect);

        List<IBeanValueProperty> itemProperties = columns.stream().map(column -> column.getName())
                .map(property -> BeanProperties.value(containedClazz, property)).collect(Collectors.toList());

        observableValue.addValueChangeListener(new IValueChangeListener() {
            @Override
            public void handleValueChange(ValueChangeEvent event) {
                listenToItems(tableViewer, toInspect, value, realm, itemProperties);
                tableViewer.setInput(value.getValue(toInspect));
                tableViewer.refresh();
            }
        });

        listenToItems(tableViewer, toInspect, value, realm, itemProperties);
        tableViewer.setInput(value.getValue(toInspect));
    }

    private void listenToItems(TableViewer tableViewer, Object toInspect, IBeanValueProperty value, Realm realm,
            List<IBeanValueProperty> itemProperties) {
        for (Object item : (List<?>) value.getValue(toInspect)) {
            for (IBeanValueProperty itemValue : itemProperties) {
                IObservableValue observableItem = itemValue.observe(realm, item);
                observableItem.addValueChangeListener((event) -> tableViewer.refresh());
            }
        }
    }

    private void createColumns(List<TableColumnModel> columns, TableViewer tableViewer) {
        for (TableColumnModel column : columns.stream().filter(column -> !column.isHidden())
                .collect(Collectors.toList())) {
            TableViewerColumn columnViewer = new TableViewerColumn(tableViewer, SWT.NONE);
            columnViewer.getColumn().setText(column.getLabel());
            columnViewer.setLabelProvider(new TableColumnLabelProvider(column.getName()));
            columnViewer.setEditingSupport(
                    new TableCellEditingSupport(columnViewer.getViewer(), tableViewer.getTable(), column));
            columnViewer.getColumn().pack();
        }
    }

    private void createDeleteButtons(TableViewer tableViewer, Method action, Object toInspect) {
        if (action != null) {
            TableViewerColumn columnViewer = new TableViewerColumn(tableViewer, SWT.NONE);
            columnViewer.setLabelProvider(new DeleteLableProvider(action, toInspect));
            columnViewer.getColumn().pack();
        }
    }

    private List<TableColumnModel> readPropertiesFromType(SwtMetawidget metawidget, String componentType) {
        String inspectedType = metawidget.inspect(null, componentType, (String[]) null);

        List<TableColumnModel> columns = new ArrayList<>();
        Element root = XmlUtils.documentFromString(inspectedType).getDocumentElement();
        NodeList elements = root.getFirstChild().getChildNodes();

        for (int i = 0; i < elements.getLength(); i++) {
            Node node = elements.item(i);
            Map<String, String> attributesAsMap = XmlUtils.getAttributesAsMap(node);
            TableColumnModel model = new TableColumnModel(attributesAsMap.get(NAME),
                    metawidget.getLabelString(attributesAsMap), attributesAsMap.get(HIDDEN),
                    attributesAsMap.get(MINIMUM_VALUE), attributesAsMap.get(MAXIMUM_VALUE));
            columns.add(model);
        }
        return columns;
    }
}