package org.sigmah.client.ui.presenter.admin;
/*
* #%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.HashMap;
import java.util.List;
import java.util.Map;
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.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.notif.N10N;
import org.sigmah.client.ui.view.admin.CategoriesAdminView;
import org.sigmah.client.ui.widget.ColorField;
import org.sigmah.client.util.AdminUtil;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.client.util.DeletionError;
import org.sigmah.shared.command.CreateEntity;
import org.sigmah.shared.command.DeleteCategories;
import org.sigmah.shared.command.GetCategories;
import org.sigmah.shared.command.GetProjectModels;
import org.sigmah.shared.command.result.CreateResult;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.command.result.VoidResult;
import org.sigmah.shared.dto.ProjectModelDTO;
import org.sigmah.shared.dto.category.CategoryElementDTO;
import org.sigmah.shared.dto.category.CategoryTypeDTO;
import org.sigmah.shared.dto.element.FlexibleElementDTO;
import org.sigmah.shared.dto.element.QuestionElementDTO;
import org.sigmah.shared.dto.referential.CategoryIcon;
import org.sigmah.shared.dto.referential.ElementTypeEnum;
import org.sigmah.shared.dto.referential.ProjectModelStatus;
import org.sigmah.shared.servlet.ServletConstants.Servlet;
import org.sigmah.shared.servlet.ServletConstants.ServletMethod;
import org.sigmah.shared.servlet.ServletUrlBuilder;
import com.extjs.gxt.ui.client.Style.Scroll;
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.Dialog;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.google.gwt.dom.client.Element;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Admin categories Presenter which manages {@link CategoriesAdminView}.
*
* @author Denis Colliot (dcolliot@ideia.fr) (v2.0)
*/
@Singleton
public class CategoriesAdminPresenter extends AbstractAdminPresenter<CategoriesAdminPresenter.View> {
/**
* Description of the view managed by this presenter.
*/
@ImplementedBy(CategoriesAdminView.class)
public static interface View extends AbstractAdminPresenter.View {
ListStore<CategoryTypeDTO> getCategoriesStore();
ListStore<CategoryElementDTO> getCategoryElementsStore();
Grid<CategoryElementDTO> getCategoryElementsGrid();
Grid<CategoryTypeDTO> getCategoriesGrid();
SimpleComboBox<String> getCategoryIcon();
TextField<String> getCategoryName();
Button getAddCategoryElementButton();
Button getDeleteCategoryElementButton();
Button getDeleteCategoryTypeButton();
LoadingMask getGategoriesTypeLoadingMonitor();
LoadingMask getGategoriesElementsLoadingMonitor();
Button getAddCategoryTypeButton();
void setCategoryPresenterHandler(CategoryPresenterHandler handler);
TextField<String> getName();
ColorField getColorField();
Button getImportCategoryTypeButton();
}
public static interface CategoryPresenterHandler {
void onClickHandler(CategoryTypeDTO categoryTypeDTO);
void onSelectHandler(CategoryTypeDTO categoryTypeDTO);
}
private CategoryTypeDTO currentCategoryType;
/**
* Presenters's initialization.
*
* @param view
* Presenter's view interface.
* @param injector
* Injected client injector.
*/
@Inject
protected CategoriesAdminPresenter(View view, Injector injector) {
super(view, injector);
}
/**
* {@inheritDoc}
*/
@Override
public Page getPage() {
return Page.ADMIN_CATEGORIES;
}
/**
* {@inheritDoc}
*/
@Override
public void onBind() {
/**
* *************** Category Panel *************************
*/
// ADD CATEGORY
createCategoryButtonListener();
// Delete Category
deleteCategoryButtonListener();
// Import Category
importCategoryButtonListener();
/**
* ****************** Category Element Panel *****************
*/
// ADD ELEMENT CATEGORY
createCategoryElementListener();
// DELETE ELEMENT CATEGORY
deleteCategoryElementListener();
/**
* ************* Presenter Handler *******************
*/
view.setCategoryPresenterHandler(new CategoryPresenterHandler() {
/**
* show Category Elements
*/
@Override
public void onSelectHandler(CategoryTypeDTO categoryTypeDTO) {
currentCategoryType = categoryTypeDTO;
view.getCategoryElementsGrid().show();
view.getCategoryElementsStore().removeAll();
for (CategoryElementDTO categoryElementDTO : categoryTypeDTO.getCategoryElementsDTO()) {
view.getCategoryElementsStore().add(categoryElementDTO);
}
view.getCategoryElementsStore().commitChanges();
view.getAddCategoryElementButton().enable();
}
/**
* Export Category
*/
@Override
public void onClickHandler(CategoryTypeDTO categoryTypeDTO) {
final ServletUrlBuilder urlBuilder =
new ServletUrlBuilder(injector.getAuthenticationProvider(), injector.getPageManager(), Servlet.EXPORT, ServletMethod.EXPORT_MODEL_CATEGORY);
urlBuilder.addParameter(RequestParameter.ID, categoryTypeDTO.getId());
ClientUtils.launchDownload(urlBuilder.toString());
}
});
// Handler
registerHandler(eventBus.addHandler(UpdateEvent.getType(), new UpdateHandler() {
@Override
public void onUpdate(final UpdateEvent event) {
if (event.concern(UpdateEvent.CATEGORY_MODEL_IMPORT)) {
refreshCategoryTypePanel();
}
}
}));
}
private void importCategoryButtonListener() {
view.getImportCategoryTypeButton().addListener(Events.Select, new Listener<ButtonEvent>() {
@Override
public void handleEvent(ButtonEvent be) {
eventBus.navigateRequest(Page.IMPORT_MODEL.requestWith(RequestParameter.TYPE, AdminUtil.ADMIN_CATEGORY_MODEL));
}
});
}
private void deleteCategoryElementListener() {
view.getDeleteCategoryElementButton().addListener(Events.OnClick, new Listener<ButtonEvent>() {
@Override
public void handleEvent(ButtonEvent be) {
onDeleteCategoryElement(view.getCategoryElementsGrid().getSelectionModel().getSelectedItems());
}
});
}
/**
* Method to delete a element under a category Firstly,get all project models for verifying if the selected category
* elements are being used by one or more project models. If being used, a category element should not be deleted.
*
* @param selectedItems
* The selected categories
*/
private void onDeleteCategoryElement(final List<CategoryElementDTO> selectedItems) {
// Check if there is at least one item selected
if (ClientUtils.isEmpty(selectedItems)) {
N10N.warn(I18N.CONSTANTS.error(), I18N.CONSTANTS.selectCategoryElementToDelete());
return;
}
dispatch.execute(new GetProjectModels(ProjectModelDTO.Mode.ALL, ProjectModelStatus.values()), new CommandResultHandler<ListResult<ProjectModelDTO>>() {
@Override
public void onCommandFailure(final Throwable arg0) {
N10N.error(I18N.CONSTANTS.error(), I18N.CONSTANTS.deleteCategoryGetProjectModelsError());
}
@Override
public void onCommandSuccess(final ListResult<ProjectModelDTO> result) {
deleteCategoryElementVerify(selectedItems, result.getList());
}
}, view.getGategoriesElementsLoadingMonitor());
}
private void createCategoryElementListener() {
view.getAddCategoryElementButton().addListener(Events.OnClick, new Listener<ButtonEvent>() {
@Override
public void handleEvent(ButtonEvent be) {
if (view.getName().getValue() != null
&& !view.getName().getValue().isEmpty()
&& view.getCategoryElementsStore().findModel("label", view.getName().getValue()) == null) {
Map<String, Object> newCategoryElementProperties = new HashMap<String, Object>();
newCategoryElementProperties.put(AdminUtil.PROP_CATEGORY_ELEMENT_NAME, view.getName().getValue());
newCategoryElementProperties.put(AdminUtil.PROP_CATEGORY_ELEMENT_COLOR, view.getColorField().getValue());
newCategoryElementProperties.put(AdminUtil.PROP_CATEGORY_TYPE, currentCategoryType);
dispatch.execute(new CreateEntity("CategoryElement", newCategoryElementProperties), new CommandResultHandler<CreateResult>() {
@Override
public void onCommandFailure(Throwable caught) {
N10N.warn(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardCreationFailureF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + currentCategoryType.getLabel() + "'"));
}
@Override
public void onCommandSuccess(CreateResult result) {
if (result != null && result.getEntity() != null) {
view.getCategoryElementsStore().add((CategoryElementDTO) result.getEntity());
view.getCategoryElementsStore().commitChanges();
List<CategoryElementDTO> elements = null;
if (currentCategoryType.getCategoryElementsDTO() == null) {
elements = new ArrayList<CategoryElementDTO>();
} else {
elements = currentCategoryType.getCategoryElementsDTO();
}
elements.add((CategoryElementDTO) result.getEntity());
currentCategoryType.setCategoryElementsDTO(elements);
view.getCategoriesStore().update(currentCategoryType);
view.getCategoriesStore().commitChanges();
view.getName().clear();
N10N.infoNotif(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardUpdateSuccessF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + currentCategoryType.getLabel() + "'"));
} else {
N10N.warn(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardCreationNullF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + currentCategoryType.getLabel() + "'"));
}
}
});
} else {
N10N.warn("", I18N.CONSTANTS.adminStandardInvalidValues());
}
}
});
}
/**
* add category button listener
*/
private void createCategoryButtonListener() {
view.getAddCategoryTypeButton().addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
if (view.getCategoryName().getValue() != null
&& view.getCategoryIcon().getValue() != null
&& view.getCategoriesStore().findModel("label", view.getCategoryName().getValue()) == null) {
Map<String, Object> newCategoryTypeProperties = new HashMap<String, Object>();
newCategoryTypeProperties.put(AdminUtil.PROP_CATEGORY_TYPE_ICON, CategoryIcon.getIcon(view.getCategoryIcon().getValue().getValue()));
newCategoryTypeProperties.put(AdminUtil.PROP_CATEGORY_TYPE_NAME, view.getCategoryName().getValue());
dispatch.execute(new CreateEntity("CategoryType", newCategoryTypeProperties), new CommandResultHandler<CreateResult>() {
@Override
public void onCommandFailure(Throwable caught) {
N10N.warn(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardCreationFailureF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + view.getCategoryName().getValue() + "'"));
}
@Override
public void onCommandSuccess(CreateResult result) {
if (result != null && result.getEntity() != null) {
view.getCategoriesStore().add((CategoryTypeDTO) result.getEntity());
view.getCategoriesStore().commitChanges();
N10N.infoNotif(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardUpdateSuccessF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + view.getCategoryName().getValue() + "'"));
List<CategoryTypeDTO> selectedCategory = new ArrayList<CategoryTypeDTO>();
selectedCategory.add((CategoryTypeDTO) result.getEntity()); // Focus and scroll to the new created
// category
int rowIndex = view.getCategoriesStore().indexOf((CategoryTypeDTO) result.getEntity());
Element addedRow = view.getCategoriesGrid().getView().getRow(rowIndex);
view.getCategoriesGrid().getSelectionModel().setSelection(selectedCategory);
addedRow.setScrollTop(addedRow.getScrollTop());
addedRow.scrollIntoView();
view.getCategoryName().clear();
view.getCategoryIcon().clearSelections();
} else {
N10N.infoNotif(I18N.CONSTANTS.adminCategoryTypeCreationBox(),
I18N.MESSAGES.adminStandardCreationNullF(I18N.CONSTANTS.adminCategoryTypeStandard() + " '" + view.getCategoryName().getValue() + "'"));
}
}
});
} else {
N10N.warn("", I18N.CONSTANTS.adminStandardInvalidValues());
}
};
});
}
/**
* Delete Category Button Listener
*/
public void deleteCategoryButtonListener() {
view.getDeleteCategoryTypeButton().addListener(Events.OnClick, new Listener<ButtonEvent>() {
@Override
public void handleEvent(ButtonEvent be) {
onDeleteCategory(view.getCategoriesGrid().getSelectionModel().getSelectedItems());
}
});
}
/**
* Method to delete a category. Firstly,get all project models for verifying if there is one or more in the selected
* categories who are being used by one or more project models. If being used, a category should not be deleted.
*
* @param selectedItems
* The selected categories
*/
protected void onDeleteCategory(final List<CategoryTypeDTO> selectedItems) {
// Check if there is at least one item selected
if (selectedItems == null || selectedItems.size() == 0) {
N10N.warn(I18N.CONSTANTS.error(), I18N.CONSTANTS.selectCategoryToDelete());
return;
}
GetProjectModels cmdGetProjectModels = new GetProjectModels(ProjectModelDTO.Mode.ALL, ProjectModelStatus.values());
dispatch.execute(cmdGetProjectModels, new CommandResultHandler<ListResult<ProjectModelDTO>>() {
@Override
public void onCommandFailure(Throwable arg0) {
N10N.warn(I18N.CONSTANTS.error(), I18N.CONSTANTS.deleteCategoryGetProjectModelsError());
}
@Override
public void onCommandSuccess(ListResult<ProjectModelDTO> result) {
deleteCategoryVerify(selectedItems, result.getList());
}
}, view.getGategoriesTypeLoadingMonitor());
}
/**
* Method to verify the deletion action. If the verification passes, try to delete a category, or show a alert window.
*
* @param selectedItems
* The selected categories
* @param allProjectModelsList
* The list of all project models
*/
private void deleteCategoryVerify(final List<CategoryTypeDTO> selectedItems, List<ProjectModelDTO> allProjectModelsList) {
// A List to store DeletionError object
List<DeletionError> deletionErrorList = new ArrayList<DeletionError>();
// Check
for (ProjectModelDTO projectModelDTO : allProjectModelsList) {
List<FlexibleElementDTO> allElements = new ArrayList<FlexibleElementDTO>();
allElements = projectModelDTO.getAllElements();
for (FlexibleElementDTO e : allElements) {
if (e.getElementType() == ElementTypeEnum.QUESTION) {
QuestionElementDTO questionElement = (QuestionElementDTO) e;
if (questionElement.getCategoryType() != null && selectedItems.contains(questionElement.getCategoryType())) {
deletionErrorList.add(new DeletionError(questionElement.getCategoryType().getLabel(), projectModelDTO.getName(), questionElement.getLabel()));
}
}
}
}
// If the category is used by project models,show an alert window
if (deletionErrorList.size() > 0) {
// Create a dialog window to show error message
final Dialog errorDialog = new Dialog();
errorDialog.setHeadingHtml(I18N.CONSTANTS.deletionError());
errorDialog.setButtons(Dialog.CANCEL);
errorDialog.setScrollMode(Scroll.AUTO);
errorDialog.setHideOnButtonClick(true);
errorDialog.setModal(true);
errorDialog.setWidth(500);
errorDialog.setHeight(250);
String errorText = "";
for (DeletionError error : deletionErrorList) {
errorText = errorText + I18N.MESSAGES.categoryBeingUsed(error.getCategoryTypeName(), error.getProjectModelName(), error.getFieldName()) + "<br />";
}
errorDialog.addText(errorText);
errorDialog.show();
}
// Else, try to delete
else {
List<Integer> ids = new ArrayList<Integer>();
String names = "";
for (CategoryTypeDTO s : selectedItems) {
ids.add(s.getId());
names = s.getLabel() + ", " + names;
}
final String toDelete = names;
final DeleteCategories deactivate = new DeleteCategories(selectedItems, null);
dispatch.execute(deactivate, new CommandResultHandler<VoidResult>() {
@Override
public void onCommandFailure(Throwable caught) {
N10N.warn(I18N.CONSTANTS.error(), I18N.MESSAGES.entityDeleteEventError(toDelete));
}
@Override
public void onCommandSuccess(VoidResult result) {
for (CategoryTypeDTO model : selectedItems) {
view.getCategoriesStore().remove(model);
view.getCategoryElementsStore().removeAll();
view.getCategoriesStore().commitChanges();
}
view.getCategoriesStore().commitChanges();
view.getAddCategoryElementButton().disable();
N10N.infoNotif(I18N.CONSTANTS.adminCategoryTypeCreationBox(), I18N.MESSAGES.adminStandardUpdateSuccessF(I18N.CONSTANTS.adminCategoryTypeStandard()));
}
});
}
}
/**
* Method to verify the deletion action. If the verification passes, try to delete a category element, or show a alert
* window.
*
* @param selectedItems
* The selected category elements
* @param allProjectModelsList
* The list of all project models
*/
protected void deleteCategoryElementVerify(final List<CategoryElementDTO> selectedItems, List<ProjectModelDTO> allProjectModelsList) {
// Get the parent CategoryTypeDTO object, they have the same parent CategoryTypeDTO object
CategoryTypeDTO parentCategoryTypeDTO = selectedItems.get(0).getParentCategoryDTO();
// A List to store DeletionError object
List<DeletionError> deletionErrorList = new ArrayList<DeletionError>();
// Check
for (ProjectModelDTO projectModelDTO : allProjectModelsList) {
List<FlexibleElementDTO> allElements = new ArrayList<FlexibleElementDTO>();
allElements = projectModelDTO.getAllElements();
for (FlexibleElementDTO e : allElements) {
if (e.getElementType() == ElementTypeEnum.QUESTION) {
QuestionElementDTO questionElement = (QuestionElementDTO) e;
if (questionElement.getCategoryType() != null && parentCategoryTypeDTO.getId().equals(questionElement.getCategoryType().getId())) {
// Add a deletion error object
deletionErrorList.add(new DeletionError(parentCategoryTypeDTO.getLabel(), projectModelDTO.getName(), questionElement.getLabel()));
}
}
}
}
// If the category is used by project models,show an alert window
if (deletionErrorList.size() > 0) {
// Create a dialog window to show error message
final Dialog errorDialog = new Dialog();
errorDialog.setHeadingHtml(I18N.CONSTANTS.deletionError());
errorDialog.setButtons(Dialog.CANCEL);
errorDialog.setScrollMode(Scroll.AUTO);
errorDialog.setHideOnButtonClick(true);
errorDialog.setModal(true);
errorDialog.setHeight(250);
errorDialog.setWidth(500);
String errorText = "";
for (DeletionError error : deletionErrorList) {
errorText = errorText + I18N.MESSAGES.categoryBeingUsed(error.getCategoryTypeName(), error.getProjectModelName(), error.getFieldName()) + "<br />";
}
errorDialog.addText(errorText);
errorDialog.show();
return;
}
// Else, try to delete
else {
List<Integer> ids = new ArrayList<Integer>();
String names = "";
for (CategoryElementDTO s : selectedItems) {
ids.add(s.getId());
names = s.getLabel() + ", " + names;
}
final String toDelete = names;
final DeleteCategories deactivate = new DeleteCategories(null, selectedItems);
dispatch.execute(deactivate, new CommandResultHandler<VoidResult>() {
@Override
public void onCommandFailure(Throwable caught) {
N10N.warn(I18N.CONSTANTS.error(), I18N.MESSAGES.entityDeleteEventError(toDelete), null);
}
@Override
public void onCommandSuccess(VoidResult result) {
List<CategoryElementDTO> elements = currentCategoryType.getCategoryElementsDTO();
for (CategoryElementDTO model : selectedItems) {
view.getCategoryElementsStore().remove(model);
elements.remove(model);
}
view.getCategoryElementsStore().commitChanges();
currentCategoryType.setCategoryElementsDTO(elements);
view.getCategoriesStore().update(currentCategoryType);
view.getCategoriesStore().commitChanges();
}
});
}
}
/**
* {@inheritDoc}
*/
@Override
public void onPageRequest(final PageRequest request) {
// clear view
view.getCategoryName().clear();
view.getCategoryIcon().clearSelections();
view.getName().clear();
// load category
refreshCategoryTypePanel();
}
/**
* Load category
*/
public void refreshCategoryTypePanel() {
dispatch.execute(new GetCategories(), new CommandResultHandler<ListResult<CategoryTypeDTO>>() {
@Override
public void onCommandFailure(Throwable arg0) {
N10N.warn(I18N.CONSTANTS.adminboard(), I18N.CONSTANTS.adminProblemLoading());
}
@Override
public void onCommandSuccess(ListResult<CategoryTypeDTO> result) {
if (result.getList() != null && !result.getList().isEmpty()) {
view.getCategoriesStore().removeAll();
view.getCategoriesStore().add(result.getList());
view.getCategoriesStore().commitChanges();
}
}
}, view.getGategoriesTypeLoadingMonitor());
}
}