info.magnolia.ui.admincentral.shellapp.favorites.FavoritesForm.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.ui.admincentral.shellapp.favorites.FavoritesForm.java

Source

/**
 * This file Copyright (c) 2013-2015 Magnolia International
 * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
 *
 *
 * This file is dual-licensed under both the Magnolia
 * Network Agreement and the GNU General Public License.
 * You may elect to use one or the other of these licenses.
 *
 * This file is distributed in the hope that it will be
 * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
 * Redistribution, except as permitted by whichever of the GPL
 * or MNA you select, is prohibited.
 *
 * 1. For the GPL license (GPL), you can redistribute and/or
 * modify this file under the terms of the GNU General
 * Public License, Version 3, as published by the Free Software
 * Foundation.  You should have received a copy of the GNU
 * General Public License, Version 3 along with this program;
 * if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 2. For the Magnolia Network Agreement (MNA), this file
 * and the accompanying materials are made available under the
 * terms of the MNA which accompanies this distribution, and
 * is available at http://www.magnolia-cms.com/mna.html
 *
 * Any modifications to this file must keep this entire header
 * intact.
 *
 */
package info.magnolia.ui.admincentral.shellapp.favorites;

import info.magnolia.cms.core.Path;
import info.magnolia.i18nsystem.SimpleTranslator;
import info.magnolia.ui.api.shell.Shell;
import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;

import java.util.Map;
import java.util.Map.Entry;

import com.vaadin.data.Item;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutListener;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
import com.vaadin.ui.TabSheet.SelectedTabChangeListener;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

/**
 * FavoritesForm.
 */
public final class FavoritesForm extends CustomComponent {

    private static final String EDIT_ACTION_STYLENAME = "favItemEdit";

    private FavoritesView.Listener listener;
    private Shell shell;
    private TabSheet tabsheet;
    private Label arrowIcon;
    private InternalFavoriteEntryForm favoriteEntryForm;
    private InternalFavoriteGroupForm favoriteGroupForm;
    private final SimpleTranslator i18n;

    private Label editIcon;
    private Label editLabel;

    public FavoritesForm(FavoritesView.Listener listener, Shell shell, SimpleTranslator i18n) {
        this.listener = listener;
        this.shell = shell;
        this.i18n = i18n;
        init();
    }

    /**
     * Since 5.3.5  use {@link #FavoritesForm(info.magnolia.ui.admincentral.shellapp.favorites.FavoritesView.Listener, Shell, SimpleTranslator)} as a constructor and populate fav/group entries individually through the new setters.
     *
     * @see #setNewFavorite(Item)
     * @see #setNewGroup(Item)
     * @see #setAvailableGroups(Map)
     */
    @Deprecated
    public FavoritesForm(final JcrNewNodeAdapter newFavorite, final JcrNewNodeAdapter newGroup,
            final Map<String, String> availableGroups, final FavoritesView.Listener listener, final Shell shell,
            final SimpleTranslator i18n) {
        this(listener, shell, i18n);
    }

    private void init() {
        addStyleName("favorites-form");
        final VerticalLayout favoriteForm = new VerticalLayout();
        favoriteEntryForm = new InternalFavoriteEntryForm();
        favoriteGroupForm = new InternalFavoriteGroupForm();

        tabsheet = new TabSheet();
        tabsheet.addStyleName("favorites-tabs");
        tabsheet.addTab(favoriteEntryForm, i18n.translate("favorites.form.favorite.add"));
        tabsheet.addTab(favoriteGroupForm, i18n.translate("favorites.form.group.add"));

        tabsheet.addSelectedTabChangeListener(new SelectedTabChangeListener() {

            @Override
            public void selectedTabChange(SelectedTabChangeEvent event) {
                if (event.getTabSheet().getSelectedTab() instanceof InternalFavoriteEntryForm) {
                    favoriteGroupForm.removeEnterKeyShortcutListener();
                    favoriteEntryForm.addEnterKeyShortcutListener();
                } else {
                    favoriteEntryForm.removeEnterKeyShortcutListener();
                    favoriteGroupForm.addEnterKeyShortcutListener();
                }
            }
        });

        final CssLayout header = new CssLayout();
        header.addStyleName("dialog-header");
        header.setSizeFull();
        header.addLayoutClickListener(new LayoutClickListener() {
            @Override
            public void layoutClick(LayoutClickEvent event) {
                // change the visibility of the group- and favorite-items
                if (event.getClickedComponent() == editIcon || event.getChildComponent() == editLabel) {
                    if (!listener.hasItems() || listener.itemsAreEditable()) {
                        listener.setToInitialState();
                    } else {
                        listener.setItemsEditable(true);
                    }
                } else {
                    // just open || close the FavoritesForm
                    if (isOpen()) {
                        close();
                    } else {
                        open();
                    }
                }
            }
        });

        // add
        final Label addNewIcon = new Label();
        addNewIcon.setSizeUndefined();
        addNewIcon.addStyleName("icon");
        addNewIcon.addStyleName("icon-add-fav");
        final Label addNewLabel = new Label(i18n.translate("favorites.form.add"));
        addNewLabel.setSizeUndefined();
        addNewLabel.addStyleName("title");

        // edit
        editIcon = new Label();
        editIcon.setSizeUndefined();
        editIcon.addStyleName(EDIT_ACTION_STYLENAME);
        editIcon.addStyleName("icon");
        editIcon.addStyleName("icon-edit");

        editLabel = new Label(i18n.translate("favorites.form.favorite.edit"));
        editLabel.setSizeUndefined();
        editLabel.addStyleName("title");
        editLabel.addStyleName(EDIT_ACTION_STYLENAME);

        // arrow
        arrowIcon = new Label();
        arrowIcon.setSizeUndefined();
        arrowIcon.addStyleName("icon");
        arrowIcon.addStyleName("arrow");
        arrowIcon.addStyleName("icon-arrow2_n");

        // assemble
        header.addComponent(addNewIcon);
        header.addComponent(addNewLabel);
        header.addComponent(editIcon);
        header.addComponent(editLabel);
        header.addComponent(arrowIcon);
        favoriteForm.addComponent(header);
        favoriteForm.addComponent(tabsheet);

        // form is closed initially
        close();
        setCompositionRoot(favoriteForm);
    }

    public void setNewFavorite(Item newFavorite) {
        favoriteEntryForm.setDataSource(newFavorite);
    }

    public void setNewGroup(Item newGroup) {
        favoriteGroupForm.setDataSource(newGroup);
    }

    public void setAvailableGroups(Map<String, String> availableGroups) {
        favoriteEntryForm.setAvailableGroups(availableGroups);
    }

    public void setEditActionEnabled(boolean enabled) {
        if (!enabled) {
            editIcon.addStyleName("disabled");
            editLabel.addStyleName("disabled");
        } else {
            editIcon.removeStyleName("disabled");
            editLabel.removeStyleName("disabled");
        }
    }

    public void close() {
        tabsheet.setVisible(false);
        // reset form to its first tab when it is closed
        if (tabsheet.getSelectedTab() != favoriteEntryForm) {
            tabsheet.setSelectedTab(favoriteEntryForm);
        }
        arrowIcon.removeStyleName("icon-arrow2_s");
        arrowIcon.addStyleName("icon-arrow2_n");
        // remove key shortcut listener or this might compete with the next element getting the focus.
        favoriteEntryForm.removeEnterKeyShortcutListener();
        favoriteGroupForm.removeEnterKeyShortcutListener();
    }

    public void open() {
        tabsheet.setVisible(true);
        arrowIcon.removeStyleName("icon-arrow2_n");
        arrowIcon.addStyleName("icon-arrow2_s");
        favoriteEntryForm.addEnterKeyShortcutListener();
        // the group form will get the key shortcut listener attached on selecting it.
    }

    public boolean isOpen() {
        return tabsheet.isVisible();
    }

    /**
     * The form component displayed in the favorite tab.
     */
    private class InternalFavoriteEntryForm extends CustomComponent {

        private TextField url = new TextField(i18n.translate("favorites.form.location"));
        private TextField title = new TextField(i18n.translate("favorites.form.title"));
        private ComboBox group;

        private ShortcutListener enterShortcutListener;

        private final FieldGroup form;

        private Map<String, String> availableGroups;

        public InternalFavoriteEntryForm() {
            addStyleName("favorites-form-content");
            FormLayout layout = new FormLayout();

            title.setRequired(true);
            title.setDescription(i18n.translate("favorites.form.title")); // tooltip

            url.setRequired(true);
            url.setDescription(i18n.translate("favorites.form.location"));
            layout.addComponent(title);
            layout.addComponent(url);

            group = new ComboBox(i18n.translate("favorites.form.groups"));
            group.setNewItemsAllowed(true);
            group.setImmediate(false);
            group.setNewItemHandler(new AbstractSelect.NewItemHandler() {
                @Override
                public void addNewItem(String newItemCaption) {
                    String newGroupId = Path.getValidatedLabel(newItemCaption);
                    group.addItem(newGroupId);
                    group.setItemCaption(newGroupId, newItemCaption);
                    group.setValue(newGroupId);
                }
            });
            // the blur-listener below ensures "appropriate" behavior when adding a new value and then clicking tab -> to blur -> to go to add-button
            // without the listener the new value is NOT selected and sometimes not added (with tab, enter)
            // String value = event.getSource().toString() leads to a warning in the log-file and is discourage from VAADIN
            group.addBlurListener(new FieldEvents.BlurListener() {
                @Override
                public void blur(FieldEvents.BlurEvent event) {
                    String value = (String) group.getValue();
                    group.setValue(value);
                }
            });

            group.setDescription(i18n.translate("favorites.form.groups"));
            layout.addComponent(group);

            // Bind fields individually  binding members doesn't seem to work with initial (null) datasource
            form = new FieldGroup();
            form.bind(title, "title");
            form.bind(url, "url");
            form.bind(group, "group");

            final CssLayout buttons = new CssLayout();
            buttons.addStyleName("buttons");

            final Button addButton = new Button(i18n.translate("favorites.button.add"), new ClickListener() {

                @Override
                public void buttonClick(ClickEvent event) {
                    addFavorite();
                }
            });
            addButton.addStyleName("commit");
            buttons.addComponent(addButton);
            layout.addComponent(buttons);

            this.enterShortcutListener = new ShortcutListener("", KeyCode.ENTER, null) {

                @Override
                public void handleAction(Object sender, Object target) {
                    addFavorite();
                }
            };

            setCompositionRoot(layout);
        }

        void setDataSource(Item newFavorite) {
            form.setItemDataSource(newFavorite);
        }

        void setAvailableGroups(Map<String, String> availableGroups) {
            group.removeAllItems();
            for (Entry<String, String> entry : availableGroups.entrySet()) {
                String id = entry.getKey();
                group.addItem(id);
                group.setItemCaption(id, entry.getValue());
            }
            this.availableGroups = availableGroups;
        }

        public void addEnterKeyShortcutListener() {
            addShortcutListener(enterShortcutListener);
            title.focus();
        }

        public void removeEnterKeyShortcutListener() {
            removeShortcutListener(enterShortcutListener);
        }

        private void addFavorite() {
            try {
                JcrNewNodeAdapter newFavorite = (JcrNewNodeAdapter) form.getItemDataSource();
                form.commit();

                // since MGNLUI-2599 it is possible to add a group and a favorite (which then goes into the group) at the same time
                if (group == null || group.getValue() == null || !selectedGroupIsNew()) {
                    listener.addFavorite(newFavorite);
                } else {
                    JcrNewNodeAdapter newGroup = ((FavoritesPresenter) listener).createNewGroupSuggestion();
                    String newGroupId = (String) group.getValue();
                    String newGroupLabel = group.getItemCaption(newGroupId);
                    // must set the properties for the group here manually; properties of newFavorite are set in binder
                    newGroup.addItemProperty("group", new ObjectProperty<String>(newGroupId));
                    newGroup.addItemProperty("title", new ObjectProperty<String>(newGroupLabel));
                    listener.addFavoriteAndGroup(newFavorite, newGroup);
                }
                close(); // close form explicitly upon successful submit
            } catch (CommitException e) {
                shell.openNotification(MessageStyleTypeEnum.ERROR, true,
                        i18n.translate("favorites.fields.required"));
            }
        }

        private boolean selectedGroupIsNew() {
            if (availableGroups == null || availableGroups.size() == 0) {
                return true;
            } else {
                Object value = group.getValue();
                if (value != null && availableGroups != null && availableGroups.size() > 0) {
                    return !availableGroups.containsKey(value);
                }
            }
            return false;
        }

    }

    /**
     * The form component displayed in the group tab.
     */
    private class InternalFavoriteGroupForm extends CustomComponent {

        private TextField title = new TextField(i18n.translate("favorites.form.title"));

        private ShortcutListener enterShortcutListener;
        private final FieldGroup form;

        public InternalFavoriteGroupForm() {
            addStyleName("favorites-form-content");
            FormLayout layout = new FormLayout();

            title.setRequired(true);
            title.setDescription(i18n.translate("favorites.form.title"));// tooltip
            title.addStyleName("group-title");
            layout.addComponent(title);

            // Bind fields individually  binding members doesn't seem to work with initial (null) datasource
            form = new FieldGroup();
            form.bind(title, "title");

            final CssLayout buttons = new CssLayout();
            buttons.addStyleName("buttons");

            final Button addButton = new Button(i18n.translate("favorites.button.add"), new ClickListener() {

                @Override
                public void buttonClick(ClickEvent event) {
                    addGroup();
                }
            });
            addButton.addStyleName("v-button-commit");
            buttons.addComponent(addButton);
            layout.addComponent(buttons);

            this.enterShortcutListener = new ShortcutListener("", KeyCode.ENTER, null) {

                @Override
                public void handleAction(Object sender, Object target) {
                    addGroup();
                }
            };

            setCompositionRoot(layout);
        }

        void setDataSource(Item newGroup) {
            form.setItemDataSource(newGroup);
        }

        public void addEnterKeyShortcutListener() {
            addShortcutListener(enterShortcutListener);
            title.focus();
        }

        public void removeEnterKeyShortcutListener() {
            removeShortcutListener(enterShortcutListener);
        }

        private void addGroup() {
            try {
                JcrNewNodeAdapter newGroup = (JcrNewNodeAdapter) form.getItemDataSource();
                form.commit();
                listener.addGroup(newGroup);
                close(); // close form explicitly upon successful submit
            } catch (CommitException e) {
                shell.openNotification(MessageStyleTypeEnum.ERROR, true,
                        i18n.translate("favorites.fields.required"));
            }
        }
    }
}