uk.q3c.krail.core.user.opt.DefaultOptionPopup.java Source code

Java tutorial

Introduction

Here is the source code for uk.q3c.krail.core.user.opt.DefaultOptionPopup.java

Source

/*
 * Copyright (c) 2015. David Sowerby
 *
 * 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.
 */

package uk.q3c.krail.core.user.opt;

import com.google.inject.Inject;
import com.vaadin.ui.*;
import org.reflections.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.q3c.krail.core.ui.DataTypeToUI;
import uk.q3c.krail.i18n.I18NKey;
import uk.q3c.krail.i18n.LabelKey;
import uk.q3c.krail.i18n.Translate;
import uk.q3c.util.ID;

import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * Default implementation for {@link OptionPopup}
 * <p>
 * Created by David Sowerby on 29/05/15.
 */
public class DefaultOptionPopup implements OptionPopup {
    private static Logger log = LoggerFactory.getLogger(DefaultOptionPopup.class);
    private OptionContext activeContext;
    private Set<Field> contextFields;
    private DataTypeToUI dataTypeToUI;
    private Translate translate;
    private Window window;

    @Inject
    public DefaultOptionPopup(DataTypeToUI dataTypeToUI, Translate translate) {
        this.dataTypeToUI = dataTypeToUI;
        this.translate = translate;
    }

    @Override
    public void popup(@Nonnull OptionContext context, I18NKey windowCaption) {

        // changing context, so we need to clear the context fields
        if (context != activeContext) {
            contextFields = null;
            if (window != null) {
                window.close();
            }
        }

        Option option = context.getOption();
        window = new Window();

        window.setCaption(windowCaption(windowCaption));

        Map<OptionKey, Class<?>> keys = contextKeys(context);
        GridLayout baseLayout = new GridLayout(2, keys.size());
        baseLayout.setSizeUndefined();

        if (keys.size() == 0) {

            Label label = new Label(translate.from(LabelKey.No_Options_to_Show));
            baseLayout.addComponent(label, 0, 0);
        } else {
            calculateWindowSize(window, keys.size());
            int row = 0;
            for (OptionKey key : keys.keySet()) {
                Object value = option.get(key);
                AbstractField uiField = dataTypeToUI.componentFor(value);
                uiField.setCaption(translate.from(key.getKey()));
                uiField.setDescription(translate.from(key.getDescriptionKey()));
                uiField.setId(ID.getId(Optional.of(((Enum) key.getKey()).name()), this, uiField));
                log.debug("Component id for '{}' set to: '{}'", uiField.getCaption(), uiField.getId());
                //noinspection unchecked
                uiField.setValue(value);
                uiField.addValueChangeListener(event -> {
                    option.set(uiField.getValue(), key);
                    context.optionValueChanged(event);
                });

                Button defaultsButton = new Button(translate.from(LabelKey.Reset_to_Default));
                defaultsButton.setId(ID.getId(Optional.of(((Enum) key.getKey()).name()), this, defaultsButton));
                defaultsButton.addClickListener((event -> {
                    option.delete(0, key);
                    //we create an event to represent the field which whose value will be affected by this change
                    AbstractField.ValueChangeEvent changeEvent = new AbstractField.ValueChangeEvent(uiField);
                    context.optionValueChanged(changeEvent);
                    //update the value of the field - it may have changed
                    uiField.setValue(option.get(key));
                }));
                baseLayout.addComponent(new FormLayout(uiField), 0, row);
                baseLayout.addComponent(new FormLayout(defaultsButton), 1, row);
                row++;
            }
        }
        window.setId(ID.getId(Optional.empty(), context, this, window));
        window.setClosable(true);
        window.setContent(baseLayout);
        window.center();
        UI.getCurrent().addWindow(window);
        this.activeContext = context;
    }

    private void calculateWindowSize(Window window, int numOfKeys) {
        window.setSizeUndefined();
    }

    protected String windowCaption(I18NKey i18NKey) {
        return translate.from(i18NKey);
    }

    /**
     * {@inheritDoc}
     */
    @Nonnull
    @Override
    public Map<OptionKey, Class<?>> contextKeys(OptionContext context) {
        captureContextFields(context);
        Map<OptionKey, Class<?>> keys = new HashMap<>();
        for (java.lang.reflect.Field field : contextFields) {
            field.setAccessible(true);

            try {
                OptionKey key = (OptionKey) field.get(context);
                if (key != null) {
                    keys.put(key, field.getType());
                }
            } catch (IllegalAccessException e) {
                log.error("Unable to access field {}", field.getName());
            }
        }
        return keys;
    }

    private void captureContextFields(OptionContext context) {
        //We should only do this once
        if (contextFields == null) {
            //noinspection unchecked
            contextFields = ReflectionUtils.getAllFields(context.getClass(),
                    p -> p.getType().equals(OptionKey.class));
        }
    }

}