package org.sigmah.client.ui.presenter.project.indicator; /* * #%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 com.extjs.gxt.ui.client.event.ButtonEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.GridEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.MenuEvent; import com.extjs.gxt.ui.client.event.SelectionListener; import com.extjs.gxt.ui.client.store.Record; import com.extjs.gxt.ui.client.store.TreeStore; import com.extjs.gxt.ui.client.widget.form.Field; import com.extjs.gxt.ui.client.widget.menu.MenuItem; import com.google.gwt.dom.client.Element; import org.sigmah.client.inject.Injector; import org.sigmah.client.page.Page; import org.sigmah.client.page.PageRequest; import org.sigmah.client.ui.view.project.indicator.ProjectIndicatorManagementView; import com.google.inject.ImplementedBy; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.HashMap; import java.util.List; import org.sigmah.client.dispatch.CommandResultHandler; import org.sigmah.client.dispatch.monitor.LoadingMask; import org.sigmah.client.event.UpdateEvent; import org.sigmah.client.event.handler.UpdateHandler; import org.sigmah.client.i18n.I18N; import org.sigmah.client.page.RequestParameter; import org.sigmah.client.ui.notif.ConfirmCallback; import org.sigmah.client.ui.notif.N10N; import org.sigmah.client.ui.presenter.project.AbstractProjectPresenter; import org.sigmah.client.ui.view.base.ViewPopupInterface; import org.sigmah.client.ui.view.project.indicator.IndicatorResources; import org.sigmah.client.ui.widget.HasTreeGrid; import org.sigmah.client.ui.widget.button.Button; import org.sigmah.client.ui.widget.button.SplitButton; import org.sigmah.client.ui.widget.form.FormPanel; import org.sigmah.client.util.ClientUtils; import org.sigmah.shared.command.BatchCommand; import org.sigmah.shared.command.CreateEntity; import org.sigmah.shared.command.Delete; import org.sigmah.shared.command.GetIndicators; import org.sigmah.shared.command.UpdateEntity; import org.sigmah.shared.command.result.CreateResult; import org.sigmah.shared.command.result.IndicatorListResult; import org.sigmah.shared.command.result.ListResult; import org.sigmah.shared.command.result.Result; import org.sigmah.shared.command.result.VoidResult; import org.sigmah.shared.dto.IndicatorDTO; import org.sigmah.shared.dto.IndicatorElement; import org.sigmah.shared.dto.IndicatorGroup; import org.sigmah.shared.dto.base.EntityDTO; import org.sigmah.shared.dto.referential.GlobalPermissionEnum; import org.sigmah.shared.servlet.ServletConstants; import org.sigmah.shared.servlet.ServletUrlBuilder; import org.sigmah.shared.util.ProfileUtils; /** * Project's indicators management presenter which manages the {@link ProjectIndicatorManagementView}. * * @author Denis Colliot (dcolliot@ideia.fr) * @author Raphaƫl Calabro (rcalabro@ideia.fr) */ @Singleton public class ProjectIndicatorManagementPresenter extends AbstractProjectPresenter<ProjectIndicatorManagementPresenter.View> { /** * Description of the view managed by this presenter. */ @ImplementedBy(ProjectIndicatorManagementView.class) public static interface View extends AbstractProjectPresenter.View, HasTreeGrid<IndicatorElement> { SplitButton getSaveButton(); MenuItem getSaveItem(); MenuItem getDiscardChangesItem(); Button getNewIndicatorGroupButton(); Button getNewIndicatorButton(); Button getDeleteButton(); Button getRefreshButton(); Button getExportButton(); ViewPopupInterface getIndicatorGroupPopup(); FormPanel getIndicatorGroupForm(); Field<String> getIndicatorGroupNameField(); Button getIndicatorGroupSaveButton(); void refreshTreeGrid(); void setEditable(boolean editable); } private Integer currentDatabaseId; /** * Presenters's initialization. * * @param view * Presenter's view interface. * @param injector * Injected client injector. */ @Inject public ProjectIndicatorManagementPresenter(final View view, final Injector injector) { super(view, injector); } /** * {@inheritDoc} */ @Override public Page getPage() { return Page.PROJECT_INDICATORS_MANAGEMENT; } /** * {@inheritDoc} */ @Override public void onBind() { view.getIndicatorGroupPopup().initialize(); view.getTreeGrid().addListener(Events.CellClick, new Listener<GridEvent<IndicatorElement>>() { @Override public void handleEvent(GridEvent<IndicatorElement> gridEvent) { if(ProfileUtils.isGranted(auth(), GlobalPermissionEnum.MANAGE_INDICATOR) && computeTarget(gridEvent) == Target.LABEL) { onEditIndicator((IndicatorDTO)gridEvent.getModel()); } } }); view.getSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { onSave(); } }); view.getSaveItem().addSelectionListener(new SelectionListener<MenuEvent>() { @Override public void componentSelected(MenuEvent ce) { onSave(); } }); view.getDiscardChangesItem().addSelectionListener(new SelectionListener<MenuEvent>() { @Override public void componentSelected(MenuEvent ce) { onDiscardChanges(); } }); view.getNewIndicatorGroupButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { view.getIndicatorGroupForm().reset(); view.getIndicatorGroupPopup().center(); } }); view.getIndicatorGroupSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { onNewIndicatorGroup(); } }); view.getNewIndicatorButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { onNewIndicator(); } }); view.getDeleteButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { onDelete(); } }); view.getRefreshButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doLoad(); } }); view.getExportButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { // BUGFIX #674: Calling the "export" method when the user clicks on the export button. onExport(); } }); eventBus.addHandler(UpdateEvent.getType(), new UpdateHandler() { @Override public void onUpdate(UpdateEvent event) { if(event.concern(UpdateEvent.INDICATOR_UPDATED)) { doLoad(); } } }); } /** * {@inheritDoc} */ @Override public void onPageRequest(final PageRequest request) { currentDatabaseId = Integer.valueOf(request.getParameter(RequestParameter.ID)); final boolean canManageIndicators = ProfileUtils.isGranted(auth(), GlobalPermissionEnum.MANAGE_INDICATOR); view.getSaveButton().setVisible(canManageIndicators); view.getNewIndicatorGroupButton().setVisible(canManageIndicators); view.getNewIndicatorButton().setVisible(canManageIndicators); view.getDeleteButton().setVisible(canManageIndicators); view.setEditable(canManageIndicators); doLoad(); } @Override protected boolean hasValueChanged() { return !view.getStore().getModifiedRecords().isEmpty(); } private void doLoad() { dispatch.execute(new GetIndicators(currentDatabaseId), new CommandResultHandler<IndicatorListResult>() { @Override protected void onCommandSuccess(IndicatorListResult result) { final TreeStore<IndicatorElement> treeStore = view.getStore(); treeStore.removeAll(); for (IndicatorGroup group : result.getGroups()) { treeStore.add(group, false); for (IndicatorDTO indicator : group.getIndicators()) { treeStore.add(group, indicator, false); } } if (!result.getUngroupedIndicators().isEmpty()) { treeStore.add((List) result.getUngroupedIndicators(), false); } view.refreshTreeGrid(); } }, new LoadingMask(view.getTreeGrid())); } // -- // Actions // -- private void onSave() { final BatchCommand updateCommands = new BatchCommand(); for(final Record record : view.getStore().getModifiedRecords()) { if(record.getModel() instanceof EntityDTO) { final EntityDTO entity = (EntityDTO) record.getModel(); final HashMap<String, Object> changes = new HashMap<String, Object>(); for(final String property : record.getChanges().keySet()) { // Retrieves the new value of the property. // (record.getChanges() only retrieves the original value). changes.put(property, record.get(property)); } updateCommands.add(new UpdateEntity(entity, changes)); } } dispatch.execute(updateCommands, new CommandResultHandler<ListResult<Result>>() { @Override protected void onCommandSuccess(ListResult<Result> result) { view.getStore().commitChanges(); } }, view.getSaveButton()); } private void onDiscardChanges() { view.getStore().rejectChanges(); } private void onNewIndicatorGroup() { final HashMap<String, Object> properties = new HashMap<String, Object>(); properties.put(IndicatorGroup.DATABASE_ID, currentDatabaseId); properties.put(IndicatorGroup.NAME, view.getIndicatorGroupNameField().getValue()); dispatch.execute(new CreateEntity(IndicatorGroup.ENTITY_NAME, properties), new CommandResultHandler<CreateResult>() { @Override protected void onCommandSuccess(CreateResult result) { view.getIndicatorGroupPopup().hide(); doLoad(); } }, view.getNewIndicatorGroupButton(), view.getIndicatorGroupSaveButton()); } private void onNewIndicator() { eventBus.navigateRequest(Page.INDICATOR_EDIT .requestWith(RequestParameter.ID, currentDatabaseId)); } private void onEditIndicator(IndicatorDTO indicatorDTO) { eventBus.navigateRequest(Page.INDICATOR_EDIT.request() .addParameter(RequestParameter.ID, currentDatabaseId) .addData(RequestParameter.MODEL, indicatorDTO)); } private void onDelete() { final IndicatorElement selected = getSelectedItem(); if (selected instanceof IndicatorDTO) { N10N.confirmation(I18N.CONSTANTS.delete(), I18N.CONSTANTS.confirmDeleteIndicator(), new ConfirmCallback() { @Override public void onAction() { deleteIndicator((IndicatorDTO) selected); } }); } else if (selected instanceof IndicatorGroup) { deleteIndicatorGroup((IndicatorGroup) selected); } } private void onExport() { final ServletUrlBuilder urlBuilder = new ServletUrlBuilder(injector.getAuthenticationProvider(), injector.getPageManager(), ServletConstants.Servlet.EXPORT, ServletConstants.ServletMethod.EXPORT_PROJECT_INDICATORS); urlBuilder.addParameter(RequestParameter.ID, getProject().getId()); ClientUtils.launchDownload(urlBuilder.toString()); } private void deleteIndicatorGroup(IndicatorGroup selected) { final TreeStore<IndicatorElement> treeStore = view.getStore(); List<IndicatorElement> children = treeStore.getChildren(selected); treeStore.remove(selected); treeStore.getRecord(selected).set("isDeleted", true); // we don't delete the indicators, just move them out of the group for (IndicatorElement child : children) { treeStore.add(child, false); treeStore.getRecord(child).set("groupId", null); } } private void deleteIndicator(final IndicatorDTO selected) { dispatch.execute(new Delete(selected), new CommandResultHandler<VoidResult>() { @Override protected void onCommandSuccess(VoidResult result) { view.getStore().remove(selected); eventBus.fireEvent(new UpdateEvent(UpdateEvent.INDICATOR_REMOVED, selected.getId())); } }, new LoadingMask(view.getTreeGrid(), I18N.CONSTANTS.deleting())); } // -- // Utility methods //-- /** * Retrieve the selected item. * * @return The selected item. */ private IndicatorElement getSelectedItem() { return view.getTreeGrid().getSelectionModel().getSelectedItem(); } /** * Possible click targets for the "name" column. */ public enum Target { MAP_ICON, STAR_ICON, LABEL, NONE } /** * Find the target of a click on the "name" column. * * @param gridEvent click event on the tree grid. * @return The target of the given event. */ private Target computeTarget(GridEvent gridEvent) { final IndicatorResources.Style css = IndicatorResources.INSTANCE.css(); final Element targetElement = gridEvent.getEvent().getEventTarget().cast(); final String targetClass = targetElement.getClassName(); if (css.indicatorLabel().equals(targetClass)) { return Target.LABEL; } else if (css.mapIcon().equals(targetClass) || css.emptyMapIcon().equals(targetClass)) { return Target.MAP_ICON; } else if (css.emptyStarIcon().equals(targetClass) || css.starIcon().equals(targetClass)) { return Target.STAR_ICON; } else { return Target.NONE; } } }