package org.sigmah.client.ui.view.project.dashboard;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.Date;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.ui.presenter.project.dashboard.PhasesPresenter;
import org.sigmah.client.ui.presenter.project.dashboard.ProjectDashboardPresenter;
import org.sigmah.client.ui.presenter.project.dashboard.ProjectDashboardPresenter.PresenterHandler;
import org.sigmah.client.ui.res.icon.IconImageBundle;
import org.sigmah.client.ui.view.base.AbstractView;
import org.sigmah.client.ui.widget.FlexibleGrid;
import org.sigmah.client.ui.widget.button.Button;
import org.sigmah.client.ui.widget.layout.Layouts;
import org.sigmah.client.ui.widget.layout.Layouts.Margin;
import org.sigmah.client.ui.widget.panel.Panels;
import org.sigmah.client.util.DateUtils;
import org.sigmah.shared.dto.ProjectDTO;
import org.sigmah.shared.dto.ProjectFundingDTO;
import org.sigmah.shared.dto.ProjectFundingDTO.LinkedProjectType;
import org.sigmah.shared.dto.base.AbstractModelDataEntityDTO;
import org.sigmah.shared.dto.reminder.MonitoredPointDTO;
import org.sigmah.shared.dto.reminder.ReminderDTO;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.store.StoreFilter;
import com.extjs.gxt.ui.client.store.StoreSorter;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Label;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem;
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
/**
* {@link ProjectDashboardPresenter} view implementation.
*
* @author Denis Colliot (dcolliot@ideia.fr)
*/
@Singleton
public class ProjectDashboardView extends AbstractView implements ProjectDashboardPresenter.View {
// CSS style names.
private static final String STYLE_TOOLBAR_TITLE = "toolbar-title";
@Inject
private Provider<PhasesPresenter> phasesPresenterProvider;
private PhasesPresenter phasesPresenter;
private Grid<ReminderDTO> remindersGrid;
private ToolBar remindersToolbar;
private Button reminderAddButton;
private Grid<MonitoredPointDTO> monitoredPointsGrid;
private ToolBar monitoredPointsToolbar;
private Button monitoredPointsAddButton;
private ContentPanel fundingProjectsPanel;
private Grid<ProjectFundingDTO> fundingProjectsGrid;
private ToolBar fundingProjectsToolbar;
private Button fundingProjectsSelectButton;
private Button fundingProjectsCreateButton;
private ContentPanel fundedProjectsPanel;
private Grid<ProjectFundingDTO> fundedProjectsGrid;
private ToolBar fundedProjectsToolbar;
private Button fundedProjectsSelectButton;
private Button fundedProjectsCreateButton;
private LinkedProjectsColumnsProvider fundingProjectsColumnsProvider;
/**
* Specific presenter's handlers.
*/
private PresenterHandler handler;
/**
* {@inheritDoc}
*/
@Override
public void initialize() {
// --
// Center panel.
// --
add(createProjectDashboardPanel(), Layouts.borderLayoutData(LayoutRegion.CENTER, Margin.LEFT));
// --
// East panel.
// --
final ContentPanel remindersPanel = Panels.content(I18N.CONSTANTS.reminders(), false, Layouts.vBoxLayout());
remindersPanel.add(createRemindersPanel(), Layouts.vBoxData());
remindersPanel.add(createMonitoredPointsPanel(), Layouts.vBoxData());
final BorderLayoutData eastData = Layouts.borderLayoutData(LayoutRegion.WEST, Layouts.LEFT_COLUMN_WIDTH);
eastData.setCollapsible(true);
add(remindersPanel, eastData);
// --
// South panel.
// --
final BorderLayoutData southData = Layouts.borderLayoutData(LayoutRegion.SOUTH, Layouts.SOUTH_PANEL_HEIGHT, Margin.TOP);
southData.setCollapsible(true);
add(createLinkedProjectsPanel(), southData);
}
/**
* Returns the presenter specific handlers implementation.
*
* @return The presenter specific handlers implementation.
*/
final PresenterHandler getPresenterHandler() {
return handler;
}
/**
* {@inheritDoc}
*/
@Override
public void setPresenterHandler(final PresenterHandler handler) {
this.handler = handler;
}
/**
* {@inheritDoc}
*/
@Override
public Grid<ReminderDTO> getRemindersGrid() {
return remindersGrid;
}
/**
* {@inheritDoc}
*/
@Override
public Grid<MonitoredPointDTO> getMonitoredPointsGrid() {
return monitoredPointsGrid;
}
/**
* {@inheritDoc}
*/
@Override
public Button getReminderAddButton() {
return reminderAddButton;
}
/**
* {@inheritDoc}
*/
@Override
public Button getMonitoredPointsAddButton() {
return monitoredPointsAddButton;
}
/**
* {@inheritDoc}
*/
@Override
public void updateRemindersToolbars(final boolean canEditReminders, final boolean canEditMonitoredPoints) {
reminderAddButton.setEnabled(canEditReminders);
if (remindersToolbar.indexOf(reminderAddButton) != -1) {
remindersToolbar.remove(reminderAddButton);
}
if (canEditReminders) {
remindersToolbar.insert(reminderAddButton, 0);
}
monitoredPointsAddButton.setEnabled(canEditMonitoredPoints);
if (monitoredPointsToolbar.indexOf(monitoredPointsAddButton) != -1) {
monitoredPointsToolbar.remove(monitoredPointsAddButton);
}
if (canEditMonitoredPoints) {
monitoredPointsToolbar.insert(monitoredPointsAddButton, 0);
}
}
/**
* {@inheritDoc}
*/
@Override
public void updateLinkedProjectsToolbars(final boolean canRelateProject, final boolean canCreateProject) {
fundingProjectsToolbar.removeAll();
fundedProjectsToolbar.removeAll();
final Label fundingTitle = new Label(I18N.CONSTANTS.projectFinancialProjectsHeader());
fundingTitle.addStyleName(STYLE_TOOLBAR_TITLE);
final Label fundedTitle = new Label(I18N.CONSTANTS.projectLocalPartnerProjectsHeader());
fundedTitle.addStyleName(STYLE_TOOLBAR_TITLE);
fundingProjectsToolbar.add(fundingTitle);
fundedProjectsToolbar.add(fundedTitle);
if (canRelateProject) {
fundingProjectsToolbar.add(new SeparatorToolItem());
fundedProjectsToolbar.add(new SeparatorToolItem());
fundingProjectsToolbar.add(fundingProjectsSelectButton);
fundedProjectsToolbar.add(fundedProjectsSelectButton);
}
if (canCreateProject) {
fundingProjectsToolbar.add(new SeparatorToolItem());
fundedProjectsToolbar.add(new SeparatorToolItem());
fundingProjectsToolbar.add(fundingProjectsCreateButton);
fundedProjectsToolbar.add(fundedProjectsCreateButton);
}
}
/**
* {@inheritDoc}
*/
@Override
public Grid<ProjectFundingDTO> getFundingProjectsGrid() {
return fundingProjectsGrid;
}
/**
* {@inheritDoc}
*/
@Override
public Button getFundingProjectSelectButton() {
return fundingProjectsSelectButton;
}
/**
* {@inheritDoc}
*/
@Override
public Button getFundingProjectCreateButton() {
return fundingProjectsCreateButton;
}
/**
* {@inheritDoc}
*/
@Override
public Grid<ProjectFundingDTO> getFundedProjectsGrid() {
return fundedProjectsGrid;
}
/**
* {@inheritDoc}
*/
@Override
public Button getFundedProjectSelectButton() {
return fundedProjectsSelectButton;
}
/**
* {@inheritDoc}
*/
@Override
public Button getFundedProjectCreateButton() {
return fundedProjectsCreateButton;
}
/**
* {@inheritDoc}
*/
@Override
public PhasesPresenter getPhasesWidget() {
return phasesPresenter;
}
/**
* {@inheritDoc}
*/
@Override
public LinkedProjectsColumnsProvider getFundingProjectsColumnsProvider() {
return fundingProjectsColumnsProvider;
}
/**
* {@inheritDoc}
*/
@Override
public void layoutView() {
layoutContainer.layout();
}
/**
* Creates the panel which displays the reminders.
*
* @return The panel which displays the reminders.
*/
private Component createRemindersPanel() {
// --
// Store filters.
// --
final StoreFilter<ReminderDTO> notCompletedFilter = new StoreFilter<ReminderDTO>() {
@Override
public boolean select(Store<ReminderDTO> store, ReminderDTO parent, ReminderDTO item, String property) {
return !item.isCompleted();
}
};
final StoreFilter<ReminderDTO> completedFilter = new StoreFilter<ReminderDTO>() {
@Override
public boolean select(Store<ReminderDTO> store, ReminderDTO parent, ReminderDTO item, String property) {
return item.isCompleted();
}
};
final StoreFilter<ReminderDTO> exceededFilter = new StoreFilter<ReminderDTO>() {
@Override
public boolean select(Store<ReminderDTO> store, ReminderDTO parent, ReminderDTO item, String property) {
return !item.isCompleted() && DateUtils.DAY_COMPARATOR.compare(new Date(), item.getExpectedDate()) > 0;
}
};
// --
// Store.
// --
final ListStore<ReminderDTO> remindersStore = new ListStore<ReminderDTO>();
// --
// Grid.
// --
remindersGrid = new Grid<ReminderDTO>(remindersStore, new RemindersColumnsProvider(this).getRemindersColumnModel());
remindersGrid.getView().setForceFit(true);
remindersGrid.setBorders(false);
remindersGrid.setAutoExpandColumn(ReminderDTO.LABEL);
// --
// Filter menu.
// --
final FilterSelectionListener<ReminderDTO> filterListener = new FilterSelectionListener<ReminderDTO>(remindersStore);
final Menu filterMenu = new Menu();
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointAll(), null, filterListener, null));
filterMenu.add(new SeparatorMenuItem());
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointCompleted(), IconImageBundle.ICONS.closedReminder(), filterListener, completedFilter));
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointUncompleted(), IconImageBundle.ICONS.openedReminder(), filterListener, notCompletedFilter));
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointExceeded(), IconImageBundle.ICONS.overdueReminder(), filterListener, exceededFilter));
// Fires manually the first filter (no filter).
filterListener.filter((MenuItem) filterMenu.getItem(0), null);
// Filter button.
final Button filterButton = new Button(I18N.CONSTANTS.filter(), IconImageBundle.ICONS.filter());
filterButton.setMenu(filterMenu);
// --
// Toolbar.
// --
reminderAddButton = new Button(I18N.CONSTANTS.addItem(), IconImageBundle.ICONS.add());
remindersToolbar = new ToolBar();
remindersToolbar.setAlignment(HorizontalAlignment.LEFT);
remindersToolbar.add(filterButton);
// --
// Panel.
// --
final ContentPanel panel = Panels.content(I18N.CONSTANTS.reminderPoints());
panel.setTopComponent(remindersToolbar);
panel.add(remindersGrid);
final Menu menuContext = new Menu();
menuContext.add(new MenuItem(I18N.CONSTANTS.historyShow(), new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(final MenuEvent ce) {
final ReminderDTO selectedReminder = remindersGrid.getSelectionModel() != null ? remindersGrid.getSelectionModel().getSelectedItem() : null;
if (selectedReminder == null) {
// A reminder has to be selected to show its history.
return;
}
handler.onShowHistoryEvent(selectedReminder);
}
}));
remindersGrid.setContextMenu(menuContext);
return panel;
}
/**
* Creates the panel which displays the monitored points.
*
* @return The panel which displays the monitored points.
*/
private Component createMonitoredPointsPanel() {
// --
// Store filters.
// --
final StoreFilter<MonitoredPointDTO> notCompletedFilter = new StoreFilter<MonitoredPointDTO>() {
@Override
public boolean select(Store<MonitoredPointDTO> store, MonitoredPointDTO parent, MonitoredPointDTO item, String property) {
return !item.isCompleted();
}
};
final StoreFilter<MonitoredPointDTO> completedFilter = new StoreFilter<MonitoredPointDTO>() {
@Override
public boolean select(Store<MonitoredPointDTO> store, MonitoredPointDTO parent, MonitoredPointDTO item, String property) {
return item.isCompleted();
}
};
final StoreFilter<MonitoredPointDTO> exceededFilter = new StoreFilter<MonitoredPointDTO>() {
@Override
public boolean select(Store<MonitoredPointDTO> store, MonitoredPointDTO parent, MonitoredPointDTO item, String property) {
return !item.isCompleted() && DateUtils.DAY_COMPARATOR.compare(new Date(), item.getExpectedDate()) > 0;
}
};
// --
// Store.
// --
final ListStore<MonitoredPointDTO> monitoredPointsStore = new ListStore<MonitoredPointDTO>();
// --
// Grid.
// --
monitoredPointsGrid = new Grid<MonitoredPointDTO>(monitoredPointsStore, new RemindersColumnsProvider(this).getMonitoredPointsColumnModel());
monitoredPointsGrid.getView().setForceFit(true);
monitoredPointsGrid.setBorders(false);
monitoredPointsGrid.setAutoExpandColumn(MonitoredPointDTO.LABEL);
// --
// Filter menu.
// --
final FilterSelectionListener<MonitoredPointDTO> filterListener = new FilterSelectionListener<MonitoredPointDTO>(monitoredPointsStore);
final Menu filterMenu = new Menu();
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointAll(), null, filterListener, null));
filterMenu.add(new SeparatorMenuItem());
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointCompleted(), IconImageBundle.ICONS.closedReminder(), filterListener, completedFilter));
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointUncompleted(), IconImageBundle.ICONS.openedReminder(), filterListener, notCompletedFilter));
filterMenu.add(buildFilterMenu(I18N.CONSTANTS.monitoredPointExceeded(), IconImageBundle.ICONS.overdueReminder(), filterListener, exceededFilter));
// Fires manually the first filter (no filter).
filterListener.filter((MenuItem) filterMenu.getItem(0), null);
// Filter button.
final Button filterButton = new Button(I18N.CONSTANTS.filter(), IconImageBundle.ICONS.filter());
filterButton.setMenu(filterMenu);
// --
// Toolbar.
// --
monitoredPointsAddButton = new Button(I18N.CONSTANTS.addItem(), IconImageBundle.ICONS.add());
monitoredPointsToolbar = new ToolBar();
monitoredPointsToolbar.setAlignment(HorizontalAlignment.LEFT);
monitoredPointsToolbar.add(filterButton);
// --
// Panel.
// --
final ContentPanel panel = Panels.content(I18N.CONSTANTS.monitoredPoints());
panel.setTopComponent(monitoredPointsToolbar);
panel.add(monitoredPointsGrid);
final Menu menuContext = new Menu();
menuContext.add(new MenuItem(I18N.CONSTANTS.historyShow(), new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(final MenuEvent ce) {
final MonitoredPointDTO selectedPoint =
monitoredPointsGrid.getSelectionModel() != null ? monitoredPointsGrid.getSelectionModel().getSelectedItem() : null;
if (selectedPoint == null) {
// A monitored point has to be selected to show its history.
return;
}
handler.onShowHistoryEvent(selectedPoint);
}
}));
monitoredPointsGrid.setContextMenu(menuContext);
return panel;
}
/**
* Creates linked projects panel.
*
* @return The component.
*/
private Component createLinkedProjectsPanel() {
final ContentPanel panel = Panels.content(I18N.CONSTANTS.projectLinkedProjects(), false, Layouts.hBoxLayout());
final String subPanelsWidth = "50%";
// --
// Funding projects panel.
// --
fundingProjectsPanel = Panels.content(null);
fundingProjectsPanel.setWidth(subPanelsWidth);
fundingProjectsSelectButton = new Button(I18N.CONSTANTS.createProjectTypeFundingSelect(), IconImageBundle.ICONS.select());
fundingProjectsSelectButton.setTitle(I18N.CONSTANTS.createProjectTypeFundingSelectDetails());
fundingProjectsCreateButton = new Button(I18N.CONSTANTS.createProjectTypeFundingCreate(), IconImageBundle.ICONS.add());
fundingProjectsCreateButton.setTitle(I18N.CONSTANTS.createProjectTypeFundingCreateDetails());
// --
// Funding projects store + grid.
// --
// The grid sorter.
final StoreSorter<ProjectFundingDTO> storeSorter = new StoreSorter<ProjectFundingDTO>() {
@Override
public int compare(Store<ProjectFundingDTO> store, ProjectFundingDTO m1, ProjectFundingDTO m2, String property) {
if (ProjectDTO.NAME.equals(property)) {
return m1.getFunding().getName().compareTo(m2.getFunding().getName());
} else if (ProjectDTO.FULL_NAME.equals(property)) {
return m1.getFunding().getFullName().compareTo(m2.getFunding().getFullName());
} else {
return super.compare(store, m1, m2, property);
}
}
};
// Builds the grid.
final ListStore<ProjectFundingDTO> fundingProjectsStore = new ListStore<ProjectFundingDTO>();
fundingProjectsStore.setStoreSorter(storeSorter);
this.fundingProjectsColumnsProvider = new LinkedProjectsColumnsProvider(this, LinkedProjectType.FUNDING_PROJECT);
fundingProjectsGrid =
new FlexibleGrid<ProjectFundingDTO>(fundingProjectsStore, null, 2,
fundingProjectsColumnsProvider.getLinkedProjectsColumnModel());
fundingProjectsGrid.setAutoExpandColumn(ProjectDTO.NAME);
fundingProjectsToolbar = new ToolBar();
fundingProjectsPanel.setTopComponent(fundingProjectsToolbar);
fundingProjectsPanel.add(fundingProjectsGrid);
// --
// Funded projects panel.
// --
fundedProjectsPanel = Panels.content(null);
fundedProjectsPanel.setWidth(subPanelsWidth);
fundedProjectsSelectButton = new Button(I18N.CONSTANTS.createProjectTypePartnerSelect(), IconImageBundle.ICONS.select());
fundedProjectsSelectButton.setTitle(I18N.CONSTANTS.createProjectTypePartnerSelectDetails());
fundedProjectsCreateButton = new Button(I18N.CONSTANTS.createProjectTypePartnerCreate(), IconImageBundle.ICONS.add());
fundedProjectsCreateButton.setTitle(I18N.CONSTANTS.createProjectTypePartnerCreateDetails());
// --
// Funded projects store + grid.
// --
// Builds the grid.
final ListStore<ProjectFundingDTO> fundedProjectsStore = new ListStore<ProjectFundingDTO>();
fundedProjectsStore.setStoreSorter(storeSorter);
fundedProjectsGrid =
new FlexibleGrid<ProjectFundingDTO>(fundedProjectsStore, null, 2,
new LinkedProjectsColumnsProvider(this, LinkedProjectType.FUNDED_PROJECT).getLinkedProjectsColumnModel());
fundedProjectsGrid.setAutoExpandColumn(ProjectDTO.NAME);
fundedProjectsToolbar = new ToolBar();
fundedProjectsPanel.setTopComponent(fundedProjectsToolbar);
fundedProjectsPanel.add(fundedProjectsGrid);
// --
// Building panel.
// --
updateLinkedProjectsToolbars(false, false);
panel.add(fundingProjectsPanel, Layouts.hBoxData(Margin.HALF_RIGHT));
panel.add(fundedProjectsPanel, Layouts.hBoxData(Margin.HALF_LEFT));
return panel;
}
/**
* Creates the project dashboard panel itself.
*
* @return The component.
*/
private Component createProjectDashboardPanel() {
phasesPresenter = phasesPresenterProvider.get();
phasesPresenter.initialize();
return (Component) phasesPresenter.getView().asWidget();
}
/**
* Builds a new filter {@link MenuItem}.
*
* @param label
* The menu label.
* @param icon
* The menu icon, may be {@code null}.
* @param filterListener
* The filter listener triggered when menu item is selected.
* @param storeFilter
* The store filter instance, may be {@code null}.
* @return The menu item component.
*/
private static <E extends AbstractModelDataEntityDTO<?>> MenuItem buildFilterMenu(final String label, final AbstractImagePrototype icon,
final FilterSelectionListener<E> filterListener, final StoreFilter<E> storeFilter) {
final MenuItem filterMenu = new MenuItem(label, icon);
filterMenu.addSelectionListener(new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(final MenuEvent ce) {
if (filterListener != null) {
filterListener.filter(filterMenu, storeFilter);
}
}
});
return filterMenu;
}
}