org.eclipse.skalli.view.component.LinkWindow.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.skalli.view.component.LinkWindow.java

Source

/*******************************************************************************
 * Copyright (c) 2010-2014 SAP AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     SAP AG - initial API and implementation
 *******************************************************************************/
package org.eclipse.skalli.view.component;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.lang.StringUtils;
import org.eclipse.skalli.commons.Link;
import org.eclipse.skalli.model.ext.linkgroups.LinkGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.Validatable;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.EmptyValueException;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.terminal.UserError;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractSelect.NewItemHandler;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.Field;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

public class LinkWindow extends Window {

    private static final long serialVersionUID = 7764538915405149666L;
    private static final Logger LOG = LoggerFactory.getLogger(LinkWindow.class);

    private final ThemeResource ICON_BUTTON_OK = new ThemeResource("icons/button/ok.png"); //$NON-NLS-1$

    private final Component parent;
    private final Collection<String> knownGroups;
    private final ILinkAddedHandler linkAddedHandler;

    private final ILinkModifiedHandler linkModifiedHandler;
    private final LinkGroup oldGroup;
    private final Link link;

    private VerticalLayout root;

    /**
     * @param parent  the calling component
     * @param linkGroups  groups that are added to the combo box
     * @param linkAddedHandler callback implementation
     */
    public LinkWindow(Component parent, Collection<LinkGroup> linkGroups, ILinkAddedHandler linkAddedHandler) {
        this.parent = parent;
        this.knownGroups = new ArrayList<String>(linkGroups.size());
        this.linkAddedHandler = linkAddedHandler;
        this.linkModifiedHandler = null;
        this.oldGroup = null;
        this.link = null;

        for (LinkGroup linkGroup : linkGroups) {
            this.knownGroups.add(linkGroup.getCaption());
        }

        createContents("Add Link");
    }

    public LinkWindow(Component parent, Collection<LinkGroup> linkGroups, LinkGroup oldGroup, Link link,
            ILinkModifiedHandler linkModifiedHandler) {
        this.parent = parent;
        this.knownGroups = new ArrayList<String>(linkGroups.size());
        this.linkAddedHandler = null;
        this.linkModifiedHandler = linkModifiedHandler;
        this.oldGroup = oldGroup;
        this.link = link;

        for (LinkGroup linkGroup : linkGroups) {
            this.knownGroups.add(linkGroup.getCaption());
        }

        createContents("Edit Link");
    }

    /**
     * Render the window
     */
    @SuppressWarnings("serial")
    private void createContents(String title) {
        setModal(true);
        setCaption(title);

        setWidth("400px"); //$NON-NLS-1$
        setHeight("300px"); //$NON-NLS-1$

        root = new VerticalLayout();
        root.setMargin(true);
        root.setSpacing(true);

        final ComboBox cbLinkGroup = new ComboBox("Link Group");
        cbLinkGroup.setInputPrompt("Enter a new group name or select from the list");
        cbLinkGroup.setWidth("100%"); //$NON-NLS-1$
        for (String groupName : knownGroups) {
            cbLinkGroup.addItem(groupName);
        }
        if (oldGroup != null && knownGroups.contains(oldGroup.getCaption())) {
            cbLinkGroup.select(oldGroup.getCaption());
        }
        cbLinkGroup.setImmediate(true);
        cbLinkGroup.setNullSelectionAllowed(false);
        cbLinkGroup.setNewItemsAllowed(true);
        cbLinkGroup.setNewItemHandler(new NewItemHandler() {
            @Override
            public void addNewItem(String newGroupName) {
                cbLinkGroup.removeAllItems();
                for (String groupName : knownGroups) {
                    cbLinkGroup.addItem(groupName);
                }
                if (!cbLinkGroup.containsId(newGroupName)) {
                    cbLinkGroup.addItem(newGroupName);
                }
                cbLinkGroup.select(newGroupName);
            }
        });
        cbLinkGroup.setRequired(true);
        cbLinkGroup.addValidator(new StringValidator());
        root.addComponent(cbLinkGroup);

        final TextField tfLinkCaption = new TextField("Page Title");
        tfLinkCaption.setInputPrompt("Enter a descriptive name for the page");
        tfLinkCaption.setWidth("100%"); //$NON-NLS-1$
        tfLinkCaption.setImmediate(true);
        tfLinkCaption.setRequired(true);
        tfLinkCaption.addValidator(new StringValidator());
        if (link != null) {
            tfLinkCaption.setValue(link.getLabel());
        }
        root.addComponent(tfLinkCaption);

        final TextField tfLinkURL = new TextField("URL");
        tfLinkURL.setInputPrompt("e.g. http://www.your-site.domain/path");
        tfLinkURL.setWidth("100%"); //$NON-NLS-1$
        tfLinkURL.setImmediate(true);
        tfLinkURL.setRequired(true);
        tfLinkURL.addValidator(new StringValidator());
        tfLinkURL.addValidator(new URLValidator());
        if (link != null) {
            tfLinkURL.setValue(link.getUrl());
        }
        root.addComponent(tfLinkURL);

        final Button okAndCloseButton = new Button("OK & Close");
        okAndCloseButton.setIcon(ICON_BUTTON_OK);
        okAndCloseButton.setDescription("Performs the action and closes the dialog.");
        okAndCloseButton.addListener(new Button.ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                validateInput(cbLinkGroup);
                validateInput(tfLinkURL);
                validateInput(tfLinkCaption);

                if (cbLinkGroup.isValid() && tfLinkURL.isValid() && tfLinkCaption.isValid()) {
                    String groupName = String.valueOf(cbLinkGroup.getValue());
                    String linkLabel = String.valueOf(tfLinkCaption.getValue());
                    String linkUrl = String.valueOf(tfLinkURL.getValue());

                    if (linkAddedHandler != null) {
                        Link link = new Link(linkUrl, linkLabel);
                        linkAddedHandler.onLinkAdded(groupName, link);
                        close();
                    }

                    if (linkModifiedHandler != null) {
                        boolean linkModified = !link.getLabel().equals(linkLabel) || !link.getUrl().equals(linkUrl);
                        link.setLabel(linkLabel);
                        link.setUrl(linkUrl);
                        linkModifiedHandler.onLinkModified(oldGroup, groupName, link, linkModified);
                        close();
                    }
                }
            }
        });
        root.addComponent(okAndCloseButton);

        root.setSizeFull();
        setContent(root);
    }

    /**
     * Display this window.
     *
     * Typically called from the outside when the window was instantiated.
     */
    public void show() {
        parent.getWindow().addWindow(this);
    }

    private void validateInput(Validatable validatable) {
        try {
            validatable.validate();
        } catch (EmptyValueException e) {
            final AbstractComponent component = (AbstractComponent) validatable;
            component.setComponentError(new UserError("This field is required."));
            ((Field) component).addListener(new ValueNotLongerEmptyListener());
        } catch (InvalidValueException e) {
            // Automatically handled by validator implementations (onValueChange)
            LOG.debug("Invalid value", e); //$NON-NLS-1$
        }
    }

    /**
     * Removes the (manually set) component error in case the property isn't blank anymore.
     */
    private final class ValueNotLongerEmptyListener implements ValueChangeListener {

        private static final long serialVersionUID = -1568052404052787122L;

        @Override
        public void valueChange(ValueChangeEvent event) {
            Property property = event.getProperty();
            if (property != null) {
                Object value = property.getValue();
                if (StringUtils.isNotBlank((String) value)) {
                    ((AbstractComponent) property).setComponentError(null);
                }
            }
        }
    }

    /**
     * Checks for 'not empty' and no trailing/leading white spaces
     */
    private final class StringValidator implements Validator {

        private static final long serialVersionUID = 383201426094234832L;

        @Override
        public void validate(Object value) throws InvalidValueException {
            String stringValue = (String) value;

            if (StringUtils.isBlank(stringValue)) {
                throw new InvalidValueException("This field must not be blank.");
            }
            if (StringUtils.trimToEmpty(stringValue).length() != stringValue.length()) {
                throw new InvalidValueException("This field must not contain trailing or leading spaces.");
            }
        }

        @Override
        public boolean isValid(Object value) {
            try {
                validate(value);
            } catch (InvalidValueException e) {
                return false;
            }
            return true;
        }
    }

    /**
     * Checks for a valid URL pattern
     */
    private final class URLValidator implements Validator {

        private static final long serialVersionUID = -7840893696280942983L;

        @Override
        public void validate(Object value) throws InvalidValueException {
            String stringValue = (String) value;

            try {
                new URL(stringValue);
            } catch (MalformedURLException e) {
                throw new InvalidValueException("The URL is malformed.");
            }
        }

        @Override
        public boolean isValid(Object value) {
            try {
                validate(value);
            } catch (InvalidValueException e) {
                return false;
            }
            return true;
        }
    }

    /**
     * Callback interface for components that open this window (case 'add').
     */
    public interface ILinkAddedHandler {
        public void onLinkAdded(String groupName, Link link);
    }

    /**
     * Callback interface for components that open this window (case 'edit').
     */
    public interface ILinkModifiedHandler {
        public void onLinkModified(LinkGroup oldGroup, String newGroupName, Link link, boolean linkModified);
    }

}