org.vaadin.tori.component.RecentBar.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.tori.component.RecentBar.java

Source

/*
 * Copyright 2014 Vaadin Ltd.
 * 
 * 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.tori.component;

import org.ocpsoft.prettytime.PrettyTime;
import org.vaadin.tori.ToriApiLoader;
import org.vaadin.tori.ToriNavigator;
import org.vaadin.tori.ToriUI;
import org.vaadin.tori.data.DataSource;
import org.vaadin.tori.data.entity.DiscussionThread;
import org.vaadin.tori.data.entity.Post;
import org.vaadin.tori.exception.DataSourceException;
import org.vaadin.tori.util.ComponentUtil;
import org.vaadin.tori.util.ComponentUtil.HeadingLevel;
import org.vaadin.tori.util.ToriActivityMessaging;
import org.vaadin.tori.util.ToriActivityMessaging.UserAuthoredListener;
import org.vaadin.tori.util.ToriScheduler;
import org.vaadin.tori.util.ToriScheduler.ScheduledCommand;
import org.vaadin.tori.view.listing.SpecialCategory;

import com.vaadin.server.ExternalResource;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;

@SuppressWarnings("serial")
public class RecentBar extends CustomComponent implements UserAuthoredListener {

    private PostNotification previous;
    private PostNotification current;
    private final FloatingNotification floatingNotification = new FloatingNotification();
    private final FloatingComponent floatingComponent = new FloatingComponent();

    private final DataSource dataSource = ToriApiLoader.getCurrent().getDataSource();
    private CssLayout notificationsLayout;
    private final ToriActivityMessaging messaging = ToriApiLoader.getCurrent().getToriActivityMessaging();

    public RecentBar() {
        if (messaging != null) {
            messaging.addUserAuthoredListener(this);
            ToriUI.getCurrent().addDetachListener(new DetachListener() {
                @Override
                public void detach(final DetachEvent event) {
                    messaging.removeUserAuthoredListener(RecentBar.this);
                }
            });
        }

        addStyleName("recentbar");
        setWidth(100.0f, Unit.PERCENTAGE);
        setHeight(35.0f, Unit.PIXELS);

        CssLayout layout = new CssLayout();
        layout.setSizeFull();
        setCompositionRoot(layout);

        HorizontalLayout barLayout = new HorizontalLayout();
        barLayout.setMargin(new MarginInfo(false, true, false, true));
        barLayout.setSizeFull();
        addTitleLabel(barLayout);
        addNotificationsLayout(barLayout);
        addRecentLink(barLayout);
        if (dataSource.isLoggedInUser()) {
            addMyPostsLink(barLayout);
        }
        layout.addComponent(barLayout);

        floatingComponent.extend(floatingNotification);
        layout.addComponent(floatingNotification);
        floatingNotification.setId("floatingnotification");

        ToriScheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
                refresh();
            }
        });
    }

    private void addMyPostsLink(final HorizontalLayout barLayout) {
        Link link = new Link("My Posts",
                new ExternalResource("#" + ToriNavigator.ApplicationView.CATEGORIES.getUrl() + "/"
                        + SpecialCategory.MY_POSTS.getId().toLowerCase()));
        link.addStyleName("mypostslink");
        barLayout.addComponent(link);
        barLayout.setComponentAlignment(link, Alignment.MIDDLE_RIGHT);
    }

    private void addRecentLink(final HorizontalLayout barLayout) {
        Link link = new Link("Recent Posts",
                new ExternalResource("#" + ToriNavigator.ApplicationView.CATEGORIES.getUrl() + "/"
                        + SpecialCategory.RECENT_POSTS.getId().toLowerCase()));
        link.addStyleName("recentlink");
        barLayout.addComponent(link);
        barLayout.setComponentAlignment(link, Alignment.MIDDLE_RIGHT);
    }

    private void addNotificationsLayout(final HorizontalLayout barLayout) {
        notificationsLayout = new CssLayout();
        notificationsLayout.setSizeFull();
        notificationsLayout.addStyleName("notificationslayout");
        barLayout.addComponent(notificationsLayout);
        barLayout.setExpandRatio(notificationsLayout, 1.0f);
        barLayout.setComponentAlignment(notificationsLayout, Alignment.MIDDLE_LEFT);
    }

    private void addTitleLabel(final HorizontalLayout barLayout) {
        Label headingLabel = ComponentUtil.getHeadingLabel("MOST RECENT", HeadingLevel.H4);
        headingLabel.setWidth(110.0f, Unit.PIXELS);
        barLayout.addComponent(headingLabel);
        barLayout.setComponentAlignment(headingLabel, Alignment.MIDDLE_LEFT);
    }

    @Override
    public void userAuthored(final long postId, final long threadId) {
        try {
            getUI().access(new Runnable() {
                @Override
                public void run() {
                    try {
                        refresh();
                    } catch (RuntimeException e) {
                        // Ignore
                    }
                }
            });
        } catch (RuntimeException e) {
            // Ignore
        }
    }

    private void newPostAdded(final Post post) {
        if (previous != null) {
            notificationsLayout.removeComponent(previous);
        }
        previous = current;
        current = new PostNotification(post);
        notificationsLayout.addComponent(current);
        floatingNotification.setLink(post.getThread().getTopic(), PostNotification.getPermaLinkUrl(post));
        floatingComponent.flash();

        ToriScheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
                previous.setState(PostNotificationState.PREVIOUS);
                current.setState(PostNotificationState.CURRENT);
            }
        });
    }

    private enum PostNotificationState {
        PREVIOUS, CURRENT, NEXT
    }

    public static class PostNotification extends HorizontalLayout {
        private final PrettyTime prettyTime = new PrettyTime();
        private final long postId;

        public PostNotification(final Post post) {
            this.postId = post.getId();
            setSpacing(true);
            Link link = new Link(post.getThread().getTopic(), new ExternalResource(getPermaLinkUrl(post)));
            StringBuilder infoText = new StringBuilder("by ");
            infoText.append(post.getAuthor().getDisplayedName()).append(", ")
                    .append(prettyTime.format(post.getTime()));
            Label info = new Label(infoText.toString());
            addComponents(link, info);
            setState(PostNotificationState.NEXT);
        }

        public void setState(final PostNotificationState state) {
            setStyleName("postnotification " + state.name().toLowerCase());
        }

        private static String getPermaLinkUrl(final Post post) {
            // @formatter:off
            final String linkUrl = String.format("#%s/%s/%s", ToriNavigator.ApplicationView.THREADS.getUrl(),
                    post.getThread().getId(), post.getId());
            // @formatter:on
            return linkUrl;
        }

        public long getPostId() {
            return postId;
        }
    }

    public static class FloatingNotification extends CssLayout {

        private final Link link;

        public FloatingNotification() {
            addStyleName("floatingnotification");
            Label label = new Label("New post in");
            label.setSizeUndefined();
            addComponent(label);

            link = new Link();
            addComponent(link);
        }

        public void setLink(final String caption, final String url) {
            link.setCaption(caption);
            link.setResource(new ExternalResource(url));
        }
    }

    public static RecentBar getCurrent() {
        return ToriUI.getCurrent().getRecentBar();
    }

    public void refresh() {
        try {
            DiscussionThread recentThread = null;

            try {
                int count = dataSource.getThreadCountRecursively(null);
                for (int i = 0; i < count; i++) {
                    DiscussionThread thread = dataSource.getRecentPosts(i, Math.min(i + 1, count - 1)).get(0);
                    boolean newerThread = recentThread == null
                            || thread.getLatestPost().getTime().after(recentThread.getLatestPost().getTime());
                    recentThread = newerThread ? thread : recentThread;
                    if (!thread.isSticky()) {
                        break;
                    }
                }
            } catch (IndexOutOfBoundsException e) {
                // No recent threads
            }

            if (recentThread != null) {
                Post latestPost = recentThread.getLatestPost();
                if (latestPost != null) {
                    latestPost.setThread(recentThread);
                    if (current == null) {
                        current = new PostNotification(latestPost);
                        current.setState(PostNotificationState.CURRENT);
                        notificationsLayout.addComponent(current);
                    } else {
                        long latestId = latestPost.getId();
                        long currentId = current.getPostId();
                        if (latestId != currentId) {
                            newPostAdded(latestPost);
                        }
                    }
                }
            }
        } catch (DataSourceException e) {
            e.printStackTrace();
        }
    }
}