package org.sigmah.client.ui.view.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.Style; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.data.ModelKeyProvider; import com.extjs.gxt.ui.client.store.ListStore; 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.form.NumberField; import com.extjs.gxt.ui.client.widget.form.TextField; import com.extjs.gxt.ui.client.widget.grid.CellEditor; import com.extjs.gxt.ui.client.widget.grid.ColumnConfig; import com.extjs.gxt.ui.client.widget.grid.ColumnData; import com.extjs.gxt.ui.client.widget.grid.ColumnModel; import com.extjs.gxt.ui.client.widget.grid.EditorGrid; import com.extjs.gxt.ui.client.widget.grid.Grid; import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer; import com.extjs.gxt.ui.client.widget.menu.MenuItem; import com.extjs.gxt.ui.client.widget.toolbar.FillToolItem; import com.extjs.gxt.ui.client.widget.toolbar.ToolBar; import com.extjs.gxt.ui.client.widget.treegrid.EditorTreeGrid; import com.extjs.gxt.ui.client.widget.treegrid.TreeGrid; import com.extjs.gxt.ui.client.widget.treegrid.TreeGridCellRenderer; import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.NumberFormat; import org.sigmah.client.ui.presenter.project.indicator.ProjectIndicatorManagementPresenter; import org.sigmah.client.ui.view.base.AbstractView; import com.google.inject.Singleton; import java.util.ArrayList; import java.util.List; import org.sigmah.client.i18n.I18N; import org.sigmah.client.ui.presenter.project.indicator.IndicatorNumberFormats; import org.sigmah.client.ui.res.icon.IconImageBundle; import org.sigmah.client.ui.view.base.AbstractPopupView; import org.sigmah.client.ui.view.base.ViewPopupInterface; 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.ui.widget.form.Forms; import org.sigmah.client.ui.widget.layout.Layouts; import org.sigmah.client.ui.widget.panel.Panels; import org.sigmah.client.ui.widget.popup.PopupWidget; import org.sigmah.shared.dto.IndicatorDTO; import org.sigmah.shared.dto.IndicatorElement; import org.sigmah.shared.dto.IndicatorGroup; /** * {@link ProjectIndicatorManagementPresenter} view. * * @author Denis Colliot (dcolliot@ideia.fr) * @author Raphaƫl Calabro (rcalabro@ideia.fr) */ @Singleton public class ProjectIndicatorManagementView extends AbstractView implements ProjectIndicatorManagementPresenter.View { /** Main panel. */ private ContentPanel mainPanel; // ToolBar buttons. private SplitButton saveButton; private MenuItem saveItem; private MenuItem discardChangesItem; private Button newIndicatorGroupButton; private Button newIndicatorButton; private Button deleteButton; private Button refreshButton; private Button exportButton; private EditorTreeGrid<IndicatorElement> treeGrid; /** New indicator group view */ private ViewPopupInterface indicatorGroupPopup; private FormPanel indicatorGroupForm; private Field<String> indicatorGroupNameField; private Button indicatorGroupSaveButton; private boolean editable; /** * {@inheritDoc} */ @Override public void initialize() { mainPanel = Panels.content(I18N.CONSTANTS.projectTabIndicators(), Layouts.fitLayout()); mainPanel.setTopComponent(buildToolbar()); mainPanel.add(buildTreeGrid()); indicatorGroupPopup = buildIndicatorGroupPopup(); add(mainPanel); } @Override public TreeGrid<IndicatorElement> getTreeGrid() { return treeGrid; } @Override public TreeStore<IndicatorElement> getStore() { return treeGrid.getTreeStore(); } @Override public SplitButton getSaveButton() { return saveButton; } @Override public MenuItem getSaveItem() { return saveItem; } @Override public MenuItem getDiscardChangesItem() { return discardChangesItem; } @Override public Button getNewIndicatorGroupButton() { return newIndicatorGroupButton; } @Override public Button getNewIndicatorButton() { return newIndicatorButton; } @Override public Button getDeleteButton() { return deleteButton; } @Override public Button getRefreshButton() { return refreshButton; } @Override public Button getExportButton() { return exportButton; } @Override public ViewPopupInterface getIndicatorGroupPopup() { return indicatorGroupPopup; } @Override public FormPanel getIndicatorGroupForm() { return indicatorGroupForm; } @Override public Field<String> getIndicatorGroupNameField() { return indicatorGroupNameField; } @Override public Button getIndicatorGroupSaveButton() { return indicatorGroupSaveButton; } @Override public void setTreeGridEventHandler(TreeGridEventHandler<IndicatorElement> handler) { } @Override public void refreshTreeGrid() { treeGrid.getView().refresh(false); } @Override public void setEditable(boolean editable) { this.editable = editable; } /** * Builds the actions toolbar. * * @return The actions toolbar. */ private ToolBar buildToolbar() { // Save or cancel changes button. saveButton = Forms.saveSplitButton(); saveItem = (MenuItem) saveButton.getMenu().getItem(0); discardChangesItem = (MenuItem) saveButton.getMenu().getItem(1); // New indicator group button. newIndicatorGroupButton = Forms.button(I18N.CONSTANTS.newIndicatorGroup()); // New indicator button. newIndicatorButton = Forms.button(I18N.CONSTANTS.newIndicator()); // Delete button. deleteButton = Forms.button(I18N.CONSTANTS.delete()); // Refresh button. refreshButton = Forms.button(I18N.CONSTANTS.refreshPreview(), IconImageBundle.ICONS.refresh()); // Export form button. exportButton = Forms.button(I18N.CONSTANTS.export(), IconImageBundle.ICONS.excel()); // Create the toolbar instance and add the buttons. final ToolBar toolBar = new ToolBar(); toolBar.add(saveButton); toolBar.add(newIndicatorGroupButton); toolBar.add(newIndicatorButton); toolBar.add(deleteButton); toolBar.add(refreshButton); toolBar.add(new FillToolItem()); toolBar.add(exportButton); return toolBar; } /** * Builds the tree grid component. * * @return The tree grid component. */ private TreeGrid<IndicatorElement> buildTreeGrid() { // Columns IndicatorResources.INSTANCE.css().ensureInjected(); final List<ColumnConfig> columns = createColumns(); // Store final TreeStore<IndicatorElement> store = createTreeStore(); // Grid treeGrid = createTreeGrid(store, columns); treeGrid.setBorders(true); treeGrid.getStyle().setNodeCloseIcon(null); treeGrid.getStyle().setNodeOpenIcon(null); treeGrid.getStyle().setLeafIcon(null); treeGrid.setAutoExpandColumn(IndicatorDTO.NAME); treeGrid.setTrackMouseOver(false); treeGrid.setClicksToEdit(EditorGrid.ClicksToEdit.TWO); // TODO: Add a SelectionModel return treeGrid; } /** * Builds the "new indicator group" popup and its fields. * * @return The popup. */ private ViewPopupInterface buildIndicatorGroupPopup() { indicatorGroupForm = Forms.panel(130); indicatorGroupNameField = Forms.text(I18N.CONSTANTS.name(), true, 128); indicatorGroupForm.add(indicatorGroupNameField); indicatorGroupSaveButton = Forms.button(I18N.CONSTANTS.adminOrgUnitCreateButton(), IconImageBundle.ICONS.save()); indicatorGroupForm.addButton(indicatorGroupSaveButton); return new AbstractPopupView(new PopupWidget(true)) { @Override public void initialize() { setPopupTitle(I18N.CONSTANTS.newIndicatorGroup()); initPopup(indicatorGroupForm); } }; } /** * Creates the tree grid element using the given store and columns. * * @param store Tree store to use. * @param columns List of columns. * @return The tree grid element. */ private EditorTreeGrid<IndicatorElement> createTreeGrid(final TreeStore<IndicatorElement> store, final List<ColumnConfig> columns) { return new EditorTreeGrid<IndicatorElement>(store, new ColumnModel(columns)) { @Override protected boolean hasChildren(IndicatorElement indicatorElement) { return indicatorElement instanceof IndicatorGroup; } }; } /** * Creates the column configs of the tree grid. * * @return The list of column config. */ protected List<ColumnConfig> createColumns() { final ArrayList<ColumnConfig> columns = new ArrayList<ColumnConfig>(); TextField<String> nameEditor = new TextField<String>(); nameEditor.setAllowBlank(false); final ColumnConfig nameColumn = new ColumnConfig(IndicatorDTO.NAME, I18N.CONSTANTS.name(), 150); nameColumn.setRenderer(new TreeGridCellRenderer() { @Override public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) { if(model instanceof IndicatorDTO) { final IndicatorDTO indicator = (IndicatorDTO) model; final IndicatorResources.Style css = IndicatorResources.INSTANCE.css(); return new StringBuilder(toHTMLIcon(css.mapIcon())) .append("<span class='") .append(editable ? css.indicatorLabel() : css.indicatorLabelInactive()) .append("'>") .append(indicator.get(property)) .append("</span>") .toString(); } else { return super.render(model, property, config, rowIndex, colIndex, store, grid); } } }); nameColumn.setEditor(new CellEditor(nameEditor)); columns.add(nameColumn); final ColumnConfig codeColumn = new ColumnConfig(IndicatorDTO.CODE, I18N.CONSTANTS.code(), 75); codeColumn.setEditor(new CellEditor(new TextField<String>())); columns.add(codeColumn); final ColumnConfig objectiveColumn = new ColumnConfig(IndicatorDTO.OBJECTIVE, I18N.CONSTANTS.targetValue(), 75); objectiveColumn.setRenderer(new GridCellRenderer() { @Override public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) { if(model instanceof IndicatorDTO) { return formatIndicatorValue((IndicatorDTO) model, property); } else { return ""; } } }); objectiveColumn.setEditor(new CellEditor(new NumberField())); objectiveColumn.setAlignment(Style.HorizontalAlignment.RIGHT); columns.add(objectiveColumn); final ColumnConfig valueColumn = new ColumnConfig(IndicatorDTO.CURRENT_VALUE, I18N.CONSTANTS.value(), 75); valueColumn.setRenderer(new GridCellRenderer() { @Override public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) { if(model instanceof IndicatorDTO) { final IndicatorDTO indicator = (IndicatorDTO) model; if (indicator.getLabelCounts() != null) { return indicator.formatMode(); } else { return formatIndicatorValue(indicator, property); } } else { return ""; } } }); valueColumn.setAlignment(Style.HorizontalAlignment.RIGHT); columns.add(valueColumn); return columns; } private String toHTMLIcon(String spriteStyle) { // we can't use the normal div produced by GWT because the icons need to be inline // to display properly in the existing GXT html structure return "<img width='16' height='16' src='" + GWT.getModuleBaseURL() + "clear.cache.gif' class='" + spriteStyle + "'>"; } /** * Format the value <code>property</code> of the given indicator. * * @param indicator Indicator to use. * @param property The property to retrieve. * * @return The value formatted according to the aggregation mode of the given indicator. */ private String formatIndicatorValue(final IndicatorDTO indicator, String property) { final Double value = indicator.get(property); if(value == null) { return ""; } final NumberFormat numberFormat = IndicatorNumberFormats.getNumberFormat(indicator); return numberFormat.format(value); } /** * Creates the store of the tree grid. * * @return The store of the tree grid. */ private TreeStore<IndicatorElement> createTreeStore() { final TreeStore<IndicatorElement> store = new TreeStore<IndicatorElement>(); store.setKeyProvider(new ModelKeyProvider<IndicatorElement>() { @Override public String getKey(IndicatorElement model) { final StringBuilder stringBuilder = new StringBuilder(); if (model instanceof IndicatorGroup) { stringBuilder.append("group"); } else { stringBuilder.append('i'); } stringBuilder.append(model.get(IndicatorDTO.ID)); return stringBuilder.toString(); } }); return store; } }