org.vaadin.notifique.Notifique.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.notifique.Notifique.java

Source

/*
 * Copyright 2010 Sami Ekblad, 2013 Haulmont Development
 *
 * 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 org.vaadin.notifique;

import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.server.Resource;
import com.vaadin.ui.*;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.themes.Reindeer;
import org.vaadin.jouni.animator.AnimatorProxy;
import org.vaadin.jouni.animator.shared.AnimType;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Notifique extends CustomComponent {

    /**
     * Built-in message styles.
     */
    public interface Styles extends Serializable {
        static String INFO = "info";
        static String SUCCESS = "success";
        static String WARNING = "warning";
        static String ERROR = "error";
        static String MESSAGE = "message";
        static String MAGIC_BLACK = "magic-black";
        static String MAGIC_GRAY = "magic-gray";
        static String MAGIC_WHITE = "magic-white";
        static String BROWSER_FF = "ff";
        static String BROWSER_FF3 = "ff3";
        static String BROWSER_IE = "ie";
        static String BROWSER_CHROME = "chrome";
        static String VAADIN_BLACK = "vaadin-black";
        static String VAADIN_BEIGE = "vaadin-beige";
        static String VAADIN_RED = "vaadin-red";
        static String VAADIN_GREEN = "vaadin-green";
        static String VAADIN_BLUE = "vaadin-blue";
        static String VAADIN_ORANGE = "vaadin-orange";
    }

    /**
     * Listener interface for message clicks.
     */
    public interface ClickListener extends Serializable {

        public void messageClicked(Message message);

    }

    /**
     * Listener interface for message close events.
     */
    public interface HideListener extends Serializable {

        public void messageHide(Message message);

    }

    private static final String STYLE_QUEUE = "queue";
    private static final String STYLE_ITEM = "item";
    private static final String STYLE_CLOSE = "close";

    private static final long serialVersionUID = -4838466600618368413L;

    private Panel root;
    private CssLayout css;
    private List<Message> items = new LinkedList<>();
    private boolean autoScroll;
    private int visibleCount = 5;
    private boolean fillFromTop = false;
    private HideListener hideListener;
    private ClickListener clickListener;
    private AnimatorProxy ap;
    protected List<AnimatorProxy.Animation> runningAnimations = new ArrayList<>();

    public class Message implements Serializable {
        private static final long serialVersionUID = 5892777954593320723L;
        private Component component;
        private CssLayout animatedContent;
        private boolean visible;
        private Object data;

        private void show() {
            runningAnimations
                    .add(ap.animate(animatedContent, AnimType.ROLL_DOWN_OPEN).setDuration(200).setDelay(0));
            visible = true;
        }

        public void hide() {
            if (!isVisible()) {
                return;
            }
            ap.animate(animatedContent, AnimType.ROLL_UP_CLOSE_REMOVE).setDuration(200).setDelay(0);
            visible = false;
            if (getHideListener() != null) {
                getHideListener().messageHide(this);
            }
        }

        public Component getComponent() {
            return component;
        }

        public boolean isVisible() {
            return visible;
        }

        public void setData(Object data) {
            this.data = data;
        }

        public Object getData() {
            return data;
        }

        public Notifique getNotifique() {
            return Notifique.this;
        }

        public CssLayout getAnimatedContent() {
            return animatedContent;
        }

        public void setAnimatedContent(CssLayout animatedContent) {
            this.animatedContent = animatedContent;
        }
    }

    /**
    //     * Custom animator extension allowing us to react on hide events coming from
    //     * client-side.
    //     *
    //     * We use this to actually remove the components from layout after they have
    //     * been animated away.
    //     *
    //     * @author Sami Ekblad
    //     *
    //     */
    //    public class MessageAnimator extends Animator {
    //        private static final long serialVersionUID = 1L;
    //
    //        @Override
    //        public void changeVariables(Object source, Map<String, Object> variables) {
    //            boolean wasHidden = isRolledUp();
    //            super.changeVariables(source, variables);
    //            if (!wasHidden && isRolledUp()) {
    //                removeAfterHide(this);
    //            } else if (!isRolledUp() && !fillFromTop) {
    //                root.setScrollTop(10000);
    //                root.requestRepaint(); // TODO
    //            }
    //        }
    //
    //        public MessageAnimator(Component toAnimate) {
    //            super(toAnimate);
    //            setWidth("100%");
    //        }
    //    }

    public Notifique(boolean autoScroll) {
        ap = new AnimatorProxy();
        css = new CssLayout();
        root = new Panel(css);
        root.setStyleName(Reindeer.PANEL_LIGHT);
        css.setWidth("100%");
        css.addComponent(ap);
        ap.addListener(new AnimatorProxy.AnimationListener() {
            @Override
            public void onAnimation(AnimatorProxy.AnimationEvent animationEvent) {
                if (animationEvent.getAnimation().getType().equals(AnimType.ROLL_LEFT_CLOSE_REMOVE)
                        || AnimType.ROLL_UP_CLOSE_REMOVE.equals(animationEvent.getAnimation().getType())) {
                    removeComponentMessage(animationEvent.getComponent());
                }
            }
        });
        root.addStyleName(STYLE_QUEUE);
        root.getContent().setStyleName(STYLE_QUEUE);
        setCompositionRoot(root);
        this.autoScroll = autoScroll;
    }

    protected void removeComponentMessage(Component component) {
        if (component == null)
            return;

        Iterator<Message> iterator = items.iterator();
        while (iterator().hasNext()) {
            Message msg = iterator.next();
            if (component.equals(msg.getAnimatedContent())) {
                iterator.remove();
                return;
            }
        }
    }

    /**
     * Publish a message.
     *
     * @param m
     */
    protected void publish(Message m) {
        synchronized (items) {
            if (fillFromTop) {
                items.add(0, m);
                ((CssLayout) root.getContent()).addComponentAsFirst(m.animatedContent);
            } else {
                items.add(m);
                css.addComponent(m.animatedContent);
            }
            m.show();
            if (autoScroll && items.size() > getVisibleCount()) {
                Message hideThis = fillFromTop ? items.get(items.size() - 1) : items.get(0);
                items.remove(hideThis);
                hideThis.hide();
            }
        }
    }

    //    /**
    //     * Remove the item after it has been hidden.
    //     *
    //     * @param toBeRemoved
    //     */
    //    private void removeAfterHide(MessageAnimator toBeRemoved) {
    //        synchronized (items) {
    //            Message removed = null;
    //            for (Message m : items) {
    //                if (m.animatedContent.equals(toBeRemoved)) {
    //                    removed = m;
    //                    break;
    //                }
    //            }
    //
    //            if (removed != null) {
    //                css.removeComponent(removed.animatedContent);
    //                items.remove(removed);
    //            }
    //        }
    //    }

    /**
     * Create a new item into the queue. It is not visible until added with
     */
    protected Message createMessage(final Component component, String style) {

        final Message m = new Message();

        // Wrap to a CssLayout (this is needed for styling and sizing correctly)
        CssLayout css = new CssLayout();
        css.setWidth("100%");
        css.setStyleName(Notifique.STYLE_ITEM);
        css.addStyleName(style != null ? style : Styles.MESSAGE);
        css.addComponent(component);

        // Wrap component into an animator
        m.component = component;
        m.animatedContent = css;

        return m;
    }

    public Message add(Resource icon, String htmlMessage, String style) {
        return add(icon, htmlMessage, true, style, true);
    }

    public Message add(Resource icon, String message, boolean allowHTML, String style, boolean showCloseButton) {

        // A Label for the message
        Component l = createContentFor(message, allowHTML);
        return add(icon, l, style, showCloseButton);
    }

    public Message add(Resource icon, Component component, String style, boolean showCloseButton) {

        HorizontalLayout lo = new HorizontalLayout();
        lo.setSpacing(true);
        lo.setWidth("100%");

        final Message i = createMessage(lo, style);
        publish(i);

        // Add icon if given
        if (icon != null) {
            lo.addComponent(new Embedded(null, icon));
        }

        lo.addComponent(component);
        lo.setExpandRatio(component, 1f);
        lo.setComponentAlignment(component, Alignment.MIDDLE_LEFT);

        // Close button if requested
        if (showCloseButton) {
            Button close = createCloseButtonFor(i);
            if (close != null) {
                lo.addComponent(close);
            }
        }

        // Listen for clicks
        lo.addListener(new LayoutClickListener() {
            private static final long serialVersionUID = 7524442205441374595L;

            public void layoutClick(LayoutClickEvent event) {
                if (getClickListener() != null) {
                    getClickListener().messageClicked(i);
                }
            }
        });

        return i;
    }

    /**
     * Remove all messages.
     */
    public void clear() {
        synchronized (items) {
            final LinkedList<Component> l = new LinkedList<>();

            for (final Iterator<Component> i = css.getComponentIterator(); i.hasNext();) {
                l.add(i.next());
            }

            for (final Iterator<Component> i = l.iterator(); i.hasNext();) {
                Component component = i.next();
                if (component instanceof CssLayout) {
                    css.removeComponent(component);
                }
            }
            items.clear();

            //unfortunately we can not directly remove animation from AnimationProxy.queue
            //so we need to cancel them to prevent adding them to the PaintTarget
            for (AnimatorProxy.Animation runningAnimation : runningAnimations)
                runningAnimation.cancel();
            runningAnimations.clear();
        }
    }

    /**
     * Get current size of the queue.
     */
    public int size() {
        synchronized (items) {
            return items.size();
        }
    }

    /**
     * Set number of messages visible at once.
     * This is only meaningful if autoScroll is true.
     */
    public void setVisibleCount(int visibleItems) {
        visibleCount = visibleItems;
    }

    /**
     * Add new items to the top rather than the end of the list.
     */
    public void setFillFromTop(boolean fillFromTop) {
        this.fillFromTop = fillFromTop;
    }

    /**
     * Add new items to the top rather than the end of the list.
     */
    public boolean isFillFromTop() {
        return fillFromTop;
    }

    /**
     * Get number of messages visible at once.
     *
     * This is only meaningful if autoScroll is true.
     */
    public int getVisibleCount() {
        return visibleCount;
    }

    @Override
    public void setHeight(String height) {
        super.setHeight(height);
        root.setHeight(height);
    }

    @Override
    public void setWidth(String width) {
        super.setWidth(width);
        root.setWidth(width);
    }

    /**
     * Create a close button for a message.
     */
    protected Button createCloseButtonFor(final Message i) {
        Button b = new Button();
        b.addListener(new Button.ClickListener() {
            private static final long serialVersionUID = -1932127150282887613L;

            public void buttonClick(ClickEvent event) {
                i.hide();

            }
        });
        b.setStyleName(Reindeer.BUTTON_LINK);
        b.addStyleName(STYLE_CLOSE);
        return b;
    }

    protected Component createContentFor(String string, boolean allowHTML) {
        Label l = new Label(string, allowHTML ? Label.CONTENT_RAW : Label.CONTENT_TEXT);
        return l;
    }

    /**
     * Set the click listener to receive item (message) hide events.
     *
     */

    public void setHideListener(HideListener hideListener) {
        this.hideListener = hideListener;
    }

    public HideListener getHideListener() {
        return hideListener;
    }

    /**
     * Set the click listener to receive item (message) clikcs.
     *
     */
    public void setClickListener(ClickListener clickListener) {
        this.clickListener = clickListener;
    }

    public ClickListener getClickListener() {
        return clickListener;
    }

}