de.metas.ui.web.vaadin.window.view.AbstractView.java Source code

Java tutorial

Introduction

Here is the source code for de.metas.ui.web.vaadin.window.view.AbstractView.java

Source

package de.metas.ui.web.vaadin.window.view;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import org.slf4j.Logger;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.vaadin.server.ErrorEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Notification;

import de.metas.logging.LogManager;
import de.metas.ui.web.vaadin.window.editor.Editor;
import de.metas.ui.web.vaadin.window.editor.EditorFactory;
import de.metas.ui.web.vaadin.window.editor.GridEditor;
import de.metas.ui.web.window.PropertyName;
import de.metas.ui.web.window.shared.datatype.NullValue;
import de.metas.ui.web.window.shared.datatype.PropertyPath;
import de.metas.ui.web.window.shared.datatype.PropertyValuesDTO;
import de.metas.ui.web.window.shared.descriptor.ViewPropertyDescriptor;

/*
 * #%L
 * metasfresh-webui
 * %%
 * Copyright (C) 2016 metas GmbH
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-2.0.html>.
 * #L%
 */

/**
 * Base class for {@link WindowView} implementations.
 * 
 * @author metas-dev <dev@metasfresh.com>
 *
 */
public abstract class AbstractView implements WindowView {
    // services
    private static final Logger logger = LogManager.getLogger(AbstractView.class);
    protected final EditorFactory editorFactory = new EditorFactory();

    private final Component content;

    //
    // Editors (UI)
    private Editor _rootPropertyEditor = null;
    private Set<Editor> _allRootEditors = new LinkedHashSet<>();
    private Map<PropertyName, Editor> _propertyName2editor = ImmutableMap.of();

    /** Listens editors and forwards to {@link WindowViewListener} */
    private final WindowViewListener2EditorListenerWrapper editorListener = new WindowViewListener2EditorListenerWrapper();

    public AbstractView() {
        super();

        content = createUI();
        Preconditions.checkNotNull(content, "content cannot be null");
        content.setErrorHandler(event -> showError(event));
    }

    protected abstract Component createUI();

    @Override
    public final Component getComponent() {
        return content;
    }

    protected final void registerEditor(final Editor editor) {
        Preconditions.checkNotNull(editor, "editor");
        if (!_allRootEditors.add(editor)) {
            // already added
            return;
        }

        // Set editor listener
        for (final Editor e : editorFactory.getAllWatchedPropertyNamesAndEditors(editor).values()) {
            e.setEditorListener(editorListener);
        }

        // Rebuild editors map
        rebuildEditorsMap();
    }

    protected final void unregisterEditor(final Editor editor) {
        if (editor == null) {
            return;
        }

        if (!_allRootEditors.remove(editor)) {
            return; // already unregistered or never registered
        }

        rebuildEditorsMap();
    }

    private final void rebuildEditorsMap() {
        logger.debug("Rebuilding editors map");
        final Map<PropertyName, Editor> propertyName2editorOld = _propertyName2editor;

        final ImmutableMap.Builder<PropertyName, Editor> editorsCollector = ImmutableMap.builder();
        for (final Editor registeredRootEditor : getRegisteredEditors()) {
            for (final Map.Entry<PropertyName, Editor> e : editorFactory
                    .getAllWatchedPropertyNamesAndEditors(registeredRootEditor).entrySet()) {
                final PropertyName propertyName = e.getKey();
                final Editor editor = e.getValue();
                logger.debug("Adding editor to map: {} = {} (root: {})", propertyName, editor,
                        registeredRootEditor);
                editorsCollector.put(propertyName, editor);
            }
        }
        final Map<PropertyName, Editor> propertyName2editorNew = editorsCollector.build();

        if (Objects.equals(propertyName2editorOld, propertyName2editorNew)) {
            // nothing changed
            return;
        }

        this._propertyName2editor = propertyName2editorNew;
        updateUI_OnEditorsChanged();
        fireSubscribeToValueChangesEvent();
    }

    protected void updateUI_OnEditorsChanged() {
        // nothing on this level
    }

    private Set<Editor> getRegisteredEditors() {
        return _allRootEditors;
    }

    @Override
    public final void setRootPropertyDescriptor(final ViewPropertyDescriptor rootPropertyDescriptor) {
        //
        // Create all editors recursively
        final Editor rootEditor;
        if (rootPropertyDescriptor != null) {
            rootEditor = editorFactory.createEditorsRecursivelly(rootPropertyDescriptor);
            if (rootEditor == null) {
                throw new IllegalStateException("No editor was created");
            }
        } else {
            rootEditor = null;
        }

        unregisterEditor(_rootPropertyEditor);

        this._rootPropertyEditor = rootEditor;
        updateUI_OnRootPropertyEditorChanged(rootEditor);

        if (rootEditor != null) {
            registerEditor(rootEditor);
        }
    }

    protected abstract void updateUI_OnRootPropertyEditorChanged(final Editor rootEditor);

    @Override
    public void setListener(final WindowViewListener listener) {
        final WindowViewListener listenerOld = editorListener.getWindowViewListener();
        if (listener == listenerOld) {
            return;
        }

        if (listenerOld != null) {
            listenerOld.viewSubscribeToValueChanges(ImmutableSet.of());
        }

        this.editorListener.setWindowViewListener(listener);
        fireSubscribeToValueChangesEvent();
    }

    protected final WindowViewListener getWindowViewListener() {
        return editorListener.getWindowViewListener();
    }

    private void fireSubscribeToValueChangesEvent() {
        final WindowViewListener listener = getWindowViewListener();
        if (listener != null) {
            final Set<PropertyName> watchedPropertyNames = getWatchedPropertyNames();
            listener.viewSubscribeToValueChanges(watchedPropertyNames);
        }
    }

    @Override
    public final void setProperties(final PropertyValuesDTO propertiesAsMap) {
        logger.trace("Setting all properties from {}", propertiesAsMap);
        for (final Map.Entry<PropertyName, Object> entry : propertiesAsMap.entrySet()) {
            try {
                final PropertyName propertyName = entry.getKey();
                final Object value = entry.getValue();
                setProperty(propertyName, value);
            } catch (Exception e) {
                // TODO: handle the error
                e.printStackTrace();
            }
        }
    }

    @Override
    public void setProperty(PropertyPath propertyPath, Object value) {
        if (propertyPath.isGridProperty()) {
            setGridProperty(propertyPath.getGridPropertyName(), propertyPath.getRowId(),
                    propertyPath.getPropertyName(), value);
        } else {
            setProperty(propertyPath.getPropertyName(), value);
        }
    }

    private final void setProperty(final PropertyName propertyName, Object value) {
        logger.trace("Setting propery: {}={}", propertyName, value);
        final Editor editor = getEditor(propertyName);
        if (editor == null) {
            // TODO: handle missing editor
            logger.trace("Skip setting {} because there is no editor for it", propertyName);
            return;
        }

        if (NullValue.isNull(value)) {
            value = null;
        }

        editor.setValue(propertyName, value);
    }

    private final void setGridProperty(final PropertyName gridPropertyName, final Object rowId,
            final PropertyName propertyName, Object value) {
        logger.trace("Setting grid propery {}, {}: {}={}", gridPropertyName, rowId, propertyName, value);

        final GridEditor editor = getGridEditor(gridPropertyName);
        if (editor == null) {
            // TODO: handle missing editor
            logger.trace("Skip setting {} because there is no editor for it", gridPropertyName);
            return;
        }

        if (NullValue.isNull(value)) {
            value = null;
        }

        editor.setValueAt(rowId, propertyName, value);
    }

    private Set<PropertyName> getWatchedPropertyNames() {
        return _propertyName2editor.keySet();
    }

    protected final Editor getEditor(final PropertyName propertyName) {
        return _propertyName2editor.get(propertyName);
    }

    protected final Collection<Editor> getAllEditors() {
        return _propertyName2editor.values();
    }

    private final GridEditor getGridEditor(final PropertyName gridPropertyName) {
        final Editor editor = getEditor(gridPropertyName);
        if (editor instanceof GridEditor) {
            return (GridEditor) editor;
        }
        return null;
    }

    @Override
    public final void gridNewRow(PropertyName gridPropertyName, Object rowId, PropertyValuesDTO rowValues) {
        logger.trace("Creating new grid row {}, {} with values: {}", gridPropertyName, rowId, rowValues);

        final GridEditor editor = getGridEditor(gridPropertyName);
        if (editor == null) {
            // TODO: handle missing editor
            logger.trace("Skip {} because there is no editor for it", gridPropertyName);
            return;
        }

        editor.newRow(rowId, rowValues);
    }

    @Override
    public void commitChanges() {
        // TODO Auto-generated method stub
        logger.info("Commiting field changes (TODO)");
    }

    @Override
    public void confirmDiscardChanges() {
        // TODO Auto-generated method stub
    }

    @Override
    public void showError(final String message) {
        try {
            Notification.show(message, Notification.Type.WARNING_MESSAGE);
        } catch (Exception e) {
            logger.error("Failed displaying error message: {}", message, e);
        }
    }

    private void showError(final ErrorEvent event) {
        final Throwable ex = event.getThrowable();
        logger.warn("Got error", ex);

        final String errorMessage = Throwables.getRootCause(ex).getLocalizedMessage();
        showError(errorMessage);
    }

}