All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nakedobjects.plugins.dnd.viewer.table.TableCellBuilder Maven / Gradle / Ivy

The newest version!
package org.nakedobjects.plugins.dnd.viewer.table;

import org.apache.log4j.Logger;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.commons.ensure.Assert;
import org.nakedobjects.metamodel.commons.exceptions.UnexpectedCallException;
import org.nakedobjects.metamodel.commons.exceptions.UnknownTypeException;
import org.nakedobjects.metamodel.facets.value.BooleanValueFacet;
import org.nakedobjects.metamodel.facets.value.ImageValueFacet;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociation;
import org.nakedobjects.metamodel.spec.feature.OneToManyAssociation;
import org.nakedobjects.metamodel.spec.feature.OneToOneAssociation;
import org.nakedobjects.plugins.dnd.CompositeViewSpecification;
import org.nakedobjects.plugins.dnd.Content;
import org.nakedobjects.plugins.dnd.ObjectContent;
import org.nakedobjects.plugins.dnd.TextParseableContent;
import org.nakedobjects.plugins.dnd.Toolkit;
import org.nakedobjects.plugins.dnd.View;
import org.nakedobjects.plugins.dnd.ViewAxis;
import org.nakedobjects.plugins.dnd.ViewFactory;
import org.nakedobjects.plugins.dnd.ViewRequirement;
import org.nakedobjects.plugins.dnd.ViewSpecification;
import org.nakedobjects.plugins.dnd.viewer.basic.UnlinedTextFieldSpecification;
import org.nakedobjects.plugins.dnd.viewer.builder.AbstractViewBuilder;
import org.nakedobjects.plugins.dnd.viewer.content.OneToOneFieldImpl;
import org.nakedobjects.plugins.dnd.viewer.content.TextParseableFieldImpl;
import org.nakedobjects.plugins.dnd.viewer.drawing.Location;
import org.nakedobjects.plugins.dnd.viewer.drawing.Padding;
import org.nakedobjects.plugins.dnd.viewer.drawing.Size;
import org.nakedobjects.plugins.dnd.viewer.view.field.CheckboxField;
import org.nakedobjects.plugins.dnd.viewer.view.simple.BlankView;
import org.nakedobjects.plugins.dnd.viewer.view.simple.CompositeViewUsingBuilder;
import org.nakedobjects.plugins.dnd.viewer.view.simple.FieldErrorView;
import org.nakedobjects.runtime.context.NakedObjectsContext;


class TableCellBuilder extends AbstractViewBuilder {
    private static final Logger LOG = Logger.getLogger(TableCellBuilder.class);

    private void addField(final View view, final NakedObject object, final NakedObjectAssociation field) {
        final NakedObject value = field.get(object);
        View fieldView;
        fieldView = createFieldView(view, object, field, value);
        if (fieldView != null) {
            view.addView(decorateSubview(fieldView));
        } else {
            view.addView(new FieldErrorView("No field for " + value));
        }
    }

    @Override
    public void build(final View view) {
        Assert.assertEquals("ensure the view is complete decorated view", view.getView(), view);

        final Content content = view.getContent();
        final NakedObject object = ((ObjectContent) content).getObject();

        final TableAxis viewAxis = (TableAxis) view.getViewAxis();

        if (view.getSubviews().length == 0) {
            buildNew(object, view, viewAxis);
        } else {
            buildUpdate(object, view, viewAxis);
        }
    }

    private void buildUpdate(final NakedObject object, final View view, final TableAxis viewAxis) {
        LOG.debug("update view " + view + " for " + object);
        final View[] subviews = view.getSubviews();
        final NakedObjectSpecification spec = object.getSpecification();
        for (int i = 0; i < subviews.length; i++) {
            final NakedObjectAssociation field = fieldFromActualSpec(spec, viewAxis.getFieldForColumn(i));
            final View subview = subviews[i];
            final NakedObject value = field.get(object);

            // if the field is parseable then it may have been modified; we need to replace what was
            // typed in with the actual title.
            if (field.getSpecification().isParseable()) {
                final boolean visiblityChange = !field.isVisible(NakedObjectsContext.getAuthenticationSession(), object).isAllowed()
                        ^ (subview instanceof BlankView);
                final NakedObject nakedObject = subview.getContent().getNaked();
                final boolean valueChange = value != null && value.getObject() != null
                        && !value.getObject().equals(nakedObject.getObject());

                if (visiblityChange || valueChange) {
                    final View fieldView = createFieldView(view, object, field, value);
                    view.replaceView(subview, decorateSubview(fieldView));
                }
                subview.refresh();
            } else if (field.isOneToOneAssociation()) {
                final NakedObject existing = ((ObjectContent) subviews[i].getContent()).getObject();
                final boolean changedValue = value != existing;
                if (changedValue) {
                    View fieldView;
                    fieldView = createFieldView(view, object, field, value);
                    if (fieldView != null) {
                        view.replaceView(subview, decorateSubview(fieldView));
                    } else {
                        view.addView(new FieldErrorView("No field for " + value));
                    }
                }
            }
        }
    }

    private NakedObjectAssociation fieldFromActualSpec(final NakedObjectSpecification spec, final NakedObjectAssociation field) {
        final String fieldName = field.getId();
        return spec.getAssociation(fieldName);
    }

    private void buildNew(final NakedObject object, final View view, final TableAxis viewAxis) {
        LOG.debug("build view " + view + " for " + object);
        final int len = viewAxis.getColumnCount();
        final NakedObjectSpecification spec = object.getSpecification();
        for (int f = 0; f < len; f++) {
            final NakedObjectAssociation field = fieldFromActualSpec(spec, viewAxis.getFieldForColumn(f));
            addField(view, object, field);
        }
    }

    public View createCompositeView(final Content content, final CompositeViewSpecification specification, final ViewAxis axis) {
        return new CompositeViewUsingBuilder(content, specification, axis);
    }

    private View createFieldView(
            final View view,
            final NakedObject object,
            final NakedObjectAssociation field,
            final NakedObject value) {
        if (field == null) {
            throw new NullPointerException();
        }
        final ViewFactory factory = Toolkit.getViewFactory();
        ViewSpecification cellSpec;
        Content content;
        if (field instanceof OneToManyAssociation) {
            throw new UnexpectedCallException("no collections allowed");
        } else if (field instanceof OneToOneAssociation) {

            final NakedObjectSpecification fieldSpecification = field.getSpecification();
            if (fieldSpecification.isParseable()) {
                content = new TextParseableFieldImpl(object, value, (OneToOneAssociation) field);
                // REVIEW how do we deal with IMAGES?
                if (content.getNaked() instanceof ImageValueFacet) {
                    return new BlankView(content);
                }

                if (!field.isVisible(NakedObjectsContext.getAuthenticationSession(), object).isAllowed()) {
                    return new BlankView(content);
                }
                if (((TextParseableContent) content).getNoLines() > 0) {
                    /*
                     * TODO remove this after introducing constraints into view specs that allow the parent
                     * view to specify what kind of subviews it can deal
                     */
                    
                    if (fieldSpecification.containsFacet(BooleanValueFacet.class)) {
                        cellSpec = new CheckboxField.Specification();
                    } else {
                        cellSpec = new UnlinedTextFieldSpecification();
                    }
                } else {
                    cellSpec = factory.getValueFieldSpecification((TextParseableContent) content);
                }
            } else {
                content = new OneToOneFieldImpl(object, value, (OneToOneAssociation) field);
                if (!field.isVisible(NakedObjectsContext.getAuthenticationSession(), object).isAllowed()) {
                    return new BlankView(content);
                }
                cellSpec = factory.getIconizedSubViewSpecification(content);
                return factory.createView(new ViewRequirement(content, view.getViewAxis(), ViewRequirement.CLOSED |  ViewRequirement.SUBVIEW));
                
            }

        } else {
            throw new UnknownTypeException(field);
        }

        final ViewAxis axis = view.getViewAxis();
        return cellSpec.createView(content, axis);
    }

    @Override
    public Size getRequiredSize(final View row) {
        int maxHeight = 0;
        int totalWidth = 0;
        final TableAxis axis = ((TableAxis) row.getViewAxis());
        final View[] cells = row.getSubviews();
        final int maxBaseline = maxBaseline(cells);

        for (int i = 0; i < cells.length; i++) {
            totalWidth += axis.getColumnWidth(i);

            final Size s = cells[i].getRequiredSize(new Size());
            final int b = cells[i].getBaseline();
            final int baselineOffset = Math.max(0, maxBaseline - b);
            maxHeight = Math.max(maxHeight, s.getHeight() + baselineOffset);
        }

        return new Size(totalWidth, maxHeight);
    }

    @Override
    public void layout(final View row, final Size maximumSize) {
        int x = 0;

        // int rowHeight = row.getSize().getHeight();
        final TableAxis axis = ((TableAxis) row.getViewAxis());
        final View[] cells = row.getSubviews();
        final int maxBaseline = maxBaseline(cells);

        for (int i = 0; i < cells.length; i++) {
            final View cell = cells[i];
            final Size s = cell.getRequiredSize(new Size(maximumSize));
            s.setWidth(axis.getColumnWidth(i));
            // s.setHeight(rowHeight);
            cell.setSize(s);

            final int b = cell.getBaseline();
            final int baselineOffset = Math.max(0, maxBaseline - b);
            cell.setLocation(new Location(x, baselineOffset));

            x += s.getWidth();
        }

        final Padding padding = row.getPadding();
        final Size size = new Size(padding.getLeftRight(), padding.getTopBottom());
        row.setSize(size);
    }

    private int maxBaseline(final View[] cells) {
        int maxBaseline = 0;
        for (int i = 0; i < cells.length; i++) {
            final View cell = cells[i];
            maxBaseline = Math.max(maxBaseline, cell.getBaseline());
        }
        return maxBaseline;
    }
}
// Copyright (c) Naked Objects Group Ltd.




© 2015 - 2025 Weber Informatics LLC | Privacy Policy