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

Java tutorial

Introduction

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

Source

/*
 * Copyright 2012 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 java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
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.Category;
import org.vaadin.tori.data.entity.DiscussionThread;
import org.vaadin.tori.exception.DataSourceException;
import org.vaadin.tori.mvp.AbstractView;
import org.vaadin.tori.service.AuthorizationService;
import org.vaadin.tori.util.ComponentUtil;
import org.vaadin.tori.util.ToriScheduler;
import org.vaadin.tori.util.ToriScheduler.ScheduledCommand;
import org.vaadin.tori.view.listing.ListingView;
import org.vaadin.tori.view.thread.ThreadView;
import org.vaadin.tori.view.thread.newthread.NewThreadView;

import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.ExternalResource;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
public class Breadcrumbs extends CustomComponent implements ViewChangeListener {

    static final String STYLE_CRUMB = "crumb";
    static final String STYLE_THREAD = "thread";
    static final String STYLE_CATEGORY = "category";

    private HorizontalLayout crumbsLayout;
    private Label viewCaption;
    private final DataSource dataSource = ToriApiLoader.getCurrent().getDataSource();
    private final String pageTitlePrefix = dataSource.getConfiguration().getPageTitlePrefix();
    private final AuthorizationService authorizationService = ToriApiLoader.getCurrent().getAuthorizationService();

    private Button followButton;
    private long threadId;

    public Breadcrumbs() {
        setStyleName("tori-breadcrumbs");
        ToriNavigator.getCurrent().addViewChangeListener(this);

        final VerticalLayout mainLayout = new VerticalLayout();
        mainLayout.setMargin(new MarginInfo(false, true, false, true));
        mainLayout.addComponent(buildCrumbsLayout());
        mainLayout.addComponent(buildCaptionLayout());
        setCompositionRoot(mainLayout);
    }

    private Component buildCaptionLayout() {
        viewCaption = new Label("");
        viewCaption.setStyleName("viewcaption");

        final HorizontalLayout captionLayout = new HorizontalLayout(viewCaption);
        captionLayout.setSpacing(true);
        captionLayout.setWidth(100.0f, Unit.PERCENTAGE);
        captionLayout.setExpandRatio(viewCaption, 1.0f);

        followButton = buildFollowButton();
        captionLayout.addComponent(followButton);

        return captionLayout;
    }

    private Button buildFollowButton() {
        Button result = new Button();
        result.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(final ClickEvent event) {
                try {
                    if (dataSource.isFollowingThread(threadId)) {
                        dataSource.unfollowThread(threadId);
                        Notification.show("Topic unfollowed");
                    } else {
                        dataSource.followThread(threadId);
                        Notification.show("Following topic");
                    }
                    updateFollowButtonStyle();
                } catch (Exception e) {
                    e.printStackTrace();
                    Notification.show(DataSourceException.GENERIC_ERROR_MESSAGE, Type.ERROR_MESSAGE);
                }
            }
        });

        return result;
    }

    public void updateFollowButtonStyle() {
        followButton.setVisible(authorizationService.mayFollowThread(threadId));
        followButton.setStyleName(dataSource.isFollowingThread(threadId) ? "followed" : "notfollowed");
    }

    private Component buildCrumbsLayout() {
        crumbsLayout = new HorizontalLayout();
        crumbsLayout.setHeight(22.0f, Unit.PIXELS);
        crumbsLayout.setStyleName("breadcrumbs-layout");
        return crumbsLayout;
    }

    @Override
    public void afterViewChange(final ViewChangeEvent event) {
        viewCaption.setValue(null);
        viewCaption.setStyleName("viewcaption");
        followButton.setVisible(false);

        final View view = event.getNewView();

        if (view instanceof AbstractView) {
            String viewTitle = ((AbstractView<?, ?>) view).getTitle();
            final Long urlParameterId = ((AbstractView<?, ?>) view).getUrlParameterId();
            viewCaption.setValue(viewTitle);
            if (view instanceof NewThreadView) {
                crumbsLayout.removeAllComponents();
                Long categoryId = ((AbstractView) view).getUrlParameterId();
                try {
                    Category category = dataSource.getCategory(categoryId);
                    prependLink(category);
                } catch (DataSourceException e) {
                    e.printStackTrace();
                }
            } else if (urlParameterId == null) {
                crumbsLayout.removeAllComponents();
                viewCaption.setValue(getDashboardTitle());
            } else {
                ToriScheduler.get().scheduleDeferred(new ScheduledCommand() {
                    @Override
                    public void execute() {
                        crumbsLayout.removeAllComponents();
                        buildCrumbs(view, urlParameterId);
                    }
                });
            }
        }

    }

    private void buildCrumbs(final View view, final Long urlParameterId) {
        Category parentCategory = null;
        if (view instanceof ThreadView) {
            try {
                DiscussionThread thread = dataSource.getThread(urlParameterId);
                if (thread.isLocked()) {
                    viewCaption.addStyleName("lockedthread");
                }
                if (thread.isSticky()) {
                    viewCaption.addStyleName("stickythread");
                }

                followButton.setVisible(true);
                threadId = thread.getId();
                updateFollowButtonStyle();
                parentCategory = thread.getCategory();
            } catch (Exception e) {
                ((ThreadView) view).showError("No topic found");
                e.printStackTrace();
                ToriNavigator.getCurrent().navigateToDashboard();
            }
        } else if (view instanceof ListingView) {
            if (urlParameterId != 0) {
                try {
                    Category category = dataSource.getCategory(urlParameterId);
                    parentCategory = category.getParentCategory();
                } catch (DataSourceException e) {
                    e.printStackTrace();
                }
            }
        }

        prependLink(parentCategory);

        for (Iterator<Component> iter = crumbsLayout.iterator(); iter.hasNext();) {
            crumbsLayout.setComponentAlignment(iter.next(), Alignment.MIDDLE_CENTER);
        }
    }

    private void prependLink(final Category category) {
        if (category == null) {
            crumbsLayout.addComponent(getDashboardLink(), 0);
        } else {
            crumbsLayout.addComponent(getCategoryLink(category), 0);
            prependLink(category.getParentCategory());
        }
    }

    private Component getDashboardLink() {
        Link link = new Link(getDashboardTitle(),
                new ExternalResource("#" + ToriNavigator.ApplicationView.DASHBOARD.getUrl()));
        link.setHeight(100.0f, Unit.PERCENTAGE);
        return link;
    }

    private String getDashboardTitle() {
        return pageTitlePrefix != null ? pageTitlePrefix : "Tori";
    }

    private Component getCategoryLink(final Category category) {
        HorizontalLayout result = new HorizontalLayout();
        result.setSpacing(true);
        result.setHeight(100.0f, Unit.PERCENTAGE);
        result.addStyleName("categorylink");
        final Link crumb = new Link(category.getName(), new ExternalResource(
                "#" + ToriNavigator.ApplicationView.CATEGORIES.getUrl() + "/" + category.getId()));
        crumb.setHeight(100.0f, Unit.PERCENTAGE);
        result.addComponent(crumb);
        result.setComponentAlignment(crumb, Alignment.MIDDLE_CENTER);
        Component siblingMenu = getSiblingMenuBar(category);
        siblingMenu.setHeight(100.0f, Unit.PERCENTAGE);
        result.addComponent(siblingMenu);
        result.setComponentAlignment(siblingMenu, Alignment.MIDDLE_CENTER);
        return result;
    }

    private Component getSiblingMenuBar(final Category category) {
        final MenuBar menuBar = ComponentUtil.getDropdownMenu();
        final MenuItem topItem = menuBar.getMoreMenuItem();
        // Lazily populate the menubar
        ToriScheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
                if (!topItem.hasChildren()) {
                    populateSiblingMenu(topItem, category);
                }
            }
        });
        return menuBar;
    }

    protected void populateSiblingMenu(final MenuItem topItem, final Category category) {
        try {
            Category parent = category.getParentCategory();
            Long parentId = parent != null ? parent.getId() : null;
            final List<Category> siblings = dataSource.getSubCategories(parentId);
            for (final Category sibling : siblings) {
                if (authorizationService.mayViewCategory(sibling.getId())) {
                    topItem.addItem(sibling.getName(), new Command() {
                        @Override
                        public void menuSelected(final MenuItem selectedItem) {
                            ToriNavigator.getCurrent().navigateToCategory(sibling.getId());
                        }
                    });
                }
            }
        } catch (final DataSourceException e) {
            getLogger().error(e);
            e.printStackTrace();
        }
    }

    private static Logger getLogger() {
        return Logger.getLogger(Breadcrumbs.class);
    }

    @Override
    public boolean beforeViewChange(final ViewChangeEvent event) {
        return true;
    }

    public static Breadcrumbs getCurrent() {
        return ToriUI.getCurrent().getBreadcrumbs();
    }
}