com.expressui.core.view.RootComponent.java Source code

Java tutorial

Introduction

Here is the source code for com.expressui.core.view.RootComponent.java

Source

/*
 * Copyright (c) 2012 Brown Bag Consulting.
 * This file is part of the ExpressUI project.
 * Author: Juan Osuna
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License Version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
 * Brown Bag Consulting, Brown Bag Consulting DISCLAIMS THE WARRANTY OF
 * NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * 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/>.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the ExpressUI software without
 * disclosing the source code of your own applications. These activities
 * include: offering paid services to customers as an ASP, providing
 * services from a web application, shipping ExpressUI with a closed
 * source product.
 *
 * For more information, please contact Brown Bag Consulting at this
 * address: juan@brownbagconsulting.com.
 */

package com.expressui.core.view;

import com.expressui.core.MainApplication;
import com.expressui.core.dao.GenericDao;
import com.expressui.core.entity.security.User;
import com.expressui.core.security.SecurityService;
import com.expressui.core.util.ApplicationProperties;
import com.expressui.core.util.StringUtil;
import com.expressui.core.util.assertion.Assert;
import com.expressui.core.view.field.LabelRegistry;
import com.expressui.core.view.field.format.DefaultFormats;
import com.expressui.core.view.util.CodePopup;
import com.expressui.core.view.util.MessageSource;
import com.vaadin.terminal.Sizeable;
import com.vaadin.ui.*;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

/**
 * Root of the view component hierarchy.
 */
public abstract class RootComponent extends CustomComponent implements ViewBean {

    /**
     * Application properties defined in application.properties
     */
    @Resource
    public ApplicationProperties applicationProperties;

    /**
     * Service for authenticating and getting the current user.
     */
    @Resource
    public SecurityService securityService;

    /**
     * Registry that keeps track of all display labels used in the application. Security system
     * uses this registry to link permissions to user-friendly names representing entity and UI components.
     */
    @Resource
    public LabelRegistry labelRegistry;

    /**
     * Defines some default formats, for dates, times, numbers, currency, etc.
     */
    @Resource
    public DefaultFormats defaultFormats;

    /**
     * Generic DAO for database actions.
     */
    @Resource
    public GenericDao genericDao;

    /**
     * Useful for displaying source code with sample applications, not for production use.
     */
    @Resource
    public CodePopup codePopup;

    /**
     * Provides messages (display labels) associated with domain-level entities.
     */
    @Resource
    public MessageSource domainMessageSource;

    /**
     * Provides messages (display labels) associated with UI elements.
     */
    @Resource
    public MessageSource uiMessageSource;

    /**
     * Provides validation error messages.
     */
    @Resource
    public MessageSource validationMessageSource;

    protected RootComponent() {
    }

    @PostConstruct
    @Override
    public void postConstruct() {
        autoAddStyleNames();

        AbstractOrderedLayout rootLayout = createOrderedLayout();
        setCompositionRoot(rootLayout);
        setWidthSizeFull();
    }

    @Override
    public void postWire() {
    }

    /**
     * Gets code for looking up messages associated with this component, using fully qualified class name.
     *
     * @return code
     */
    public String getCode() {
        return getClass().getName();
    }

    /**
     * Gets code for looking up messages associated with this component, using fully qualified class name plus code arg.
     *
     * @param code code to prepend class name
     * @return code fully qualified code prepended by class name
     */
    public String getCode(String code) {
        return getClass().getName() + "." + code;
    }

    /**
     * Gets domain message associated with this component, where the code consists only of the class name.
     *
     * @return internationalized domain message
     */
    public String getDomainMessage() {
        return domainMessageSource.getMessage(getCode());
    }

    /**
     * Gets domain message associated with this component and given code.
     *
     * @param code code to prepend class name
     * @return internationalized domain message
     */
    public String getDomainMessage(String code) {
        return domainMessageSource.getMessage(getCode(code));
    }

    /**
     * Gets domain message associated with this component, where the code consists only of the class name.
     *
     * @param args used to interpolate the message
     * @return internationalized domain message
     */
    public String getDomainMessage(Object... args) {
        return domainMessageSource.getMessage(getCode(), args);
    }

    /**
     * Gets domain message associated with this component and given code.
     *
     * @param code code to prepend class name
     * @param args used to interpolate the message
     * @return internationalized domain message
     */
    public String getDomainMessage(String code, Object... args) {
        return domainMessageSource.getMessage(getCode(code), args);
    }

    /**
     * Gets the main application, representing user's session.
     *
     * @return main application
     */
    public MainApplication getMainApplication() {
        return MainApplication.getInstance();
    }

    /**
     * Gets the user entity for the currently logged in user.
     *
     * @return user entity with roles and permissions
     */
    public User getCurrentUser() {
        return securityService.getCurrentUser();
    }

    /**
     * Automatically adds style names (CSS classes) to all visual components. This is automatically called on
     * postConstruct. CSS class names are derived from Java class names, that is simple class name without package
     * qualifier. For any given component, CSS classes are generated for each Java class in the inheritance hierarchy
     * up to RootComponent.
     */
    protected void autoAddStyleNames() {
        List<String> styles = StringUtil.generateStyleNamesFromClassHierarchy("e", RootComponent.class, this);
        for (String style : styles) {
            addStyleName(style);
        }
    }

    /**
     * Sets the debug id for this component, useful for finding the generated HTML with a tool like Firebug.
     *
     * @param subComponent nested component
     * @param suffix       friendly suffix
     */
    public void setDebugId(AbstractComponent subComponent, String suffix) {
        String id = StringUtil.generateDebugId("e", this, subComponent, suffix);
        subComponent.setDebugId(id);
    }

    @Override
    public void addComponent(Component c) {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        ((ComponentContainer) getCompositionRoot()).addComponent(c);
    }

    /**
     * Set alignment on a child component.
     *
     * @param childComponent child component
     * @param alignment      alignment
     */
    public void setComponentAlignment(Component childComponent, Alignment alignment) {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        Assert.PROGRAMMING.isTrue(getCompositionRoot() instanceof AbstractOrderedLayout,
                "RootComponent.setComponentAlignment may only be called if using HorizontalLayout or VerticalLayout");
        ((AbstractOrderedLayout) getCompositionRoot()).setComponentAlignment(childComponent, alignment);
    }

    /**
     * Removes all child components.
     */
    public void removeAllComponents() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        ((AbstractComponentContainer) getCompositionRoot()).removeAllComponents();
    }

    /**
     * Creates ordered layout (vertical or horizontal) for this component. Default is vertical. Override to change this.
     *
     * @return ordered layout
     */
    protected AbstractOrderedLayout createOrderedLayout() {
        return createVerticalLayout();
    }

    /**
     * Sets composition root of this component to a VerticalLayout with margins and spacing.
     */
    public VerticalLayout createVerticalLayout() {
        VerticalLayout rootLayout = new VerticalLayout();
        setDebugId(rootLayout, "rootLayout");
        rootLayout.setMargin(true);
        rootLayout.setSpacing(false);

        return rootLayout;
    }

    /**
     * Sets composition root of this component to a HorizontalLayout with margins and spacing.
     */
    public HorizontalLayout createHorizontalLayout() {
        HorizontalLayout rootLayout = new HorizontalLayout();
        setDebugId(rootLayout, "rootLayout");
        rootLayout.setMargin(true);
        rootLayout.setSpacing(false);

        return rootLayout;
    }

    /**
     * Sets width of this component to 100%.
     */
    public void setWidthSizeFull() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        setWidth(100, Sizeable.UNITS_PERCENTAGE);
        getCompositionRoot().setWidth(100, Sizeable.UNITS_PERCENTAGE);
    }

    /**
     * Sets height of this component to 100%.
     */
    public void setHeightSizeFull() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        setHeight(100, Sizeable.UNITS_PERCENTAGE);
        getCompositionRoot().setHeight(100, Sizeable.UNITS_PERCENTAGE);
    }

    /**
     * Sets both width and height of this component to 100%.
     */
    public void setSizeFull() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        super.setSizeFull();
        getCompositionRoot().setSizeFull();
    }

    /**
     * Sets width size to undefined.
     */
    public void setWidthUndefined() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        setWidth(-1, UNITS_PIXELS);
        getCompositionRoot().setWidth(-1, UNITS_PIXELS);
    }

    /**
     * Sets height size to undefined.
     */
    public void setHeightUndefined() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        setHeight(-1, UNITS_PIXELS);
        getCompositionRoot().setHeight(-1, UNITS_PIXELS);
    }

    /**
     * Sets size to undefined.
     */
    public void setSizeUndefined() {
        Assert.PROGRAMMING.notNull(getCompositionRoot(),
                "Composition root must be set before this method can be called");
        super.setSizeUndefined();
        getCompositionRoot().setSizeUndefined();
    }

    /**
     * Adds code popup button next to this component to the right.
     *
     * @param classes classes for displaying related source code and Javadoc. If
     *                class is within com.expressui.core or com.expressui.domain,
     *                then Javadoc is displayed, otherwise source code.
     */
    protected void addCodePopupButtonIfEnabled(Class... classes) {
        addCodePopupButtonIfEnabled(Alignment.MIDDLE_LEFT, classes);
    }

    /**
     * Adds code popup button next to this component to the right.
     *
     * @param alignment alignment for button
     * @param classes   classes for displaying related source code and Javadoc
     */
    protected void addCodePopupButtonIfEnabled(Alignment alignment, Class... classes) {
        if (isCodePopupEnabled()) {
            Component firstComponent = getCompositionRoot();
            AbstractOrderedLayout codePopupButtonLayout = new HorizontalLayout();
            codePopupButtonLayout.setMargin(false);
            setDebugId(codePopupButtonLayout, "codePopupButtonLayout");
            setCompositionRoot(codePopupButtonLayout);
            codePopupButtonLayout.addComponent(firstComponent);
            Button codePopupButton = codePopup.createPopupCodeButton(autoAddCodeClasses(classes));
            codePopupButtonLayout.addComponent(codePopupButton);
            codePopupButtonLayout.setComponentAlignment(codePopupButton, alignment);
        }
    }

    protected Class[] autoAddCodeClasses(Class... classes) {
        Class[] allClasses = new Class[classes.length + 1];
        allClasses[0] = getClass();
        System.arraycopy(classes, 0, allClasses, 1, classes.length);

        return allClasses;
    }

    /**
     * Asks if code popups should be displayed. Only useful for demo applications.
     *
     * @return true if code popups should be displayed
     */
    public boolean isCodePopupEnabled() {
        return applicationProperties.isCodePopupEnabled();
    }
}