package org.sigmah.client.ui.presenter;
/*
* #%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.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.sigmah.client.dispatch.CommandResultHandler;
import org.sigmah.client.dispatch.monitor.LoadingMask;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.inject.Injector;
import org.sigmah.client.page.Page;
import org.sigmah.client.page.PageRequest;
import org.sigmah.client.page.RequestParameter;
import org.sigmah.client.ui.presenter.base.AbstractPagePresenter;
import org.sigmah.client.ui.presenter.contact.dashboardlist.ContactsListWidget;
import org.sigmah.client.ui.presenter.project.treegrid.ProjectsListWidget;
import org.sigmah.client.ui.presenter.project.treegrid.ProjectsListWidget.LoadingMode;
import org.sigmah.client.ui.presenter.project.treegrid.ProjectsListWidget.RefreshMode;
import org.sigmah.client.ui.res.icon.IconImageBundle;
import org.sigmah.client.ui.view.DashboardView;
import org.sigmah.client.ui.view.base.ViewInterface;
import org.sigmah.client.ui.widget.HasTreeGrid.TreeGridEventHandler;
import org.sigmah.client.ui.widget.WorkInProgressWidget;
import org.sigmah.client.ui.widget.orgunit.OrgUnitTreeGrid;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.shared.command.GetMonitoredPoints;
import org.sigmah.shared.command.GetOrgUnits;
import org.sigmah.shared.command.GetReminders;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.dto.orgunit.OrgUnitDTO;
import org.sigmah.shared.dto.referential.GlobalPermissionEnum;
import org.sigmah.shared.dto.reminder.MonitoredPointDTO;
import org.sigmah.shared.dto.reminder.ReminderDTO;
import org.sigmah.shared.util.ProfileUtils;
import com.allen_sauer.gwt.log.client.Log;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Component;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.sigmah.client.event.OfflineEvent;
import org.sigmah.client.event.handler.OfflineHandler;
import org.sigmah.client.ui.notif.ConfirmCallback;
import org.sigmah.client.ui.notif.N10N;
import org.sigmah.client.ui.zone.Zone;
import org.sigmah.client.util.profiler.Checkpoint;
import org.sigmah.client.util.profiler.Execution;
import org.sigmah.client.util.profiler.ExecutionAsyncDAO;
import org.sigmah.client.util.profiler.Profiler;
import org.sigmah.client.util.profiler.Scenario;
import org.sigmah.offline.status.ApplicationState;
import org.sigmah.offline.sync.UpdateDates;
import org.sigmah.shared.command.SendProbeReport;
import org.sigmah.shared.command.result.Result;
import org.sigmah.shared.dto.profile.CheckPointDTO;
import org.sigmah.shared.dto.profile.ExecutionDTO;
/**
* Dashboard page presenter.
*
* @author Tom Miette (tmiette@ideia.fr)
* @author Denis Colliot (dcolliot@ideia.fr)
*/
@Singleton
public class DashboardPresenter extends AbstractPagePresenter<DashboardPresenter.View> {
public static interface ReminderOrMonitoredPointHandler{
public void onLabelClickEvent(Integer projectId);
}
/**
* View interface.
*/
@ImplementedBy(DashboardView.class)
public static interface View extends ViewInterface {
void setReminderOrMonitoredPointHandler(ReminderOrMonitoredPointHandler handler);
/**
* Returns the reminders wrapper component.
*
* @return The reminders wrapper component.
*/
Component getRemindersPanel();
/**
* Returns the reminders list store.
*
* @return The reminders list store.
*/
ListStore<ReminderDTO> getRemindersStore();
/**
* Returns the monitored points wrapper component.
*
* @return The monitored points wrapper component.
*/
Component getMonitoredPointsPanel();
/**
* Returns the monitored points list store.
*
* @return The monitored points list store.
*/
ListStore<MonitoredPointDTO> getMonitoredPointsStore();
/**
* Clears the menu buttons component and removes all the buttons.
*/
void clearMenuButtons();
/**
* Adds a navigation button to the menu buttons panel.
*
* @param buttonText
* (required) The button label.
* @param buttonIcon
* (optional) Button icon displayed next to the label.
* @param clickHandler
* The button click handler implementation.
*/
void addMenuButton(final String buttonText, final AbstractImagePrototype buttonIcon, final Listener<ButtonEvent> clickHandler);
/**
* Ask the button panel to relayout itself.
*/
void layoutButtons();
/**
* Ask the main container to relayout itself.
*/
void layoutViews();
/**
* Returns the OrgUnit tree grid component.
*
* @return The OrgUnit tree grid component.
*/
OrgUnitTreeGrid getOrgUnitsTreeGrid();
/**
* Sets the org units panel header title.
*
* @param title
* The new title.
*/
void setPanelsTitleSuffix(String title);
/**
* Returns the {@link ContactsListWidget} widget.
*
* @return The contacts list widget.
*/
ContactsListWidget getContactsList();
/**
* Returns the {@link ProjectsListWidget} widget.
*
* @return The projects list widget.
*/
ProjectsListWidget getProjectsList();
}
private Integer lastUserId;
private final ExecutionAsyncDAO executionAsyncDAO = new ExecutionAsyncDAO();
/**
* Presenters's initialization.
*
* @param view
* Presenter's view interface.
* @param injector
* Injected client injector.
*/
@Inject
public DashboardPresenter(final View view, final Injector injector) {
super(view, injector);
}
/**
* {@inheritDoc}
*/
@Override
public Page getPage() {
return Page.DASHBOARD;
}
/**
* {@inheritDoc}
*/
@Override
public void onBind() {
// Org units tree grid events handler.
view.getOrgUnitsTreeGrid().setTreeGridEventHandler(new TreeGridEventHandler<OrgUnitDTO>() {
@Override
public void onRowClickEvent(final OrgUnitDTO rowElement) {
eventBus.navigateRequest(Page.ORGUNIT_DASHBOARD.requestWith(RequestParameter.ID, rowElement.getId()));
}
});
if (auth().getSecondaryOrgUnitIds().isEmpty()) {
view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().setVisible(false);
} else {
view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().setValue(true);
view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().addListener(Events.Change, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent event) {
loadReminders();
loadMonitoredPoints();
loadContacts();
loadProjects(true);
loadOrgUnits();
}
});
}
// Projects widget initialization.
view.getProjectsList().init(RefreshMode.ON_FIRST_TIME, LoadingMode.CHUNK);
view.setReminderOrMonitoredPointHandler(new ReminderOrMonitoredPointHandler() {
@Override
public void onLabelClickEvent(Integer projectId) {
Profiler.INSTANCE.startScenario(Scenario.OPEN_PROJECT);
eventBus.navigateRequest(Page.PROJECT_DASHBOARD.requestWith(RequestParameter.ID, projectId));
}
});
// Listening to connection state changes to refresh the available buttons.
// Fixes mantis #682 and #683
eventBus.addHandler(OfflineEvent.getType(), new OfflineHandler() {
@Override
public void handleEvent(OfflineEvent event) {
initializeMenuButtons(event.getState());
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void onPageRequest(final PageRequest request) {
// Reloads the reminders store.
loadReminders();
// Reloads the monitored points store.
loadMonitoredPoints();
// Initializes menu buttons.
initializeMenuButtons();
// Reloads OrgUnits.
loadOrgUnits();
// Reloads contacts.
loadContacts();
// Reloads projects.
loadProjects(false);
// Ask the user to synchronize its favorite projects.
// BUGFIX #701: only showing this message if the user is online.
final boolean userIsOnline = injector.getApplicationStateManager().getState() == ApplicationState.ONLINE;
final boolean userIsDifferent = auth().getUserId() != null && !auth().getUserId().equals(lastUserId);
final boolean userHasSynchronized = UpdateDates.getDatabaseUpdateDate(auth()) != null;
if(userIsOnline && userIsDifferent && !userHasSynchronized) {
N10N.confirmation(I18N.CONSTANTS.offlineModeHeader(), I18N.CONSTANTS.sigmahOfflineWelcome(), new ConfirmCallback() {
@Override
public void onAction() {
eventBus.updateZoneRequest(Zone.OFFLINE_BANNER.requestWith(RequestParameter.PULL_DATABASE, true));
}
});
}
lastUserId = auth().getUserId();
}
@Override
protected void onViewRevealed() {
// BUGFIX #786: Relayout the views on reveal to avoid having the last project hidden.
view.layoutViews();
}
// -------------------------------------------------------------------------------------------
//
// UTILITY METHODS.
//
// -------------------------------------------------------------------------------------------
/**
* Performs a dispatch command to load the reminders list and populates the view store.
*/
private void loadReminders() {
Set<Integer> orgUnitIds = getOrgUnitIds();
dispatch.execute(new GetReminders(ReminderDTO.Mode.BASE, orgUnitIds), new CommandResultHandler<ListResult<ReminderDTO>>() {
@Override
public void onCommandSuccess(final ListResult<ReminderDTO> result) {
final List<ReminderDTO> reminderListToLoad = new ArrayList<ReminderDTO>();
// Only show the undeleted reminders.
for (final ReminderDTO reminder : result.getList()) {
// TODO [PERF] Filter should be performed on server-side.
final Boolean deleted = reminder.getDeleted();
if (Log.isDebugEnabled()) {
Log.debug("Deleted reminder? " + deleted);
}
if (ClientUtils.isNotTrue(deleted)) {
reminderListToLoad.add(reminder);
}
}
view.getRemindersStore().removeAll();
view.getRemindersStore().add(reminderListToLoad);
}
}, new LoadingMask(view.getRemindersPanel()));
}
/**
* Performs a dispatch command to load the monitored points list and populates the view store.
*/
private void loadMonitoredPoints() {
Set<Integer> orgUnitIds = getOrgUnitIds();
dispatch.execute(new GetMonitoredPoints(MonitoredPointDTO.Mode.BASE, orgUnitIds), new CommandResultHandler<ListResult<MonitoredPointDTO>>() {
@Override
public void onCommandSuccess(final ListResult<MonitoredPointDTO> result) {
final List<MonitoredPointDTO> pointListToLoad = new ArrayList<MonitoredPointDTO>();
// Only show the undeleted monitored points.
for (final MonitoredPointDTO p : result.getList()) {
// TODO [PERF] Filter should be performed on server-side.
final Boolean deleted = p.getDeleted();
if (Log.isDebugEnabled()) {
Log.debug("Deleted monitored point? " + deleted);
}
if (ClientUtils.isNotTrue(deleted)) {
pointListToLoad.add(p);
}
}
view.getMonitoredPointsStore().removeAll();
view.getMonitoredPointsStore().add(pointListToLoad);
}
}, new LoadingMask(view.getMonitoredPointsPanel()));
}
/**
* Initializes menu buttons based on authenticated user profile permissions.
*/
private void initializeMenuButtons() {
initializeMenuButtons(injector.getApplicationStateManager().getState());
}
private void initializeMenuButtons(ApplicationState applicationState) {
view.clearMenuButtons();
final boolean online = applicationState == ApplicationState.UNKNOWN || applicationState == ApplicationState.ONLINE;
// Create project.
if (online && ProfileUtils.isGranted(auth(), GlobalPermissionEnum.CREATE_PROJECT)) {
final PageRequest request = new PageRequest(Page.CREATE_PROJECT);
request.addParameter(RequestParameter.TYPE, CreateProjectPresenter.Mode.PROJECT);
view.addMenuButton(I18N.CONSTANTS.createProjectNewProject(), IconImageBundle.ICONS.add(), new ButtonClickHandler(request));
}
// Draft project.
if (online && ProfileUtils.isGranted(auth(), GlobalPermissionEnum.CREATE_TEST_PROJECT)) {
final PageRequest request = new PageRequest(Page.CREATE_PROJECT);
request.addParameter(RequestParameter.TYPE, CreateProjectPresenter.Mode.TEST_PROJECT);
view.addMenuButton(I18N.CONSTANTS.createTestProject(), IconImageBundle.ICONS.add(), new ButtonClickHandler(request));
}
// Users administration.
if (online && ProfileUtils.isGranted(auth(), GlobalPermissionEnum.VIEW_ADMIN)) {
view.addMenuButton(I18N.CONSTANTS.adminboard(), IconImageBundle.ICONS.setup(), new ButtonClickHandler(getDefaultAdminPage()));
}
// Import.
if (online && ProfileUtils.isGranted(auth(), GlobalPermissionEnum.IMPORT_BUTTON)) {
view.addMenuButton(I18N.CONSTANTS.importItem(), null, new ButtonClickHandler(Page.IMPORT_VALUES));
}
// TODO Handle other menus buttons.
// There are two ways to show these menus (authentication / profile).
// if (auth().isShowMenus()) {
// view.addMenuButton(I18N.CONSTANTS.dataEntry(), IconImageBundle.ICONS.dataEntry(), new SiteGridPageState());
// view.addMenuButton(I18N.CONSTANTS.reports(), IconImageBundle.ICONS.report(), new ReportListPageState());
// view.addMenuButton(I18N.CONSTANTS.charts(), IconImageBundle.ICONS.barChart(), new ChartPageState());
// view.addMenuButton(I18N.CONSTANTS.maps(), IconImageBundle.ICONS.map(), new MapPageState());
// view.addMenuButton(I18N.CONSTANTS.tables(), IconImageBundle.ICONS.table(), new PivotPageState());
// view.addMenuButton(I18N.CONSTANTS.setup(), IconImageBundle.ICONS.setup(), new DbListPageState());
// }
view.layoutButtons();
}
/**
* Find the page of the administration to show by default for the current user.
*
* @return First page of the administration to show.
*/
private Page getDefaultAdminPage() {
final Page[] administrationPages = new Page[] {
Page.ADMIN_USERS, Page.ADMIN_ORG_UNITS,
Page.ADMIN_PROJECTS_MODELS, Page.ADMIN_ORG_UNITS_MODELS,
Page.ADMIN_CONTACT_MODELS, Page.ADMIN_REPORTS_MODELS,
Page.ADMIN_CATEGORIES, Page.ADMIN_IMPORTATION_SCHEME,
Page.ADMIN_PARAMETERS
};
final GlobalPermissionEnum[] accessRights = new GlobalPermissionEnum[] {
GlobalPermissionEnum.MANAGE_USERS, GlobalPermissionEnum.MANAGE_ORG_UNITS,
GlobalPermissionEnum.MANAGE_PROJECT_MODELS, GlobalPermissionEnum.MANAGE_ORG_UNIT_MODELS,
GlobalPermissionEnum.MANAGE_CONTACT_MODELS, GlobalPermissionEnum.MANAGE_REPORT_MODELS,
GlobalPermissionEnum.MANAGE_CATEGORIES, GlobalPermissionEnum.MANAGE_IMPORTATION_SCHEMES,
GlobalPermissionEnum.MANAGE_SETTINGS
};
for(int index = 0; index < accessRights.length; index++) {
if (accessRights[index] == null || ProfileUtils.isGranted(auth(), accessRights[index])) {
return administrationPages[index];
}
}
return Page.ADMIN_USERS;
}
/**
* {@link Listener} implementation navigating to a given {@link PageRequest}.
*
* @author Denis Colliot (dcolliot@ideia.fr)
*/
private class ButtonClickHandler implements Listener<ButtonEvent> {
private final PageRequest request;
private ButtonClickHandler(final Page page) {
this.request = page != null ? page.request() : null;
}
private ButtonClickHandler(final PageRequest request) {
this.request = request;
}
/**
* {@inheritDoc}
*/
@Override
public void handleEvent(final ButtonEvent be) {
if (request != null) {
eventBus.navigateRequest(request);
} else {
WorkInProgressWidget.popup(true);
}
}
}
private void loadContacts() {
if (view.getContactsList() != null) {
view.getContactsList().refresh(view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().getValue());
}
}
private void loadProjects(boolean forceRefresh) {
if (view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().getValue()) {
view.getProjectsList().refresh(true, forceRefresh, auth().getMainOrgUnitId());
} else {
view.getProjectsList().refresh(true, forceRefresh, auth().getOrgUnitIds().toArray(new Integer[auth().getOrgUnitIds().size()]));
}
}
/**
* Retrieves OrgUnits and populates tree grid store.
*/
private void loadOrgUnits() {
Set<Integer> orgUnitIds = getOrgUnitIds();
dispatch.execute(new GetOrgUnits(orgUnitIds, OrgUnitDTO.Mode.WITH_TREE), new CommandResultHandler<ListResult<OrgUnitDTO>>() {
@Override
public void onCommandSuccess(final ListResult<OrgUnitDTO> result) {
view.getOrgUnitsTreeGrid().getStore().removeAll();
view.getOrgUnitsTreeGrid().getStore().add(result.getData(), true);
for (OrgUnitDTO orgUnitDTO : view.getOrgUnitsTreeGrid().getStore().getRootItems()) {
view.getOrgUnitsTreeGrid().getTreeGrid().setExpanded(orgUnitDTO, true, false);
}
OrgUnitDTO mainOrgUnitDTO = view.getOrgUnitsTreeGrid().getStore().findModel(OrgUnitDTO.ID, auth().getMainOrgUnitId());
String panelTitle = " - ";
if (auth().getSecondaryOrgUnitIds().isEmpty()) {
panelTitle += mainOrgUnitDTO.getName() + " (" + mainOrgUnitDTO.getFullName() + ")";
} else if (view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().getValue()) {
panelTitle += I18N.CONSTANTS.myMainOrganisationalUnitPanelTitle() + " " + mainOrgUnitDTO.getName() + " (" + mainOrgUnitDTO.getFullName() + ")";
} else {
panelTitle += I18N.CONSTANTS.allMyOrganisationalUnitsPanelTitle();
}
view.setPanelsTitleSuffix(panelTitle);
}
});
}
Set<Integer> getOrgUnitIds() {
Set<Integer> orgUnitIds = new HashSet<Integer>();
if (view.getOrgUnitsTreeGrid().getDisplayOnlyMainOrgUnitCheckbox().getValue()) {
orgUnitIds.add(auth().getMainOrgUnitId());
} else {
orgUnitIds.addAll(auth().getOrgUnitIds());
}
return orgUnitIds;
}
}