package org.sigmah.client.ui.presenter.project.treegrid;
/*
* #%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.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
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.RequestParameter;
import org.sigmah.client.ui.notif.N10N;
import org.sigmah.client.ui.presenter.base.AbstractPresenter;
import org.sigmah.client.ui.view.base.ViewInterface;
import org.sigmah.client.ui.view.project.treegrid.ProjectsListView;
import org.sigmah.client.ui.widget.HasTreeGrid;
import org.sigmah.client.ui.widget.HasTreeGrid.TreeGridEventHandler;
import org.sigmah.client.ui.widget.button.Button;
import org.sigmah.client.util.ClientConfiguration;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.client.util.MessageType;
import org.sigmah.client.util.NumberUtils;
import org.sigmah.shared.command.GetCategories;
import org.sigmah.shared.command.GetProjects;
import org.sigmah.shared.command.UpdateProjectFavorite;
import org.sigmah.shared.command.result.CreateResult;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.dto.ProjectDTO;
import org.sigmah.shared.dto.UserDTO;
import org.sigmah.shared.dto.category.CategoryElementDTO;
import org.sigmah.shared.dto.category.CategoryTypeDTO;
import org.sigmah.shared.dto.referential.GlobalPermissionEnum;
import org.sigmah.shared.dto.referential.ProjectModelType;
import org.sigmah.shared.util.ProfileUtils;
import com.allen_sauer.gwt.log.client.Log;
import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.data.ModelData;
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.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.StoreEvent;
import com.extjs.gxt.ui.client.store.StoreFilter;
import com.extjs.gxt.ui.client.store.StoreSorter;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.grid.filters.GridFilters;
import com.extjs.gxt.ui.client.widget.grid.filters.ListFilter;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import org.sigmah.client.util.profiler.Profiler;
import org.sigmah.client.util.profiler.Scenario;
/**
* <p>
* Widget displaying a list of projects with a tree structure.
* </p>
* <p>
* This widget respects MVP structure (presenter & view separation):
* <ul>
* <li>This class handles the widget functionalities (data loading, events management, etc.).</li>
* <li>The widget's view is implemented by {@link ProjectsListView}.</li>
* </ul>
* </p>
*
* @author Tom Miette (tmiette@ideia.fr)
* @author Denis Colliot (dcolliot@ideia.fr)
*/
public class ProjectsListWidget extends AbstractPresenter<ProjectsListWidget.View> {
/**
* The widget view interface.
*
* @author Denis Colliot (dcolliot@ideia.fr)
*/
@ImplementedBy(ProjectsListView.class)
public static interface View extends ViewInterface, HasTreeGrid<ProjectDTO> {
/**
* Time column key.
*/
static final String TIME_COLUMN = "time";
/**
* Category filter key.
*/
static final String CATEGORY_FILTER = "categoryFilter";
/**
* Allows the presenter to provide necessary handlers to the view.
*
* @param handlerProvider
* The {@link HandlerProvider} implementation.
*/
void setHandlerProvider(HandlerProvider handlerProvider);
/**
* Updates the widget accessibility state.
*
* @param authorized
* If {@code true}, the widget is accessible and rendered. If {@code false}, the widget is hidden and a
* proper label is rendered.
*/
void updateAccessibilityState(boolean authorized);
ContentPanel getProjectsPanel();
GridFilters getGridFilters();
/**
* Returns the project model type field.
*
* @return The project model type field.
*/
Field<ProjectModelType> getProjectModelTypeField();
/**
* Display the given date as the last refreshed date.
*
* @param date
* The last refreshed date.
*/
void updateRefreshingDate(Date date);
Button getRefreshButton();
Button getFilterButton();
/**
* Updates the view toolbar.
*
* @param refresh
* {@code true} to enable <em>refresh</em> functionality, {@code false} to disable it.
* @param export
* {@code true} to enable <em>export</em> functionality, {@code false} to disable it.
*/
void updateToolbar(boolean refresh, boolean export);
/**
* Returns the export button.
*
* @return The export button.
*/
Button getExportButton();
/**
* Resynchronize the size of the grid.
*/
void syncSize();
}
/**
* Allows the presenter to provide necessary handlers to the view.
*
* @author Denis Colliot (dcolliot@ideia.fr)
*/
public static interface HandlerProvider {
/**
* Returns if the given {@code model} is a favorite project.
*
* @param model
* The corresponding project.
* @return {@code true} if the given {@code model} is a favorite project, {@code false} otherwise.
*/
boolean isFavoriteProject(final ProjectDTO model);
/**
* Returns the given {@code model} corresponding {@link ProjectModelType} value.
*
* @param model
* The corresponding project.
* @return The given {@code model} corresponding {@link ProjectModelType} value.
*/
ProjectModelType getProjectModelType(final ProjectDTO model);
/**
* Method executed on given {@code model} corresponding star icon (favorite) click event.
*
* @param model
* The corresponding project.
*/
void onStarIconClicked(final ProjectDTO model);
}
public interface TitleSupplier {
String supplyTitle(int projectCount);
}
/**
* Defines the refreshing mode.
*
* @author Tom Miette (tmiette@ideia.fr)
*/
public static enum RefreshMode {
/**
* The project list is refreshed each time the {@link ProjectsListWidget#refresh(boolean, boolean, Integer...)} method is
* called.
*/
ALWAYS,
/**
* The project list is refreshed each time user clicks on the refresh button.
*/
MANUAL,
/**
* Refresh the project list when {@link ProjectsListWidget#refresh(boolean, boolean, Integer...)} is called for the first
* time. Subsequent refreshs are called by the refresh button.
*/
ON_FIRST_TIME;
}
/**
* Defines the loading mode.
*
* @author Tom Miette (tmiette@ideia.fr)
*/
public static enum LoadingMode {
/**
* The projects list id loaded by one single server call.
*/
ONE_TIME,
/**
* The projects list is loaded by chunks and a progress bar informs of the loading process.
*/
CHUNK;
}
public static final TitleSupplier DEFAULT_TITLE_SUPPLIER = new TitleSupplier() {
@Override
public String supplyTitle(int projectCount) {
return I18N.CONSTANTS.projects() + " (" + projectCount + ")";
}
};
// Current projects grid parameters.
private ProjectModelType currentModelType;
private final ArrayList<Integer> orgUnitsIds;
private boolean currentlyLoading = false;
private final Queue<GetProjects> commandQueue = new LinkedList<GetProjects>();
/**
* The refreshing mode (automatic by default).
*/
private RefreshMode refreshMode;
/**
* The loading mode (one time by default).
*/
private LoadingMode loadingMode;
/**
* The GetProjects command which will be executed for the next refresh.
*/
private GetProjects command;
/**
* Has the project grid already been loaded once?
*/
private boolean loaded;
private TitleSupplier titleSupplier = DEFAULT_TITLE_SUPPLIER;
/**
* Builds a new project list panel with default values.
*/
@Inject
public ProjectsListWidget(final View view, final Injector injector) {
super(view, injector);
this.orgUnitsIds = new ArrayList<Integer>();
// Default values.
init(null, null);
// Default filters parameters.
currentModelType = ProjectModelType.NGO;
}
/**
* {@inheritDoc}
*/
@Override
public void onBind() {
// --
// Listeners.
// --
addListeners();
// --
// Filters.
// --
addFilters();
// --
// Store sorter implementation.
// --
view.getStore().setStoreSorter(new StoreSorter<ProjectDTO>() {
@Override
public int compare(final Store<ProjectDTO> store, final ProjectDTO m1, final ProjectDTO m2, final String property) {
if (ProjectDTO.NAME.equals(property)) {
return m1.getName().compareToIgnoreCase(m2.getName());
} else if (ProjectDTO.FULL_NAME.equals(property)) {
return m1.getFullName().compareToIgnoreCase(m2.getFullName());
} else if (ProjectDTO.CURRENT_PHASE_NAME.equals(property)) {
return m1.getCurrentPhaseName().compareToIgnoreCase(m2.getCurrentPhaseName());
} else if (ProjectDTO.ORG_UNIT_NAME.equals(property)) {
return m1.getOrgUnitName().compareToIgnoreCase(m2.getOrgUnitName());
} else if (ProjectDTO.SPEND_BUDGET.equals(property)) {
final Double d1 = NumberUtils.adjustRatio(NumberUtils.ratio(m1.getSpendBudget(), m1.getPlannedBudget()));
final Double d2 = NumberUtils.adjustRatio(NumberUtils.ratio(m2.getSpendBudget(), m2.getPlannedBudget()));
return d1.compareTo(d2);
} else if (View.TIME_COLUMN.equals(property)) {
final Double d1 = m1.getElapsedTime();
final Double d2 = m2.getElapsedTime();
return d1.compareTo(d2);
} else if (ProjectDTO.ACTIVITY_ADVANCEMENT.equals(property)) {
final Integer a1 = m1.getActivityAdvancement();
final Integer a2 = m2.getActivityAdvancement();
return a1.compareTo(a2);
} else if (ProjectDTO.CATEGORY_ELEMENTS.equals(property)) {
return 0;
} else {
return super.compare(store, m1, m2, property);
}
}
});
// --
// Project name click handler.
// --
view.setTreeGridEventHandler(new TreeGridEventHandler<ProjectDTO>() {
@Override
public void onRowClickEvent(final ProjectDTO rowElement) {
Profiler.INSTANCE.startScenario(Scenario.OPEN_PROJECT);
eventBus.navigateRequest(Page.PROJECT_DASHBOARD.requestWith(RequestParameter.ID, rowElement.getId()));
}
});
// --
// View's specific handlers.
// --
view.setHandlerProvider(new HandlerProvider() {
@Override
public boolean isFavoriteProject(final ProjectDTO model) {
final Integer userId = auth().getUserId();
if (userId == null || model == null || ClientUtils.isEmpty(model.getFavoriteUsers())) {
return false;
}
for (final UserDTO u : model.getFavoriteUsers()) {
if (u.getId().equals(userId)) {
return true;
}
}
return false;
}
@Override
public ProjectModelType getProjectModelType(final ProjectDTO model) {
if(model == null) {
return ProjectModelType.NGO;
}
return model.getProjectModelType(auth().getOrganizationId());
}
@Override
public void onStarIconClicked(final ProjectDTO model) {
// Get the project's id from tree structure.
final Integer projectId = model.getId();
final UpdateProjectFavorite updateCmd;
if (isFavoriteProject(model)) {
// Remove the favorite user from project favorite user list
updateCmd = new UpdateProjectFavorite(projectId, UpdateProjectFavorite.UpdateType.REMOVE);
} else {
// Add current user into the favorite user list of the project
updateCmd = new UpdateProjectFavorite(projectId, UpdateProjectFavorite.UpdateType.ADD);
}
// RPC to change the favorite tag
dispatch.execute(updateCmd, new CommandResultHandler<CreateResult>() {
@Override
public void onCommandFailure(final Throwable caught) {
if (Log.isErrorEnabled()) {
Log.error("Error while setting the favorite status of the project #" + projectId + ".", caught);
}
N10N.error(I18N.CONSTANTS.projectStarredError(), I18N.CONSTANTS.projectStarredErrorDetails());
}
@Override
public void onCommandSuccess(final CreateResult result) {
if (result == null || result.getEntity() == null) {
N10N.warn(I18N.CONSTANTS.projectStarredError(), I18N.CONSTANTS.projectStarredErrorDetails());
return;
}
// Updates local store.
final ProjectDTO resultProject = (ProjectDTO) result.getEntity();
model.setFavoriteUsers(resultProject.getFavoriteUsers());
view.getStore().update(model);
N10N.notification(I18N.CONSTANTS.infoConfirmation(), I18N.CONSTANTS.projectStarred(), MessageType.VALID);
}
}, new LoadingMask(view.getProjectsPanel()));
}
});
}
public void setTitleSupplier(TitleSupplier titleSupplier) {
this.titleSupplier = titleSupplier;
updateTitle(titleSupplier);
}
private void updateTitle(TitleSupplier titleSupplier) {
view.getProjectsPanel().setHeadingText(titleSupplier.supplyTitle(view.getStore().getChildCount()));
}
/**
* <p>
* Initializes the widget.
* </p>
* <p>
* This method should be called in parent presenter's {@code onBind()} method.
* </p>
*
* @param refreshMode
* The {@link RefreshMode} value. If {@code null}, default {@link RefreshMode#ALWAYS} value is set.
* @param loadingMode
* The {@link LoadingMode} value. If {@code null}, default {@link LoadingMode#ONE_TIME} value is set.
*/
public void init(final RefreshMode refreshMode, final LoadingMode loadingMode) {
// Initializes values.
this.refreshMode = refreshMode != null ? refreshMode : RefreshMode.ALWAYS;
this.loadingMode = loadingMode != null ? loadingMode : LoadingMode.ONE_TIME;
}
/**
* Asks for a refresh of the projects list. If the refreshing mode is set to {@link RefreshMode#ALWAYS}, the list
* will be refreshed immediately. Otherwise, the list will be refreshed depending on the selected refreshing mode.
*
* @param viewOwnOrManage
* If the projects that the user own or manage must be included in the list (no matter of their
* organizational units).
* @param orgUnitsIds
* The list of ids of the organizational units for which the projects will be retrieved. The projects of each
* the sub-organizational units are retrieved automatically.
*/
public void refresh(final boolean viewOwnOrManage, final boolean forceRefresh, final Integer... orgUnitsIds) {
// Updates toolbar.
final boolean refreshEnabled = refreshMode == RefreshMode.MANUAL || refreshMode == RefreshMode.ON_FIRST_TIME;
final boolean exportEnabled = ProfileUtils.isGranted(auth(), GlobalPermissionEnum.GLOBAL_EXPORT);
view.updateToolbar(refreshEnabled, exportEnabled);
// Updates accessibility.
view.updateAccessibilityState(ProfileUtils.isGranted(auth(), GlobalPermissionEnum.VIEW_MY_PROJECTS));
final List<Integer> orgUnitsIdsAsList = orgUnitsIds != null ? Arrays.asList(orgUnitsIds) : null;
this.orgUnitsIds.clear();
this.orgUnitsIds.addAll(orgUnitsIdsAsList);
// Builds the next refresh command.
command = new GetProjects(orgUnitsIdsAsList, null);
command.setViewOwnOrManage(viewOwnOrManage);
// If the mode is automatic, the list is refreshed immediately.
if (forceRefresh || refreshMode == RefreshMode.ALWAYS || (refreshMode == RefreshMode.ON_FIRST_TIME && !loaded)) {
refreshProjectGrid(command);
loaded = true;
}
}
// ---------------------------------------------------------------------------------------------------------
//
// UTILITY METHODS.
//
// ---------------------------------------------------------------------------------------------------------
/**
* Sets-up the listeners.
*/
private void addListeners() {
// --
// Grid 'time' filter activation.
// --
view.getProjectsPanel().addListener(Events.AfterLayout, new Listener<BaseEvent>() {
@Override
public void handleEvent(final BaseEvent be) {
view.getGridFilters().getFilter(View.TIME_COLUMN).setActive(true, false);
}
});
// --
// Updates the projects grid heading when the store is filtered.
// --
view.getStore().addListener(Store.Filter, new Listener<StoreEvent<ProjectDTO>>() {
@Override
public void handleEvent(StoreEvent<ProjectDTO> be) {
updateTitle(titleSupplier);
}
});
// --
// Adds actions on filter by project model type.
// --
view.getProjectModelTypeField().addListener(Events.Change, new Listener<BaseEvent>() {
@Override
public void handleEvent(final BaseEvent be) {
currentModelType = view.getProjectModelTypeField().getValue();
applyProjectFilters();
}
});
// --
// Delete project event.
// --
registerHandler(eventBus.addHandler(UpdateEvent.getType(), new UpdateHandler() {
@Override
public void onUpdate(final UpdateEvent event) {
if (event.concern(UpdateEvent.PROJECT_CREATE)) {
// On project creation event.
final ProjectDTO createdProject = event.getParam(1);
view.getStore().clearFilters();
view.getStore().add(createdProject, false);
view.getStore().applyFilters(null);
} else if (event.concern(UpdateEvent.PROJECT_DELETE)) {
// On project delete event.
// Will force projects list to reload on next refresh.
loaded = false;
} else if (event.concern(UpdateEvent.PROJECT_DRAFT_DELETE)) {
// On 'draft' project delete event.
final ProjectDTO deletedDraftProject = event.getParam(0);
onDraftProjectDeleted(deletedDraftProject);
} else if(event.concern(UpdateEvent.USER_LOGGED_IN)) {
// Force dashboard to load projects for the new user.
loaded = false;
}
}
}));
// --
// Export action handler.
// --
view.getExportButton().addListener(Events.Select, new Listener<BaseEvent>() {
@Override
public void handleEvent(final BaseEvent be) {
eventBus.navigate(Page.PROJECT_EXPORTS);
}
});
}
/**
* Sets-up the grid filters.
*/
private void addFilters() {
// --
// The filter by model type.
// --
view.getStore().addFilter(new StoreFilter<ProjectDTO>() {
@Override
public boolean select(Store<ProjectDTO> store, ProjectDTO parent, ProjectDTO item, String property) {
boolean selected = false;
// Root item.
if (item.getParent() == null) {
// A root item is filtered if its type doesn't match the current type.
selected = item.getVisibility(auth().getOrganizationId()) == currentModelType;
}
// Child item
else {
// A child item is filtered if its parent is filtered.
selected = ((ProjectDTO) item.getParent()).getVisibility(auth().getOrganizationId()) == currentModelType;
}
return selected;
}
});
// --
// Refresh button selection listener.
// --
view.getRefreshButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
// Explicit refresh.
refreshProjectGrid(command);
}
});
// --
// Filters aren't used for the moment.
// --
view.getFilterButton().setVisible(false);
}
/**
* Applies the store filters.
*/
private void applyProjectFilters() {
view.getStore().applyFilters(null);
}
/**
* Refreshes the projects grid with the current parameters.
*
* @param cmd
* The {@link GetProjects} command to execute.
*/
private void refreshProjectGrid(final GetProjects cmd) {
// Checks that the user can view projects.
if (!ProfileUtils.isGranted(auth(), GlobalPermissionEnum.VIEW_MY_PROJECTS)) {
return;
}
if (cmd == null) {
return;
}
if (currentlyLoading) {
commandQueue.add(cmd);
return;
}
currentlyLoading = true;
// Reload filter labels for category filter list store.
reloadCategoryListFilterStore();
if (loadingMode == LoadingMode.ONE_TIME) {
// Loads projects in one time (one request).
loadProjectsInOneTime(cmd);
} else if (loadingMode == LoadingMode.CHUNK) {
// Loads projects in multiple 'chunks' (multiple requests) to render a progression.
loadProjectsInMultipleChunks(cmd);
}
}
/**
* Loads projects using one request.<br>
* To load the projects with a progress bar, see {@link #loadProjectsInMultipleChunks(GetProjects)}.
*
* @param cmd
* The command retrieving projects.
*/
private void loadProjectsInOneTime(final GetProjects cmd) {
cmd.setMappingMode(ProjectDTO.Mode._USE_PROJECT_MAPPER);
dispatch.execute(cmd, new CommandResultHandler<ListResult<ProjectDTO>>() {
@Override
public void onCommandSuccess(final ListResult<ProjectDTO> result) {
view.getStore().removeAll();
view.getStore().clearFilters();
if (result != null) {
addProjectToTreeGrid(result.getList());
}
applyProjectFilters();
view.updateRefreshingDate(new Date());
currentlyLoading = false;
// Try to execute the next loader
refreshProjectGrid(commandQueue.poll());
}
}, new LoadingMask(view.getProjectsPanel()));
}
/**
* Loads projects using multiple <em>chunks</em> (see {@link GetProjectsWorker}).<br>
* This mechanism allows the application to render a progress bar.
*
* @param cmd
* The command retrieving projects.
*/
private void loadProjectsInMultipleChunks(final GetProjects cmd) {
// --
// Builds a new chunks worker.
// --
final GetProjectsWorker worker = new GetProjectsWorker(dispatch, cmd, view.getProjectsPanel(), ClientConfiguration.getChunkSize());
worker.addWorkerListener(new GetProjectsWorker.WorkerListener() {
private int chunk = 0;
@Override
public void serverError(final Throwable error) {
if (Log.isErrorEnabled()) {
Log.error("Error while getting projects by chunks.", error);
}
applyProjectFilters();
view.updateRefreshingDate(new Date());
N10N.warn(I18N.CONSTANTS.error(), I18N.CONSTANTS.refreshProjectListError());
}
@Override
public void chunkRetrieved(final List<ProjectDTO> projects) {
addProjectToTreeGrid(projects);
}
@Override
public void ended() {
applyProjectFilters();
view.updateRefreshingDate(new Date());
view.getProjectsPanel().layout();
currentlyLoading = false;
// Try to execute the next loader
refreshProjectGrid(commandQueue.poll());
}
});
// --
// Runs the worker.
// --
view.getStore().removeAll();
view.getStore().clearFilters();
worker.run();
}
private void addProjectToTreeGrid(final List<ProjectDTO> projects) {
if (ClientUtils.isEmpty(projects)) {
return;
}
for (final ProjectDTO project : projects) {
project.setTreeRendering(true);
if (ClientUtils.isNotEmpty(project.getChildrenProjects())) {
for (final ProjectDTO child : project.getChildrenProjects()) {
child.setTreeRendering(true);
}
}
}
view.getStore().add(projects, true);
}
/**
* Fetches categories in active user's organization and fills {@link ListFilter} store of a category column.
*/
private void reloadCategoryListFilterStore() {
dispatch.execute(new GetCategories(), new CommandResultHandler<ListResult<CategoryTypeDTO>>() {
@SuppressWarnings("unchecked")
@Override
public void onCommandSuccess(final ListResult<CategoryTypeDTO> result) {
final ListFilter categoryListFilter = (ListFilter) view.getGridFilters().getFilter(ProjectDTO.CATEGORY_ELEMENTS);
final ListStore<ModelData> filterStore = categoryListFilter.getStore();
final List<CategoryTypeDTO> categories = result.getList();
for (final CategoryTypeDTO category : categories) {
final List<CategoryElementDTO> categoryElements = category.getCategoryElementsDTO();
for (final CategoryElementDTO element : categoryElements) {
final String filterLabel = element.getLabel() + " (" + category.getLabel() + ")";
boolean exist = false;
for (final ModelData model : filterStore.getModels()) {
if (model.get(View.CATEGORY_FILTER).equals(filterLabel)) {
exist = true;
break;
}
}
if (!exist) {
final ModelData model = new BaseModelData();
model.set(View.CATEGORY_FILTER, filterLabel);
filterStore.add(model);
}
}
}
}
});
}
/**
* Method executed when a <b>draft</b> project is deleted.
*
* @param deletedDraftProject
* The deleted <b>draft</b> project.
*/
private void onDraftProjectDeleted(final ProjectDTO deletedDraftProject) {
final TreeStore<ProjectDTO> store = view.getStore();
store.clearFilters();
final Integer projectId = deletedDraftProject.getId();
// Inspect root elements.
final List<ProjectDTO> parents = store.getRootItems();
for (final ProjectDTO parent : parents) {
final List<ProjectDTO> childrens = parent.getChildrenProjects();
for (final ProjectDTO child : childrens) {
// Deletes children if equals to project.
if (child.getId().equals(projectId) || child.getId().equals(projectId)) {
store.remove(parent, child);
}
}
}
// Deletes the parent that corresponds to project.
if (store.findModel(ProjectDTO.ID, projectId) != null) {
// Deletes children links.
store.removeAll(store.findModel(ProjectDTO.ID, projectId));
store.remove(store.findModel(ProjectDTO.ID, projectId));
} else {
// Deletes children links.
store.removeAll(store.findModel(ProjectDTO.ID, projectId));
store.remove(store.findModel(ProjectDTO.ID, projectId));
}
store.applyFilters(null);
// Show notification.
N10N.infoNotif(I18N.CONSTANTS.deleteTestProjectHeader(), I18N.CONSTANTS.deleteTestProjectSucceededDetails());
}
}