package org.activityinfo.ui.client.page.entry.admin; /* * #%L * ActivityInfo Server * %% * Copyright (C) 2009 - 2013 UNICEF * %% * 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.data.BaseListLoader; import com.extjs.gxt.ui.client.data.ListLoadResult; import com.extjs.gxt.ui.client.data.ListLoader; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.BaseObservable; import com.extjs.gxt.ui.client.store.ListStore; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.activityinfo.legacy.client.Dispatcher; import org.activityinfo.legacy.shared.Log; import org.activityinfo.legacy.shared.model.AdminEntityDTO; import org.activityinfo.legacy.shared.model.AdminLevelDTO; import org.activityinfo.legacy.shared.model.CountryDTO; import org.activityinfo.legacy.shared.model.HasAdminEntityValues; import org.activityinfo.legacy.shared.reports.util.mapping.Extents; import org.activityinfo.ui.client.component.report.editor.map.symbols.AdminBoundsHelper; import java.util.*; /** * Presenter which drives the selection of a set of heirarchial admin levels. */ public class AdminFieldSetPresenter extends BaseObservable implements HasAdminEntityValues { private class Level { private AdminLevelDTO level; private AdminEntityProxy proxy; private ListLoader<ListLoadResult<AdminEntityDTO>> loader; private ListStore<AdminEntityDTO> store; private AdminEntityDTO selection; private List<Level> children; private boolean enabled; public Level(AdminLevelDTO level) { this.level = level; this.proxy = new AdminEntityProxy(dispatcher, level.getId()); this.loader = new BaseListLoader<ListLoadResult<AdminEntityDTO>>(proxy); this.store = new ListStore<AdminEntityDTO>(loader); this.children = Lists.newArrayList(); if (level.isRoot()) { this.loader.load(); this.enabled = true; } else { this.enabled = false; } } /** * @return the AdminLevel id */ public int getId() { return level.getId(); } public String getPropertyName() { return AdminEntityDTO.getPropertyName(level.getId()); } public ListStore<AdminEntityDTO> getStore() { return store; } public AdminEntityDTO getSelection() { return selection; } /** * Sets the new selection, returning true if it is different from the * existing selection */ public boolean setSelection(AdminEntityDTO newSelection) { trace("setSelection(" + newSelection + "), was = " + selection); if (selection == null && newSelection != null) { updateSelection(newSelection); return true; } if (selection != null && newSelection == null) { updateSelection(newSelection); return true; } if (selection != null && newSelection != null) { if (selection.getId() != newSelection.getId()) { updateSelection(newSelection); return true; } } return false; } private void updateSelection(AdminEntityDTO newSelection) { trace("updateSelection(" + newSelection + ")"); this.selection = newSelection; fireEvent(new AdminLevelSelectionEvent(level.getId(), newSelection)); for (Level child : children) { child.onParentSelectionChanged(newSelection); } } public void addChild(Level child) { children.add(child); } public void onParentSelectionChanged(AdminEntityDTO newParentSelection) { trace("onParentSelectionChanged(" + newParentSelection + ")"); if (newParentSelection == null) { disable(); } else { proxy.setParentAdminEntityId(newParentSelection.getId()); setEnabled(true); if (selection != null && selection.getParentId() != newParentSelection.getId()) { setSelection(null); } } } public boolean isEnabled() { return enabled; } private void disable() { trace("disable()"); store.removeAll(); setEnabled(false); setSelection(null); } private void setEnabled(boolean newState) { trace("setEnabled(" + newState + ")"); if (enabled != newState) { this.enabled = newState; fireEvent(new LevelStateChangeEvent(level.getId(), newState)); } } private void trace(String message) { Log.trace("level(" + level.getName() + ")." + message); } } private final Dispatcher dispatcher; private final Extents countryBounds; private List<AdminLevelDTO> levels; private Map<Integer, Level> levelMap; private Extents bounds; private String boundsName = ""; public AdminFieldSetPresenter(Dispatcher dispatcher, Extents countryBounds, List<AdminLevelDTO> levels) { this.dispatcher = dispatcher; this.levels = Lists.newArrayList(sort(levels)); this.levelMap = Maps.newHashMap(); this.bounds = countryBounds; this.countryBounds = countryBounds; for (AdminLevelDTO level : levels) { levelMap.put(level.getId(), new Level(level)); } for (AdminLevelDTO level : levels) { if (!level.isRoot()) { Level parent = levelMap.get(level.getParentLevelId()); if (parent != null) { parent.addChild(levelMap.get(level.getId())); } } } } private ArrayList<AdminLevelDTO> sort(List<AdminLevelDTO> levels2) { ArrayList<AdminLevelDTO> sortedList = new ArrayList<>(); ArrayList<AdminLevelDTO> sorterList = new ArrayList<>(); for (AdminLevelDTO level : levels2) { if (level.getParentLevelId() == null) { sorterList.add(level); sortedList.add(level); } } while (levels2.size() != sortedList.size()) { ArrayList<AdminLevelDTO> tempList = new ArrayList<>(); for (AdminLevelDTO dto : sorterList) { for (AdminLevelDTO e : levels2) { if (e.getParentLevelId() != null) { if (e.getParentLevelId().equals(dto.getId())) { tempList.add(e); } } } } sortedList.addAll(tempList); sorterList.clear(); sorterList.addAll(tempList); } return sortedList; } private Level level(int id) { return levelMap.get(id); } public List<AdminLevelDTO> getAdminLevels() { return levels; } public ListStore<AdminEntityDTO> getStore(int levelId) { return level(levelId).getStore(); } /** * Sets the selection for a given admin level: * <ul> * <li>This WILL fire a SELECTION_CHANGED event for this level * <li>If child selections are not consistent with this new selection, they * will be updated recursively and will fire events as well if their * selection changes.</li> * </ul> */ public void setSelection(int levelId, AdminEntityDTO selection) { if (level(levelId).setSelection(selection)) { updateBounds(); fireEvent(new AdminSelectionChangedEvent()); } } /** * Sets the selection for all AdminLevels. A SELECTION_CHANGED event will be * fired for each changed level. */ public void setSelection(HasAdminEntityValues values) { for (Level level : levelMap.values()) { level.setSelection(values.getAdminEntity(level.getId())); } updateBounds(); fireEvent(new AdminSelectionChangedEvent()); } public Map<String, AdminEntityDTO> getPropertyMap() { Map<String, AdminEntityDTO> map = new HashMap<String, AdminEntityDTO>(); for (Level level : levelMap.values()) { map.put(level.getPropertyName(), level.getSelection()); } return map; } private void fireEvent(BaseEvent event) { fireEvent(event.getType(), event); } public Extents getBounds() { return bounds; } public String getBoundsName() { return boundsName; } private void updateBounds() { Extents oldBounds = bounds; bounds = AdminBoundsHelper.calculate(countryBounds, levels, new HasAdminEntityValues() { @Override public AdminEntityDTO getAdminEntity(int levelId) { return level(levelId).getSelection(); } }); if (!bounds.equals(oldBounds)) { boundsName = AdminBoundsHelper.name(bounds, levels, this); fireEvent(new BoundsChangedEvent(bounds, boundsName)); } } public Collection<Integer> getAdminEntityIds() { List<Integer> result = Lists.newArrayList(); for (Level level : levelMap.values()) { AdminEntityDTO entity = level.getSelection(); if (entity != null) { result.add(entity.getId()); } } return result; } @Override public AdminEntityDTO getAdminEntity(int levelId) { return level(levelId).getSelection(); } public AdminEntityDTO getAdminEntity(AdminLevelDTO level) { return level(level.getId()).getSelection(); } public boolean isLevelEnabled(int levelId) { return level(levelId).isEnabled(); } public boolean isLevelEnabled(AdminLevelDTO level) { return isLevelEnabled(level.getId()); } }