org.zkoss.ganttz.timetracker.OnColumnsRowRenderer.java Source code

Java tutorial

Introduction

Here is the source code for org.zkoss.ganttz.timetracker.OnColumnsRowRenderer.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.zkoss.ganttz.timetracker;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.Validate;
import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;

public class OnColumnsRowRenderer<C, T> implements RowRenderer {

    private final List<C> columns;

    private final ICellForDetailItemRenderer<C, T> cellRenderer;

    private Class<T> type;

    public static <C, T> OnColumnsRowRenderer<C, T> create(ICellForDetailItemRenderer<C, T> cellRenderer,
            Collection<C> columns) {

        return create(inferGenericType(cellRenderer), cellRenderer, columns);
    }

    public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type,
            ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {

        return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
    }

    private static <T> Class<T> inferGenericType(ICellForDetailItemRenderer<?, T> renderer) {
        ParameterizedType parametrizedType = findRenderererInterfaceType(renderer);
        Type[] actualTypeArguments = parametrizedType.getActualTypeArguments();
        final int genericTypePosition = 1;
        Type type = actualTypeArguments[genericTypePosition];

        if (!isActualType(type)) {
            informCannotBeInferred(renderer);
        }

        return (Class<T>) actualTypeArguments[genericTypePosition];
    }

    private static boolean isActualType(Type t) {
        return t instanceof Class;
    }

    private static ParameterizedType findRenderererInterfaceType(ICellForDetailItemRenderer<?, ?> renderer) {
        Type[] genericInterfaces = renderer.getClass().getGenericInterfaces();

        for (Type type : genericInterfaces) {

            if (isTypeForInterface(type, ICellForDetailItemRenderer.class)) {

                if (type instanceof ParameterizedType) {
                    return (ParameterizedType) type;
                } else {
                    informCannotBeInferred(renderer);
                }
            }
        }

        throw new RuntimeException("shouldn't reach here. Uncovered case for " + renderer);
    }

    private static boolean isTypeForInterface(Type type, Class<?> interfaceBeingSearched) {
        if (type instanceof ParameterizedType) {
            ParameterizedType p = (ParameterizedType) type;
            Type rawType = p.getRawType();

            return rawType.equals(interfaceBeingSearched);
        }

        return type.equals(interfaceBeingSearched);
    }

    private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
        throw new IllegalArgumentException(
                "the generic type cannot be inferred if actual type parameters are not declared "
                        + "or implements the raw interface: " + renderer.getClass().getName());
    }

    private OnColumnsRowRenderer(Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer,
            Collection<C> columns) {

        Validate.notNull(type);
        Validate.notNull(columns);
        Validate.notNull(cellRenderer);
        Validate.noNullElements(columns);

        this.cellRenderer = cellRenderer;
        this.columns = new ArrayList<>(columns);
        this.type = type;
    }

    @Override
    public void render(Row row, Object o, int index) throws Exception {
        if (!type.isInstance(o)) {
            throw new IllegalArgumentException(o + " is not instance of " + type);
        }

        for (C item : columns) {
            Component child = cellRenderer.cellFor(item, type.cast(o));
            child.setParent(row);
        }
    }

}