org.opencms.gwt.client.seo.CmsAliasList.java Source code

Java tutorial

Introduction

Here is the source code for org.opencms.gwt.client.seo.CmsAliasList.java

Source

/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (C) Alkacon Software (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.gwt.client.seo;

import org.opencms.gwt.client.CmsCoreProvider;
import org.opencms.gwt.client.rpc.CmsRpcAction;
import org.opencms.gwt.client.ui.CmsPushButton;
import org.opencms.gwt.client.ui.I_CmsButton;
import org.opencms.gwt.client.ui.I_CmsButton.ButtonStyle;
import org.opencms.gwt.client.ui.css.I_CmsInputCss;
import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
import org.opencms.gwt.client.ui.input.CmsSelectBox;
import org.opencms.gwt.client.ui.input.CmsTextBox;
import org.opencms.gwt.client.util.CmsDomUtil;
import org.opencms.gwt.shared.alias.CmsAliasBean;
import org.opencms.gwt.shared.alias.CmsAliasMode;
import org.opencms.util.CmsUUID;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PushButton;

/**
 * A widget used for editing the alias list of a page.<p>
 */
public class CmsAliasList extends Composite {

    /**
     * A helper class which encapsulates the input widgets for a single alias.<p>
     */
    protected class AliasControls {

        /** The alias to which these controls belong. */
        protected CmsAliasBean m_alias;

        /** A string which uniquely identiy this set of controls. */
        protected String m_id = "" + (idCounter++); //$NON-NLS-1$

        /** The select box for selecting the alias mode. */
        protected CmsSelectBox m_selectBox;

        /** The text box for the alias path. */
        protected CmsTextBox m_textBox;

        /**
         * Creates a new alias controls instance.<p>
         *
         * @param alias the alias to which the controls belong
         * @param textBox the text box for entering the alias site path
         * @param selectBox the select box for selecting alias modes
         */
        public AliasControls(CmsAliasBean alias, CmsTextBox textBox, CmsSelectBox selectBox) {

            m_alias = alias;
            m_textBox = textBox;
            m_selectBox = selectBox;
        }

        /**
         * Gets the alias to which these controls belong.<p>
         *
         * @return the alias to which these controls belong
         */
        public CmsAliasBean getAlias() {

            return m_alias;
        }

        /**
         * Gets the id of this set of controls.<p>
         *
         * @return the id
         */
        public String getId() {

            return m_id;
        }

        /**
         * Gets the alias mode select box.<p>
         *
         * @return the alias mode select box
         */
        public CmsSelectBox getSelectBox() {

            return m_selectBox;
        }

        /**
         * Gets the text box for the alias site path.<p>
         *
         * @return the text box for the alias site path
         */
        public CmsTextBox getTextBox() {

            return m_textBox;
        }

    }

    /** The CSS bundle for input widgets. */
    public static final I_CmsInputCss INPUT_CSS = I_CmsInputLayoutBundle.INSTANCE.inputCss();

    /** The alias messages. */
    protected static CmsAliasMessages aliasMessages = new CmsAliasMessages();

    /** Static variable used to generate new ids. */
    protected static int idCounter;

    /** The callback which is normally used for validation of the site paths. */
    protected AsyncCallback<Map<String, String>> m_defaultValidationHandler = new AsyncCallback<Map<String, String>>() {

        public void onFailure(Throwable caught) {

            // do nothing
        }

        public void onSuccess(java.util.Map<String, String> result) {

            for (Map.Entry<String, String> entry : result.entrySet()) {
                String id = entry.getKey();
                String errorMessage = entry.getValue();
                AliasControls controls = m_aliasControls.get(id);
                controls.getTextBox().setErrorMessage(errorMessage);
                if (errorMessage != null) {
                    m_hasValidationErrors = true;
                }
            }
        }
    };

    /** A flag used to keep track of whether the last validation had any errors. */
    protected boolean m_hasValidationErrors;

    /** The structure id of the page for which the aliases are being edited. */
    protected CmsUUID m_structureId;

    /** A map containing the alias controls which are currently visible. */
    LinkedHashMap<String, AliasControls> m_aliasControls = new LinkedHashMap<String, AliasControls>();

    /** This panel contains the existing aliases. */
    private FlowPanel m_changeBox = new FlowPanel();

    /** This panel contains input widgets for adding new aliases. */
    private FlowPanel m_newBox = new FlowPanel();

    /** The root panel for this widget. */
    private FlowPanel m_panel = new FlowPanel();

    /**
     * Creates a new widget instance.<p>
     *
     * @param structureId the structure id of the page for which the aliases should be edited
     * @param aliases the aliases being edited
     */
    public CmsAliasList(CmsUUID structureId, List<CmsAliasBean> aliases) {

        initWidget(m_panel);

        m_panel.addStyleName(INPUT_CSS.highTextBoxes());
        m_structureId = structureId;
        Label newLabel = createLabel(aliasMessages.newAlias());
        m_panel.add(newLabel);
        m_panel.add(m_newBox);
        Label changeLabel = createLabel(aliasMessages.existingAliases());
        m_panel.add(changeLabel);
        m_panel.add(m_changeBox);
        init(aliases);
    }

    /**
     * Adds the controls for a single alias to the widget.<p>
     *
     * @param alias the alias for which the controls should be added
     */
    public void addAlias(final CmsAliasBean alias) {

        final HorizontalPanel hp = new HorizontalPanel();
        hp.getElement().getStyle().setMargin(2, Unit.PX);
        final CmsTextBox textbox = createTextBox();
        textbox.setFormValueAsString(alias.getSitePath());
        hp.add(textbox);

        CmsSelectBox selectbox = createSelectBox();
        selectbox.setFormValueAsString(alias.getMode().toString());
        hp.add(selectbox);
        PushButton deleteButton = createDeleteButton();
        hp.add(deleteButton);

        final AliasControls controls = new AliasControls(alias, textbox, selectbox);
        m_aliasControls.put(controls.getId(), controls);

        selectbox.addValueChangeHandler(new ValueChangeHandler<String>() {

            public void onValueChange(ValueChangeEvent<String> event) {

                onChangePath(controls);
            }
        });

        deleteButton.addClickHandler(new ClickHandler() {

            public void onClick(ClickEvent e) {

                m_aliasControls.remove(controls.getId());
                hp.removeFromParent();
                validateFull(m_structureId, getAliasPaths(), m_defaultValidationHandler);
            }
        });
        textbox.addValueChangeHandler(new ValueChangeHandler<String>() {

            public void onValueChange(ValueChangeEvent<String> e) {

                onChangePath(controls);
                validateFull(m_structureId, getAliasPaths(), m_defaultValidationHandler);
            }
        });

        textbox.addKeyPressHandler(new KeyPressHandler() {

            public void onKeyPress(KeyPressEvent event) {

                onChangePath(controls);
            }
        });
        m_changeBox.add(hp);
        CmsDomUtil.resizeAncestor(this);
    }

    /**
     * Clears the validation error flag.<p>
     */
    public void clearValidationErrors() {

        m_hasValidationErrors = false;
    }

    /**
     * Gets a list of the changed aliases.<p>
     *
     * @return a list of the aliases
     */
    public List<CmsAliasBean> getAliases() {

        List<CmsAliasBean> beans = new ArrayList<CmsAliasBean>();
        for (AliasControls controls : m_aliasControls.values()) {
            beans.add(controls.getAlias());
        }
        return beans;
    }

    /**
     * Gets a map of the current alias site paths, with the alias controls ids as the keys.<p>
     *
     * @return a map from control ids to alias site paths
     */
    public Map<String, String> getAliasPaths() {

        Map<String, String> paths = new HashMap<String, String>();
        for (AliasControls controls : m_aliasControls.values()) {
            paths.put(controls.getId(), controls.getAlias().getSitePath());
        }
        return paths;
    }

    /**
     * Checks whether there have been validation errors since the validation errors were cleared the last time.<p>
     *
     * @return true if there were validation errors
     */
    public boolean hasValidationErrors() {

        return m_hasValidationErrors;
    }

    /**
     * Initializes the alias controls.<p>
     *
     * @param aliases the existing aliases
     */
    public void init(List<CmsAliasBean> aliases) {

        for (CmsAliasBean alias : aliases) {
            addAlias(alias);
        }

        final HorizontalPanel hp = new HorizontalPanel();
        final CmsTextBox textbox = createTextBox();
        textbox.setGhostMode(true);
        textbox.setGhostValue(aliasMessages.enterAlias(), true);
        textbox.setGhostModeClear(true);
        hp.add(textbox);
        final CmsSelectBox selectbox = createSelectBox();
        hp.add(selectbox);
        PushButton addButton = createAddButton();
        hp.add(addButton);
        final Runnable addAction = new Runnable() {

            public void run() {

                textbox.setErrorMessage(null);
                validateSingle(m_structureId, getAliasPaths(), textbox.getText(), new AsyncCallback<String>() {

                    public void onFailure(Throwable caught) {

                        // shouldn't be called
                    }

                    public void onSuccess(String result) {

                        if (result == null) {
                            CmsAliasMode mode = CmsAliasMode.valueOf(selectbox.getFormValueAsString());
                            addAlias(new CmsAliasBean(textbox.getText(), mode));
                            textbox.setFormValueAsString("");
                        } else {
                            textbox.setErrorMessage(result);
                        }
                    }
                });
            }
        };

        ClickHandler clickHandler = new ClickHandler() {

            public void onClick(ClickEvent e) {

                addAction.run();
            }
        };
        addButton.addClickHandler(clickHandler);
        textbox.addKeyPressHandler(new KeyPressHandler() {

            public void onKeyPress(KeyPressEvent event) {

                int keycode = event.getNativeEvent().getKeyCode();
                if ((keycode == 10) || (keycode == 13)) {
                    addAction.run();
                }
            }
        });

        m_newBox.add(hp);
    }

    /**
     * Simplified method to perform a full validation of the aliases in the list and execute an action afterwards.<p>
     *
     * @param nextAction the action to execute after the validation finished
     */
    public void validate(final Runnable nextAction) {

        validateFull(m_structureId, getAliasPaths(), new AsyncCallback<Map<String, String>>() {

            public void onFailure(Throwable caught) {

                // do nothing

            }

            public void onSuccess(Map<String, String> result) {

                for (Map.Entry<String, String> entry : result.entrySet()) {
                    if (entry.getValue() != null) {
                        m_hasValidationErrors = true;
                    }
                }
                m_defaultValidationHandler.onSuccess(result);
                nextAction.run();
            }
        });
    }

    /**
     * Validates aliases.
     *
     * @param uuid The structure id for which the aliases should be valid
     * @param aliasPaths a map from id strings to alias paths
     * @param callback the callback which should be called with the validation results
     */
    public void validateAliases(final CmsUUID uuid, final Map<String, String> aliasPaths,
            final AsyncCallback<Map<String, String>> callback) {

        CmsRpcAction<Map<String, String>> action = new CmsRpcAction<Map<String, String>>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                start(200, true);
                CmsCoreProvider.getVfsService().validateAliases(uuid, aliasPaths, this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(Map<String, String> result) {

                stop(false);
                callback.onSuccess(result);
            }

        };
        action.execute();
    }

    /**
     * Creates the button used for adding new aliases.<p>
     *
     * @return the new button
     */
    protected PushButton createAddButton() {

        PushButton button = createIconButton(I_CmsButton.ADD_SMALL);
        button.setTitle(aliasMessages.addAlias());
        return button;
    }

    /**
     * Creates the button used for deleting aliases.<p>
     *
     * @return the new button
     */
    protected PushButton createDeleteButton() {

        PushButton button = createIconButton(I_CmsButton.DELETE_SMALL);
        button.setTitle(aliasMessages.removeAlias());
        return button;
    }

    /**
     * Creates an icon button for editing aliases.<p>
     *
     * @param icon the icon css class to use
     *
     * @return the new icon button
     */
    protected PushButton createIconButton(String icon) {

        CmsPushButton button = new CmsPushButton();
        button.setImageClass(icon);
        button.setButtonStyle(ButtonStyle.FONT_ICON, null);
        return button;
    }

    /**
     * Creates a label for this widget.<p>
     *
     * @param text the text to display in the label
     *
     * @return the created label
     */
    protected Label createLabel(String text) {

        Label label = new Label(text);
        Style style = label.getElement().getStyle();
        style.setMarginTop(10, Unit.PX);
        style.setMarginBottom(4, Unit.PX);
        style.setFontWeight(FontWeight.BOLD);
        return label;
    }

    /**
     * Creates the select box for selecting alias modes.<p>
     *
     * @return the select box for selecting alias modes
     */
    protected CmsSelectBox createSelectBox() {

        CmsSelectBox selectbox = new CmsSelectBox();
        selectbox.setTitle(CmsAliasMode.page.toString(), aliasMessages.pageDescription());
        selectbox.setTitle(CmsAliasMode.redirect.toString(), aliasMessages.redirectDescription());
        selectbox.setTitle(CmsAliasMode.permanentRedirect.toString(), aliasMessages.movedDescription());
        selectbox.addOption(CmsAliasMode.page.toString(), aliasMessages.optionPage());
        selectbox.addOption(CmsAliasMode.redirect.toString(), aliasMessages.optionRedirect());
        selectbox.addOption(CmsAliasMode.permanentRedirect.toString(), aliasMessages.optionMoved());

        selectbox.getElement().getStyle().setWidth(190, Unit.PX);
        selectbox.getElement().getStyle().setMarginRight(5, Unit.PX);
        return selectbox;
    }

    /**
     * Creates a text box for entering an alias path.<p>
     *
     * @return the new text box
     */
    protected CmsTextBox createTextBox() {

        CmsTextBox textbox = new CmsTextBox();
        textbox.getElement().getStyle().setWidth(325, Unit.PX);
        textbox.getElement().getStyle().setMarginRight(5, Unit.PX);
        return textbox;
    }

    /**
     * This method is called when an alias path changes.<p>
     *
     * @param controls the alias controls
     */
    protected void onChangePath(AliasControls controls) {

        CmsTextBox textbox = controls.getTextBox();
        CmsAliasBean alias = controls.getAlias();
        CmsSelectBox selectbox = controls.getSelectBox();
        String text = textbox.getText();
        alias.setSitePath(text);
        alias.setMode(CmsAliasMode.valueOf(selectbox.getFormValueAsString()));
    }

    /**
     * Performs a validation of the current list of aliases in the widget.<p>
     *
     * @param structureId the resource's structure id
     * @param sitePaths the map from ids to alias site paths
     *
     * @param errorCallback the callback to invoke when the validation finishes
     */
    protected void validateFull(CmsUUID structureId, Map<String, String> sitePaths,
            final AsyncCallback<Map<String, String>> errorCallback) {

        validateAliases(structureId, sitePaths, errorCallback);
    }

    /**
     * Validation method used when adding a new alias.<p>
     *
     * @param structureId the structure id
     * @param sitePaths the site paths
     * @param newSitePath the new site path
     * @param errorCallback on error callback
     */
    protected void validateSingle(CmsUUID structureId, Map<String, String> sitePaths, String newSitePath,
            final AsyncCallback<String> errorCallback) {

        Map<String, String> newMap = new HashMap<String, String>(sitePaths);
        newMap.put("NEW", newSitePath); //$NON-NLS-1$
        AsyncCallback<Map<String, String>> callback = new AsyncCallback<Map<String, String>>() {

            public void onFailure(Throwable caught) {

                assert false; // should never happen
            }

            public void onSuccess(Map<String, String> result) {

                String newRes = result.get("NEW"); //$NON-NLS-1$
                errorCallback.onSuccess(newRes);
            }
        };
        validateAliases(structureId, newMap, callback);
    }
}