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

tools.dynamia.zk.crud.CrudView Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1
 * Colombia / South America
 *
 * 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 tools.dynamia.zk.crud;

import org.zkoss.bind.Binder;
import org.zkoss.bind.impl.BinderUtil;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Box;
import org.zkoss.zul.Center;
import org.zkoss.zul.Div;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.Menuseparator;
import org.zkoss.zul.North;
import org.zkoss.zul.Window;
import org.zkoss.zul.impl.XulElement;
import tools.dynamia.actions.*;
import tools.dynamia.commons.ApplicableClass;
import tools.dynamia.commons.BeanMap;
import tools.dynamia.commons.BeanUtils;
import tools.dynamia.commons.Callback;
import tools.dynamia.commons.LocalizedMessagesProvider;
import tools.dynamia.commons.Messages;
import tools.dynamia.commons.collect.ArrayListMultiMap;
import tools.dynamia.commons.collect.ListMultiMap;
import tools.dynamia.crud.ChangedStateEvent;
import tools.dynamia.crud.CrudAction;
import tools.dynamia.crud.CrudActionEvent;
import tools.dynamia.crud.CrudControllerAPI;
import tools.dynamia.crud.CrudDataSetViewBuilder;
import tools.dynamia.crud.CrudState;
import tools.dynamia.crud.CrudStateChangedListener;
import tools.dynamia.crud.CrudViewComponent;
import tools.dynamia.crud.actions.DeleteAction;
import tools.dynamia.crud.actions.EditAction;
import tools.dynamia.crud.actions.NewAction;
import tools.dynamia.domain.ValidationError;
import tools.dynamia.domain.services.CrudService;
import tools.dynamia.integration.Containers;
import tools.dynamia.integration.ObjectMatcher;
import tools.dynamia.navigation.NavigationManager;
import tools.dynamia.navigation.Page;
import tools.dynamia.viewers.DataSetView;
import tools.dynamia.viewers.Field;
import tools.dynamia.viewers.View;
import tools.dynamia.viewers.ViewDescriptor;
import tools.dynamia.viewers.ViewRendererException;
import tools.dynamia.viewers.util.Viewers;
import tools.dynamia.web.util.HttpUtils;
import tools.dynamia.zk.BindingComponentIndex;
import tools.dynamia.zk.ComponentAliasIndex;
import tools.dynamia.zk.actions.ActionToolbar;
import tools.dynamia.zk.actions.MenuitemActionRenderer;
import tools.dynamia.zk.actions.ToolbarbuttonActionRenderer;
import tools.dynamia.zk.navigation.ComponentPage;
import tools.dynamia.zk.ui.CanBeReadonly;
import tools.dynamia.zk.util.ZKUtil;
import tools.dynamia.zk.viewers.form.FormFieldComponent;
import tools.dynamia.zk.viewers.form.FormView;
import tools.dynamia.zk.viewers.mv.MultiView;
import tools.dynamia.zk.viewers.mv.MultiViewListener;
import tools.dynamia.zk.viewers.ui.Viewer;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.function.Consumer;

/**
 * @author Mario A. Serrano Leones
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public class CrudView extends Div implements CrudViewComponent, ActionEventBuilder, IdSpace, CanBeReadonly {

    private static final String DEFAULT_FORM_VIEW_TITLE = "defaultFormViewTitle";

    static {
        BindingComponentIndex.getInstance().put("value", CrudView.class);
        ComponentAliasIndex.getInstance().add(CrudView.class);
    }

    /**
     *
     */
    private static final long serialVersionUID = 7256261472260522851L;
    protected static final String ACTION = "ACTION";
    private Class objectClass;
    private View parentView;
    private String dataSetViewType = "table";
    protected ActionToolbar toolbarLeft;
    protected ActionToolbar toolbarRight;

    protected FormView formView;
    protected MultiView formViewContainer;
    protected DataSetView dataSetView;
    protected Component layout;
    protected Component activeView;
    protected Component toolbarContainer;

    private boolean readOnly;
    private Map actionsParams;
    // ------------------------
    private Class controllerClass;
    private CrudController controller;
    private CrudState state;
    private ViewDescriptor viewDescriptor;
    private final List localListeners = new ArrayList<>();
    // -----------------------------------
    private Menupopup contextMenu;
    private List applicableActions;
    private final List actions = new ArrayList<>();
    private String crudServiceName;
    private String formViewDescriptorId;

    private Object source;
    private Consumer onSourceChange;
    private boolean queryProjection;
    private LocalizedMessagesProvider messagesProvider;


    public CrudView() {
        buildGeneralView();
        buildToolbars();
        buildToolbarContainer();
        buildContextMenu();
    }

    protected void buildToolbars() {
        ActionToolbar toolbar = new ActionToolbar(this);
        toolbar.setAlign("start");
        toolbar.setActionRenderer(getDefaultActionRenderer());
        toolbarLeft = toolbar;

        toolbar = new ActionToolbar(this);
        toolbar.setAlign("end");
        toolbar.setActionRenderer(getDefaultActionRenderer());
        toolbarRight = toolbar;
    }

    protected void buildToolbarContainer() {
        Box boxToolbarContainer = new Box(new Component[]{toolbarLeft, toolbarRight});
        boxToolbarContainer.setOrient("horizontal");
        boxToolbarContainer.setPack("stretch");
        boxToolbarContainer.setStyle("width:100%; padding:0px");
        boxToolbarContainer.setSclass(ActionToolbar.CONTAINER_SCLASS);
        if (layout instanceof Borderlayout borderlayout) {
            boxToolbarContainer.setParent(borderlayout.getNorth());
            toolbarContainer = boxToolbarContainer;
        }
    }

    protected void buildGeneralView() {
        setHeight("100%");
        setZclass("crudview");
        Borderlayout borderLayout = new Borderlayout();
        borderLayout.setVflex("1");
        {
            North north = new North();
            north.setSclass("crudview-header");
            north.setParent(borderLayout);
            north.setBorder("none");

            Center center = new Center();
            center.setSclass("crudview-body");
            center.setParent(borderLayout);
            center.setBorder("none");
        }
        borderLayout.setParent(this);
        layout = borderLayout;
    }

    protected void buildDataSetView() {

        CrudDataSetViewBuilder viewBuilder = getDataSetViewBuilder(getDataSetViewType());
        if (viewBuilder != null) {
            dataSetView = viewBuilder.build(this);
        }

        if (dataSetView == null) {
            throw new ViewRendererException(
                    "Unable to build DataSetViewType [" + dataSetViewType + "] for CrudView " + getClass());
        }

        if (dataSetView.getViewDescriptor().getParams().get("useProjection") == Boolean.TRUE) {
            setQueryProjection(true);
        }

        ((Component) dataSetView).addEventListener(Events.ON_SELECT,
                event -> getController().setSelected(dataSetView.getSelected()));

    }

    protected void buildFormView() {
        final String device = HttpUtils.detectDevice();
        if (formViewDescriptorId != null && !formViewDescriptorId.isBlank()) {
            formView = (FormView) Viewers.getView(formViewDescriptorId);
        }

        if (formView == null) {
            formView = (FormView) Viewers.getView(getViewDescriptor().getBeanClass(), "form", device, getValue());
        }

        formView.setActionEventBuilder(this);
        formView.setAutoheight(true);
    }

    protected void buildFormViewContainer() {
        String formViewTitle = (String) formView.getViewDescriptor().getParams().get(Viewers.PARAM_TITLE);
        if (formViewTitle == null) {
            formViewTitle = Messages.get(CrudView.class, DEFAULT_FORM_VIEW_TITLE);
        }

        if (messagesProvider != null) {
            formViewTitle = messagesProvider.getMessage("Form Title", Viewers.buildMessageClasffier(formView.getViewDescriptor()),
                    Messages.getDefaultLocale(),
                    formViewTitle);
        }

        formViewContainer = new MultiView();
        formViewContainer.setVflex("1");
        var multiViewParams = formView.getViewDescriptor().getParams().get(Viewers.PARAM_MULTIVIEW);
        if (multiViewParams instanceof Map) {
            BeanUtils.setupBean(formViewContainer, multiViewParams);
        }
        addFormViewToContainer(formViewTitle);
        formViewContainer.setParentView(this);

        // Find collection and viewers fields and add Subviews
        for (Field field : formView.getViewDescriptor().getFields()) {
            String label = field.getLocalizedLabel(Messages.getDefaultLocale());
            if (messagesProvider != null) {
                label = messagesProvider.getMessage(field.getName(), Viewers.buildMessageClasffier(field.getViewDescriptor()), Messages.getDefaultLocale(), label);
            }


            if (field.isCollection() && field.getComponentClass() == CrudView.class) {
                addSubCrudView(formView, field, label);
            } else if (field.getComponentClass() == Viewer.class) {
                addSubGenericView(field);
            }
        }
    }

    protected void addFormViewToContainer(String formViewTitle) {
        formViewContainer.addView(formViewTitle, formView);
    }

    protected void buildContextMenu() {
        contextMenu = new Menupopup();
        contextMenu.setParent(this);
        contextMenu.addEventListener(Events.ON_OPEN, event -> loadMenuActions());
    }

    @Override
    public void setState(CrudState crudState) {
        CrudState oldState = this.state;
        Component activeViewParent = getActiveViewParent();
        activeView = null;
        this.state = crudState;
        switch (crudState) {
            case CREATE, UPDATE -> {
                activeView = getFormView();
                if (activeViewParent instanceof Center) {
                    ((Center) activeViewParent).setAutoscroll(true);
                }
                setTitle(null);
            }
            case READ -> {
                activeView = (Component) getDataSetView();
                if (activeViewParent instanceof Center) {
                    ((Center) activeViewParent).setAutoscroll(false);
                }
            }
            default -> {
            }
        }

        if (activeView != null) {

            activeViewParent.getChildren().clear();
            showActiveView();
            loadActions(getState());
            fireChangedStateListeners(this.state, oldState);
        }
    }

    @Override
    public CrudState getState() {
        return state;
    }

    @Override
    public T getValue() {
        if (activeView != null) {
            View view = (View) activeView;
            return (T) view.getValue();
        } else {
            return null;
        }
    }

    @Override
    public void setValue(T value) {
        if (activeView != null) {
            View view = (View) activeView;
            view.setValue(value);
            if (view instanceof FormView && formViewContainer != null) {
                formViewContainer.setValue(value);
            }

        }
    }

    @Override
    public ViewDescriptor getViewDescriptor() {
        return viewDescriptor;
    }

    @Override
    public void setViewDescriptor(ViewDescriptor viewDescriptor) {
        this.viewDescriptor = viewDescriptor;
    }

    @Override
    public FormView getFormView() {
        if (formView == null) {
            buildFormView();
            if (formView.getCustomView() == null) {
                buildFormViewContainer();
            }
        }
        return formView;
    }

    @Override
    public DataSetView getDataSetView() {
        if (dataSetView == null) {
            buildDataSetView();
        }
        return dataSetView;
    }

    public String getDataSetViewType() {
        return dataSetViewType;
    }

    public void setDataSetViewType(String dataSetViewType) {
        this.dataSetViewType = dataSetViewType;
    }

    public Class getBeanClass() {
        return objectClass;
    }

    public void setBeanClass(Class objectClass) {
        this.objectClass = objectClass;
    }

    public Class getControllerClass() {
        return controllerClass;
    }

    public void setControllerClass(Class controller) {
        this.controllerClass = controller;
    }

    public void setControllerClass(String className) throws ClassNotFoundException {
        Class clazz = Class.forName(className.trim());
        if (BeanUtils.isAssignable(clazz, CrudController.class)) {
            setControllerClass(clazz);
        } else {
            throw new ViewRendererException("CrudView controllers class is not a CrudController");
        }
    }

    @Override
    public CrudController getController() {
        return controller;
    }

    @Override
    public void setController(CrudControllerAPI controller) {
        if (controller == null) {
            throw new NullPointerException("You can't asign a null CrudController to CrudView... :(");
        }
        this.controller = (CrudController) controller;
        this.controller.setDataSetView(getDataSetView());
        this.controller.setQueryProjection(isQueryProjection());

        if (crudServiceName != null && !crudServiceName.isEmpty()) {
            CrudService customCrudService = Containers.get().findObject(crudServiceName, CrudService.class);
            if (customCrudService == null) {
                throw new ViewRendererException(
                        "Cant find crudservice instace with name:" + crudServiceName + ". CrudView: " + this);
            }

            this.controller.setCrudService(customCrudService);
        }

        try {
            this.controller.doAfterCompose(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean isReadonly() {
        return readOnly;
    }

    @Override
    public void setReadonly(boolean readOnly) {
        this.readOnly = readOnly;

    }

    public void clearActions() {
        if (applicableActions != null) {
            for (Action action : applicableActions) {
                if (action instanceof ActionLifecycleAware ala) {
                    ala.onDestroy();
                }
            }
        }

        if (toolbarLeft != null) {
            toolbarLeft.getChildren().clear();
        }
        if (toolbarRight != null) {
            toolbarRight.getChildren().clear();
        }

        applicableActions = null;
    }

    public void addAction(CrudAction action) {
        this.actions.add(action);
        loadActions(getState());
    }

    protected ActionRenderer getDefaultActionRenderer() {
        return new ToolbarbuttonActionRenderer();
    }

    private void renderMenuActions(Class valueClass) {

        List menuActions = findApplicableActions(valueClass, CrudState.READ);

        MenuitemActionRenderer renderer = new MenuitemActionRenderer();
        ListMultiMap menuItems = new ArrayListMultiMap<>();
        for (CrudAction crudAction : menuActions) {

            if (crudAction.isEnabled() && crudAction.isMenuSupported()) {
                menuItems.put(crudAction.getGroup(), Actions.render(renderer, crudAction, this));
            }
        }

        if (!menuItems.entrySet().isEmpty()) {
            Component lastSeparator = null;

            for (Entry> entry : menuItems.entrySet()) {

                List groupActions = entry.getValue();
                groupActions.sort(new ComponentComparator());
                for (Component menuitem : groupActions) {
                    contextMenu.appendChild(menuitem);
                }
                lastSeparator = new Menuseparator();
                contextMenu.appendChild(new Menuseparator());
            }
            lastSeparator.setParent(null);
        }
    }

    public void addCrudStateChangedListener(CrudStateChangedListener listener) {
        if (listener != null && !localListeners.contains(listener)) {
            localListeners.add(listener);
        }
    }

    public void removeCrudStateChangedListener(CrudStateChangedListener listener) {
        localListeners.remove(listener);
    }

    private void showActiveView() {
        if (activeView == dataSetView) {
            destroyFormView();
            showDataSetView();
        } else {
            showFormView();
        }
    }

    private void showFormView() {
        Component activeViewParent = getActiveViewParent();

        if (formViewContainer != null) {
            formViewContainer.setParent(activeViewParent);
        } else {
            activeView.setParent(activeViewParent);
        }

        if (formView != null && formView.getCustomView() != null) {
            clearActions();

            Binder binder = BinderUtil.getBinder(formView.getFirstChild());
            if (binder != null) {
                Object viewModel = binder.getViewModel();
                if (viewModel instanceof FormCrudViewModel) {
                    ((FormCrudViewModel) viewModel).initForm(this, formView);
                }
            }
        }
    }

    protected Component getActiveViewParent() {
        Component activeViewParent = layout;

        if (layout instanceof Borderlayout borderlayout) {
            activeViewParent = borderlayout.getCenter();
        }
        return activeViewParent;
    }

    private void destroyFormView() {
        if (formView != null) {
            formView.detach();
            formView = null;
        }

        if (formViewContainer != null) {
            formViewContainer.detach();
            formViewContainer = null;
        }
    }

    private void showDataSetView() {
        ((Component) dataSetView).setParent(getActiveViewParent());
    }

    protected void addSubCrudView(FormView formView, final Field field, final String label) {
        if (field.getParams().get(Viewers.PARAM_INPLACE) == Boolean.TRUE) {
            View view = loadSubview(field);
            Component parent = null;
            FormFieldComponent parentField = formView.getFieldComponent(field.getName());
            if (parentField != null) {
                parent = parentField.getInputComponent().getParent();
                parentField.getInputComponent().detach();
            }
            if (view instanceof XulElement && field.getParams().containsKey(Viewers.PARAM_HEIGHT)) {
                ((XulElement) view).setHeight((String) field.getParams().get(Viewers.PARAM_HEIGHT));
            }
            if (parent != null) {
                ((Component) view).setParent(parent);
            } else {
                this.formView.addSubview(label, view);
            }
            if (view instanceof CrudView) {
                ((CrudView) view).getController().doQuery();
            }
        } else {
            formViewContainer.addView(label, p -> CrudView.this.loadSubview(field));
        }
    }

    protected void addSubGenericView(final Field field) {

        if (field.getParams().get(Viewers.PARAM_INPLACE) != Boolean.TRUE) {

            MultiViewListener listener = null;
            if (field.getParams().get(Viewers.PARAM_MULTIVIEW_LISTENER) != null) {
                listener = BeanUtils.newInstance(field.getParams().get(Viewers.PARAM_MULTIVIEW_LISTENER).toString());
                if (listener != null) {
                    BeanUtils.setupBean(listener, field.getParams());
                }
            }

            formViewContainer.addView(field.getLabel(), listener, parentView -> {
                Viewer viewer = new Viewer();
                BeanUtils.setupBean(viewer, field.getParams());
                return viewer.getView();
            });
        }
    }

    private boolean isWritableAction(Action action) {
        return action instanceof NewAction || action instanceof EditAction || action instanceof DeleteAction;
    }

    @Override
    public Object getSource() {
        return source;
    }

    @Override
    public void setSource(Object source) {
        this.source = source;
        if (onSourceChange != null) {
            onSourceChange.accept(source);
        }
    }

    public boolean isQueryProjection() {
        return queryProjection;
    }

    public void setQueryProjection(boolean queryProjection) {
        this.queryProjection = queryProjection;
        if (controller != null) {
            controller.setQueryProjection(queryProjection);
        }

    }

    public String getFormViewDescriptorId() {
        return formViewDescriptorId;
    }

    public void setFormViewDescriptorId(String formViewDescriptorId) {
        this.formViewDescriptorId = formViewDescriptorId;
    }

    public LocalizedMessagesProvider getMessagesProvider() {
        return messagesProvider;
    }

    public void setMessagesProvider(LocalizedMessagesProvider messagesProvider) {
        this.messagesProvider = messagesProvider;
    }

    private static class ComponentComparator implements Comparator {

        @Override
        public int compare(Component o1, Component o2) {
            Action a1 = (Action) o1.getAttribute(ACTION);
            Action a2 = (Action) o2.getAttribute(ACTION);
            return a1.compareTo(a2);
        }
    }

    private View loadSubview(Field field) {

        Class subentityClass = field.getPropertyInfo().getGenericType();
        if (subentityClass == null && field.getParams().containsKey("genericType")) {
            try {
                subentityClass = Class.forName((String) field.getParams().get("genericType"));
            } catch (ClassNotFoundException e) {
                throw new ViewRendererException(
                        "Cannot load subcrud view " + field.getLabel() + " not class found for subentity", e);
            }
        }

        if (subentityClass == null) {
            throw new ViewRendererException(
                    "Field " + field.getName() + " dont have a generic type, i cannot build a crudview");
        }

        Object parent = formView.getValue();
        String parentName = BeanUtils.findParentPropertyName(getViewDescriptor().getBeanClass(), subentityClass);
        if (field.getParams().get("parentName") != null) {
            parentName = field.getParams().get("parentName").toString();
        }
        SubcrudController subcrudController = new SubcrudController(subentityClass, parent, parentName,
                field.getName());

        try {
            String subcontrollerClass = (String) field.getParams().get(Viewers.PARAM_CONTROLLER);
            if (subcontrollerClass != null) {
                Constructor constructor = Class.forName(subcontrollerClass).getConstructor(Class.class, Object.class,
                        String.class, String.class);
                if (constructor != null) {
                    subcrudController = (SubcrudController) constructor.newInstance(subentityClass, parent, parentName,
                            field.getName());
                } else {
                    throw new ViewRendererException("No valid constructor found in custom SubcrudController class");
                }
            }

        } catch (Exception e) {
            throw new ViewRendererException("Cannot instanciate custom SubcrudController", e);
        }

        ViewDescriptor descriptor = Viewers.getViewDescriptor(subentityClass, "crud");
        CrudViewRenderer crudViewRenderer = getCrudViewRenderer();
        CrudView subView = crudViewRenderer.render(descriptor, null, subcrudController);
        getController().addSubcrudController(subcrudController);

        return subView;
    }

    protected CrudViewRenderer getCrudViewRenderer() {
        return new CrudViewRenderer<>();
    }


    private void loadMenuActions() {
        if (contextMenu != null && dataSetView != null && dataSetView.getSelected() != null) {
            Object value = dataSetView.getSelected();
            Class valueClass = value.getClass();
            Class lastClass = (Class) contextMenu.getAttribute("LastClass");
            if (valueClass != lastClass) {
                lastClass = valueClass;
                contextMenu.getChildren().clear();
                contextMenu.getAttributes().put("LastClass", lastClass);

                renderMenuActions(valueClass);
            }
        }
    }

    protected void loadActions(final CrudState state) {
        clearActions();

        this.applicableActions = findApplicableActions(getBeanClass(), state);
        Map groups = new TreeMap<>();
        for (final Action action : applicableActions) {
            if (action.isEnabled()) {
                String groupName = "default";
                if (action.getGroup() != null) {
                    groupName = action.getGroup().getName();
                }
                ActionGroup group = groups.get(groupName);
                if (group == null) {
                    group = new ActionGroup(groupName);
                    if (action.getGroup() != null) {
                        group.setAlign(action.getGroup().getAlign());
                    }
                    groups.put(groupName, group);
                }
                group.getActions().add(action);

                if (action instanceof CrudControllerAware) {
                    ((CrudControllerAware) action).setCrudController(getController());
                }
            }
        }
        for (ActionGroup group : groups.values()) {
            showActionGroup(group);
        }

    }

    protected void showActionGroup(final ActionGroup actionGroup) {
        for (Action action : actionGroup.getActions()) {
            showAction(actionGroup, action);
        }
    }


    protected boolean isFormActive() {
        return formView != null && formView.equals(activeView) || getState() == CrudState.CREATE || getState() == CrudState.UPDATE;
    }

    protected void showAction(final ActionGroup actionGroup, Action action) {
        if (isReadonly() && isWritableAction(action)) {
            return;
        }
        if (isFormActive()) {
            formView.addAction(action);
        } else {
            if ("right".equals(actionGroup.getAlign())) {
                toolbarRight.addAction(action);
            } else {
                toolbarLeft.addAction(action);
            }
        }
    }

    protected List findApplicableActions(final Class targetClass, final CrudState state) {
        ActionLoader loader = new ActionLoader(CrudAction.class);
        loader.setActionAttributes(actionsParams);
        List allowedActions = loader.load((ObjectMatcher) crudAction -> {
            if (isReadonly()) {
                return isApplicable(targetClass, state, crudAction) && crudAction instanceof ReadableOnly;
            } else {
                return isApplicable(targetClass, state, crudAction);
            }
        });

        for (CrudAction action : this.actions) {
            if (isApplicable(targetClass, state, action)) {
                allowedActions.add(action);
            }
        }
        allowedActions.sort(new ActionComparator());

        return allowedActions;
    }

    private boolean isApplicable(final Class targetClass, final CrudState state, CrudAction crudAction) {
        boolean applicableState = CrudState.isApplicable(state, crudAction.getApplicableStates());
        boolean applicableClass = ApplicableClass.isApplicable(targetClass, crudAction.getApplicableClasses(), true);
        return applicableClass && applicableState;
    }

    @Override
    public ActionEvent buildActionEvent(Object source, Map params) {
        Object data = switch (getState()) {
            case CREATE, UPDATE -> getValue();
            case READ, DELETE -> getDataSetView().getSelected();
        };

        if (data instanceof BeanMap && ((BeanMap) data).getId() != null) {
            CrudService crudService = crudServiceName != null ? Containers.get().findObject(crudServiceName, CrudService.class) : Containers.get().findObject(CrudService.class);
            if (crudService != null) {
                BeanMap beanMap = (BeanMap) data;
                data = crudService.find(beanMap.getBeanClass(), (Serializable) beanMap.getId());
            }
        }

        return new CrudActionEvent(data, source, params, this, this.getController());
    }

    private void fireChangedStateListeners(CrudState newState, CrudState oldState) {
        ChangedStateEvent evt = new ChangedStateEvent(newState, oldState, this);
        // FIRST FIRE LOCAL LISTENERS
        for (CrudStateChangedListener localListener : localListeners) {
            localListener.changedState(evt);
        }

        // THEN FIRE GLOBAL LISTENERS
        Collection listeners = Containers.get().findObjects(CrudStateChangedListener.class);
        if (listeners != null && !listeners.isEmpty()) {
            for (CrudStateChangedListener listener : listeners) {
                listener.changedState(evt);
            }
        }
    }

    @Override
    public View getParentView() {
        return parentView;
    }

    @Override
    public void setParentView(View parentView) {
        this.parentView = parentView;
    }

    public Menupopup getContextMenu() {
        return contextMenu;
    }

    public void setActionsParams(Map actionsParams) {
        this.actionsParams = actionsParams;
    }

    public static Window showUpdateView(String title, Class clazz, Object value) {
        return showUpdateView(title, clazz, value, null);
    }

    public static Window showUpdateView(String title, Class clazz, Object value, Callback callback) {

        final Viewer viewer = new Viewer("crud", clazz);
        final Window window = ZKUtil.showDialog(title, viewer, "90%", "98%");

        CrudView crudView = (CrudView) viewer.getView();
        crudView.setState(CrudState.UPDATE);
        crudView.setValue(value);
        crudView.getController().setEntity(value);
        crudView.addCrudStateChangedListener(evt -> {
            if (evt.newState() != CrudState.UPDATE) {
                window.detach();
                if (callback != null) {
                    callback.doSomething();
                }
            }
        });
        return window;
    }


    public static void showUpdateViewPage(String title, Class clazz, Object value) {

        final Viewer viewer = new Viewer("crud", clazz);

        CrudView crudView = (CrudView) viewer.getView();
        crudView.setState(CrudState.UPDATE);
        crudView.setValue(value);
        crudView.getController().setEntity(value);
        crudView.addCrudStateChangedListener(evt -> {
            if (evt.newState() != CrudState.UPDATE) {
                NavigationManager.getCurrent().closeCurrentPage();
            }

        });

        Page page = new ComponentPage("edit" + clazz.getName(), title, viewer);
        page.setTemporal(true);
        page.setAlwaysAllowed(true);
        NavigationManager.getCurrent().setCurrentPage(page);
    }

    public static void showCreateViewPage(String title, Class clazz) {

        final Viewer viewer = new Viewer("crud", clazz);
        CrudView crudView = (CrudView) viewer.getView();
        crudView.setState(CrudState.CREATE);
        crudView.getController().newEntity();
        crudView.addCrudStateChangedListener(evt -> {
            if (evt.newState() == CrudState.READ) {
                NavigationManager.getCurrent().closeCurrentPage();
            }
        });

        Page page = new ComponentPage("create" + clazz.getName(), title, viewer);
        page.setAlwaysAllowed(true);
        page.setTemporal(true);
        NavigationManager.getCurrent().setCurrentPage(page);
    }

    public static Window showCreateView(String title, Class clazz) {
        return showCreateView(title, clazz, null);
    }

    public static Window showCreateView(String title, Class clazz, Callback callback) {

        final Viewer viewer = new Viewer("crud", clazz);
        CrudView crudView = (CrudView) viewer.getView();
        crudView.setState(CrudState.CREATE);
        crudView.getController().newEntity();
        crudView.addCrudStateChangedListener(evt -> {
            if (evt.newState() == CrudState.READ) {
                Window window = (Window) viewer.getParent();
                window.detach();
                if (callback != null) {
                    callback.doSomething();
                }
            }
        });
        return ZKUtil.showDialog(title, viewer, "90%", "98%");
    }

    public static void showCrudView(String title, Class clazz) {

        final Viewer viewer = new Viewer("crud", clazz);

        ZKUtil.showDialog(title, viewer, "90%", "98%");

    }

    public static CrudDataSetViewBuilder getDataSetViewBuilder(String typeName) {
        for (CrudDataSetViewBuilder viewBuilder : Containers.get().findObjects(CrudDataSetViewBuilder.class)) {
            if (viewBuilder.getViewTypeName().equals(typeName)) {
                return viewBuilder;
            }
        }
        return null;
    }

    public Component getLayout() {
        return layout;
    }

    public String getCrudServiceName() {
        return crudServiceName;
    }

    public void setCrudServiceName(String crudServiceName) {
        this.crudServiceName = crudServiceName;
    }

    @Override
    public void handleValidationError(ValidationError error) {
        if (error != null && error.getInvalidProperty() != null && formView != null) {
            FormFieldComponent fieldComponent = formView.getFieldComponent(error.getInvalidProperty());
            if (fieldComponent != null) {
                throw new WrongValueException(fieldComponent.getInputComponent(), error.getMessage());
            }
        }
    }

    @Override
    public void setTitle(String title) {
        if (title != null && messagesProvider != null) {
            title = messagesProvider.getMessage(title, Viewers.buildMessageClasffier(getFormView().getViewDescriptor()), Messages.getDefaultLocale(), title);
        }
        getFormView().setTitle(title);
    }

    @Override
    public List getActions() {
        return applicableActions;
    }

    @Override
    public String toString() {
        return super.toString() + ". " + getViewDescriptor();
    }

    public void onSourceChanged(Consumer onSourceChange) {
        this.onSourceChange = onSourceChange;
    }

    @Override
    public Class getObjectClass() {
        return objectClass;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy