package de.dhbw.humbuch.view;
import java.util.Locale;
import java.util.NoSuchElementException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.annotations.Widgetset;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.Navigator.ComponentContainerViewDisplay;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.StreamResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import de.davherrmann.guice.vaadin.ScopedUI;
import de.davherrmann.mvvm.BasicState;
import de.davherrmann.mvvm.StateChangeListener;
import de.davherrmann.mvvm.ViewModelComposer;
import de.davherrmann.mvvm.annotations.BindState;
import de.dhbw.humbuch.event.ConfirmEvent;
import de.dhbw.humbuch.event.MessageEvent;
import de.dhbw.humbuch.util.ResourceLoader;
import de.dhbw.humbuch.view.components.ConfirmDialog;
import de.dhbw.humbuch.view.components.Header;
import de.dhbw.humbuch.view.components.PrintingComponent;
import de.dhbw.humbuch.view.components.PrintingComponent.MIMEType;
import de.dhbw.humbuch.view.components.Sidebar;
import de.dhbw.humbuch.viewmodel.LoginViewModel;
import de.dhbw.humbuch.viewmodel.LoginViewModel.IsLoggedIn;
/**
* The main UI class responsible for building the main layout and providing a
* {@link Navigator} for navigating through {@link View}s. Additionally
* {@link ConfirmEvent}s and {@link MessageEvent}s are handled.
*
* @author Johannes Idelhauser
* @author Henning Muszynski
* @author David Herrmann
* @author David Vitt
* @author Martin Junker
*/
@Theme("humbuch")
@SuppressWarnings("serial")
@Widgetset("com.vaadin.DefaultWidgetSet")
@Title("HumBuch Schulbuchverwaltung")
public class MainUI extends ScopedUI {
private final static Logger LOG = LoggerFactory.getLogger(MainUI.class);
public static final String LOGIN_VIEW = "login_view";
public static final String BOOK_MANAGEMENT_VIEW = "book_management_view";
public static final String DUNNING_VIEW = "dunning_view";
public static final String LENDING_VIEW = "lending_view";
public static final String RETURN_VIEW = "return_view";
public static final String STUDENT_INFORMATION_VIEW = "student_information_view";
public static final String SETTINGS_VIEW = "settings_view";
public static final String ERROR_VIEW = "error_view";
@Inject
private LoginView loginView;
@Inject
private DunningView dunningView;
@Inject
private LendingView lendingView;
@Inject
private ReturnView returnView;
@Inject
private TeachingMaterialView bookManagementView;
@Inject
private StudentInformationView studentInformationView;
@Inject
private SettingsView settingsView;
@Inject
private ErrorView errorView;
private Header header = new Header();
private VerticalLayout viewContainer = new VerticalLayout();;
private GridLayout root;
private ComponentContainerViewDisplay ccViewDisplay;
private Sidebar sidebar;
private Panel panelContent = new Panel();
private View currentView;
private LoginViewModel loginViewModel;
public Navigator navigator;
@BindState(IsLoggedIn.class)
private BasicState<Boolean> isLoggedIn = new BasicState<Boolean>(Boolean.class);
@Inject
public MainUI(ViewModelComposer viewModelComposer, LoginViewModel loginViewModel, EventBus eventBus, MVVMConfig mvvmConfig) {
this.loginViewModel = loginViewModel;
eventBus.register(this);
bindViewModel(viewModelComposer, loginViewModel);
}
@Override
protected void init(VaadinRequest request) {
getUI().getSession().setLocale(new Locale("de", "DE"));
ccViewDisplay = new ComponentContainerViewDisplay(viewContainer);
navigator = new Navigator(UI.getCurrent(), ccViewDisplay);
navigator.setErrorView(errorView);
navigator.addView("", lendingView);
navigator.addView(LOGIN_VIEW, loginView);
navigator.addView(BOOK_MANAGEMENT_VIEW, bookManagementView);
navigator.addView(DUNNING_VIEW, dunningView);
navigator.addView(LENDING_VIEW, lendingView);
navigator.addView(RETURN_VIEW, returnView);
navigator.addView(STUDENT_INFORMATION_VIEW, studentInformationView);
navigator.addView(SETTINGS_VIEW, settingsView);
// Make the displayed view as big as possible
viewContainer.setSizeFull();
if (!isLoggedIn.get()) {
buildMainView(true);
} else {
buildMainView(false);
}
attachListener();
}
/**
* Build the MainView with header, navigation bar and footer
*
* @param cancel
* Whether the MainView should be build or not
*/
private void buildMainView(boolean cancel) {
if (cancel) {
setContent(viewContainer);
return;
}
root = new GridLayout(2, 2);
header.setWidth("100%");
sidebar = new Sidebar();
sidebar.setWidth("150px");
sidebar.getLogoutButton().addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
loginViewModel.doLogout(new Object());
}
});
panelContent.setContent(viewContainer);
panelContent.setSizeFull();
root.setSizeFull();
root.setRowExpandRatio(1, 1);
root.setColumnExpandRatio(0, 0);
root.setColumnExpandRatio(1, 1);
root.addStyleName("main-view");
root.addComponent(panelContent, 1, 1);
root.addComponent(header, 1, 0);
root.addComponent(sidebar, 0, 0, 0, 1);
setContent(root);
}
/**
* Attaches all listeners to the components.
*/
private void attachListener() {
/**
* Checks if the user is logged in before the view changes
*/
navigator.addViewChangeListener(new ViewChangeListener() {
@Override
public boolean beforeViewChange(ViewChangeEvent event) {
currentView = event.getNewView();
boolean isLoginView = currentView instanceof LoginView;
if (!isLoggedIn.get() && !isLoginView) {
// Redirect to login view always if a user has not yet
// logged in
getNavigator().navigateTo(MainUI.LOGIN_VIEW);
return false;
} else if (isLoggedIn.get() && isLoginView) {
// If someone tries to access to login view while logged in,
// then cancel
return false;
}
return true;
}
@Override
public void afterViewChange(ViewChangeEvent event) {
if (isLoggedIn.get()) {
View newView = event.getNewView();
if (newView instanceof ViewInformation) {
ViewInformation view = (ViewInformation) newView;
panelContent.setCaption(((ViewInformation) view)
.getTitle());
sidebar.changeMenuBarSelection(event.getViewName());
} else {
LOG.warn("New View does not implement ViewInformation interface."
+ " Could not set caption of panel correctly.");
}
}
}
});
/**
* Listens for a login or logout of a user an constructs the UI
* accordingly
*/
isLoggedIn.addStateChangeListener(new StateChangeListener() {
@Override
public void stateChange(Object arg0) {
if (isLoggedIn.get()) {
buildMainView(false);
} else {
buildMainView(true);
getNavigator().navigateTo(MainUI.LOGIN_VIEW);
}
}
});
/**
* Adds the help HTML to the help button.
*/
header.getHelpButton().addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
String name = "help/" + currentView.getClass().getSimpleName() + ".html";
ResourceLoader res = new ResourceLoader(name);
StreamResource sr = new StreamResource(res, "Hilfe");
new PrintingComponent(sr, "Hilfe", MIMEType.HTML);
}
});
}
/**
* Handles {@link MessageEvent}s showing the message in a Vaadin
* {@link Notification}
*
* @param messageEvent
* {@link MessageEvent} containing the message to show
*/
@Subscribe
public void handleMessageEvent(MessageEvent messageEvent) {
Type notificationType;
switch (messageEvent.type) {
case ERROR:
notificationType = Type.ERROR_MESSAGE;
break;
case WARNING:
notificationType = Type.WARNING_MESSAGE;
break;
case TRAYINFO:
notificationType = Type.TRAY_NOTIFICATION;
break;
case INFO:
default:
notificationType = Type.HUMANIZED_MESSAGE;
}
Notification.show(messageEvent.caption, messageEvent.message, notificationType);
}
/**
* Handles {@link ConfirmEvent}s showing a window with a cancel and a
* confirm button.
*
* @param confirmEvent
* {@link ConfirmEvent}s containing the confirmable information
*/
@Subscribe
public void handleConfirmEvent(final ConfirmEvent confirmEvent) {
ConfirmDialog.show(confirmEvent.caption, confirmEvent.message,
confirmEvent.confirmCaption, confirmEvent.cancelCaption,
new ConfirmDialog.Listener() {
@Override
public void onClose(ConfirmDialog dialog) {
if (dialog.isConfirmed()) {
confirmEvent.confirm();
} else {
confirmEvent.cancel();
}
}
});
}
private void bindViewModel(ViewModelComposer viewModelComposer,
Object... viewModels) {
try {
viewModelComposer.bind(this, viewModels);
} catch (IllegalAccessException | NoSuchElementException
| UnsupportedOperationException e) {
e.printStackTrace();
}
}
}