package org.activityinfo.ui.client.page.config.design;
/*
* #%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.GXT;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.binding.FieldBinding;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelIconProvider;
import com.extjs.gxt.ui.client.data.TreeModel;
import com.extjs.gxt.ui.client.dnd.DND;
import com.extjs.gxt.ui.client.dnd.TreeGridDragSource;
import com.extjs.gxt.ui.client.dnd.TreeGridDropTarget;
import com.extjs.gxt.ui.client.event.*;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.grid.*;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem;
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
import com.extjs.gxt.ui.client.widget.treegrid.CellTreeGridSelectionModel;
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.user.client.ui.AbstractImagePrototype;
import com.google.inject.Inject;
import org.activityinfo.i18n.shared.I18N;
import org.activityinfo.legacy.client.Dispatcher;
import org.activityinfo.legacy.shared.model.*;
import org.activityinfo.ui.client.page.common.dialog.FormDialogCallback;
import org.activityinfo.ui.client.page.common.dialog.FormDialogImpl;
import org.activityinfo.ui.client.page.common.dialog.FormDialogTether;
import org.activityinfo.ui.client.page.common.grid.AbstractEditorTreeGridView;
import org.activityinfo.ui.client.page.common.grid.ImprovedCellTreeGridSelectionModel;
import org.activityinfo.ui.client.page.common.toolbar.UIActions;
import org.activityinfo.ui.client.style.legacy.icon.IconImageBundle;
import java.util.ArrayList;
import java.util.List;
/**
* @author Alex Bertram
*/
public class DesignView extends AbstractEditorTreeGridView<ModelData, DesignPresenter> implements DesignPresenter.View {
private MenuItem newAttributeGroup;
private MenuItem newAttribute;
private MenuItem newIndicator;
private Menu newMenu;
private final class DragDropListener extends DNDListener {
private final TreeStore treeStore;
private DragDropListener(TreeStore treeStore) {
this.treeStore = treeStore;
}
@Override
public void dragMove(DNDEvent e) {
List<TreeModel> sourceData = e.getData();
ModelData source = sourceData.get(0).get("model");
TreeGrid.TreeNode target = tree.findNode(e.getTarget());
if (treeStore.getParent(target.getModel()) != treeStore.getParent(source)) {
e.setCancelled(true);
e.getStatus().setStatus(false);
}
}
@Override
public void dragDrop(DNDEvent e) {
List<TreeModel> sourceData = e.getData();
ModelData source = sourceData.get(0).get("model");
presenter.onNodeDropped(source);
}
}
private final Dispatcher service;
private EditorTreeGrid<ModelData> tree;
private ContentPanel formContainer;
private UserDatabaseDTO db;
@Inject
public DesignView(Dispatcher service) {
this.service = service;
}
@Override
public void init(DesignPresenter presenter, UserDatabaseDTO db, TreeStore store) {
this.db = db;
setLayout(new BorderLayout());
setHeadingText(I18N.CONSTANTS.design() + " - " + db.getName());
setIcon(IconImageBundle.ICONS.design());
super.init(presenter, store);
createFormContainer();
}
@Override
protected Grid<ModelData> createGridAndAddToContainer(Store store) {
final TreeStore treeStore = (TreeStore) store;
tree = new EditorTreeGrid<ModelData>(treeStore, createColumnModel());
tree.setSelectionModel(new ImprovedCellTreeGridSelectionModel<ModelData>());
tree.setClicksToEdit(EditorGrid.ClicksToEdit.TWO);
tree.setAutoExpandColumn("name");
tree.setHideHeaders(true);
tree.setLoadMask(true);
tree.setIconProvider(new ModelIconProvider<ModelData>() {
@Override
public AbstractImagePrototype getIcon(ModelData model) {
if (model instanceof IsActivityDTO) {
return IconImageBundle.ICONS.activity();
} else if (model instanceof Folder) {
return GXT.IMAGES.tree_folder_closed();
} else if (model instanceof AttributeGroupDTO) {
return IconImageBundle.ICONS.attributeGroup();
} else if (model instanceof AttributeDTO) {
return IconImageBundle.ICONS.attribute();
} else if (model instanceof IndicatorDTO) {
return IconImageBundle.ICONS.indicator();
} else if (model instanceof LocationTypeDTO) {
return IconImageBundle.ICONS.marker();
} else {
return null;
}
}
});
tree.addListener(Events.CellClick, new Listener<GridEvent>() {
@Override
public void handleEvent(GridEvent ge) {
showForm(tree.getStore().getAt(ge.getRowIndex()));
}
});
add(tree, new BorderLayoutData(Style.LayoutRegion.CENTER));
TreeGridDragSource source = new TreeGridDragSource(tree);
source.addDNDListener(new DNDListener() {
@Override
public void dragStart(DNDEvent e) {
ModelData sel = ((CellTreeGridSelectionModel) tree.getSelectionModel()).getSelectCell().model;
if (!db.isDesignAllowed() || sel == null || sel instanceof Folder) {
e.setCancelled(true);
e.getStatus().setStatus(false);
return;
}
super.dragStart(e);
}
});
TreeGridDropTarget target = new TreeGridDropTarget(tree);
target.setAllowSelfAsSource(true);
target.setFeedback(DND.Feedback.BOTH);
target.setAutoExpand(false);
target.addDNDListener(new DragDropListener(treeStore));
return tree;
}
@Override
protected void initToolBar() {
toolBar.addSaveSplitButton();
SelectionListener<MenuEvent> listener = new SelectionListener<MenuEvent>() {
@Override
public void componentSelected(MenuEvent ce) {
presenter.onNew(ce.getItem().getItemId());
}
};
newMenu = new Menu();
initNewMenu(newMenu, listener);
Button newButtonMenu = new Button(I18N.CONSTANTS.newText(), IconImageBundle.ICONS.add());
newButtonMenu.setMenu(newMenu);
newButtonMenu.setEnabled(db.isDesignAllowed());
toolBar.add(newButtonMenu);
toolBar.add(new SeparatorMenuItem());
toolBar.addButton(UIActions.EDIT, I18N.CONSTANTS.openFormDesigner(), IconImageBundle.ICONS.edit());
toolBar.addButton(UIActions.OPEN_TABLE, I18N.CONSTANTS.openTable(), IconImageBundle.ICONS.table());
toolBar.addDeleteButton();
toolBar.add(new SeparatorToolItem());
toolBar.addImportButton();
toolBar.addExcelExportButton();
}
protected void initNewMenu(Menu menu, SelectionListener<MenuEvent> listener) {
MenuItem newActivity = new MenuItem(I18N.CONSTANTS.newActivity(), IconImageBundle.ICONS.activity(), listener);
newActivity.setItemId("Activity");
menu.add(newActivity);
MenuItem newLocationType = new MenuItem(
I18N.CONSTANTS.newLocationType(),
IconImageBundle.ICONS.marker(), listener);
newLocationType.setItemId("LocationType");
menu.add(newLocationType);
newAttributeGroup = newMenuItem("AttributeGroup",
I18N.CONSTANTS.newAttributeGroup(),
IconImageBundle.ICONS.attribute(),
listener);
menu.add(newAttributeGroup);
newAttribute = newMenuItem("Attribute",
I18N.CONSTANTS.newAttribute(),
IconImageBundle.ICONS.attribute(),
listener);
menu.add(newAttribute);
newIndicator = new MenuItem(I18N.CONSTANTS.newIndicator(),
IconImageBundle.ICONS.indicator(),
listener);
newIndicator.setItemId("Indicator");
menu.add(newIndicator);
}
public Menu getNewMenu() {
return newMenu;
}
public MenuItem getNewAttributeGroup() {
return newAttributeGroup;
}
public MenuItem getNewAttribute() {
return newAttribute;
}
public MenuItem getNewIndicator() {
return newIndicator;
}
private MenuItem newMenuItem(String itemId,
String label,
AbstractImagePrototype icon,
SelectionListener<MenuEvent> listener) {
final MenuItem newAttribute = new MenuItem(label, icon, listener);
newAttribute.setItemId(itemId);
return newAttribute;
}
private void createFormContainer() {
formContainer = new ContentPanel();
formContainer.setHeaderVisible(false);
formContainer.setBorders(false);
formContainer.setFrame(false);
BorderLayoutData layout = new BorderLayoutData(Style.LayoutRegion.EAST);
layout.setSplit(true);
layout.setCollapsible(true);
layout.setSize(375);
layout.setMargins(new Margins(0, 0, 0, 5));
add(formContainer, layout);
}
private ColumnModel createColumnModel() {
List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
TextField<String> nameField = new TextField<String>();
nameField.setAllowBlank(false);
ColumnConfig nameColumn = new ColumnConfig("name", I18N.CONSTANTS.name(), 150);
nameColumn.setEditor(new CellEditor(nameField));
nameColumn.setRenderer(new TreeGridCellRenderer());
columns.add(nameColumn);
return new ColumnModel(columns);
}
protected Class formClassForSelection(ModelData sel) {
if (sel instanceof IsActivityDTO) {
return ActivityForm.class;
} else if (sel instanceof AttributeGroupDTO) {
return AttributeGroupForm.class;
} else if (sel instanceof IndicatorDTO) {
return IndicatorForm.class;
} else if (sel instanceof AttributeDTO) {
return AttributeForm.class;
} else if (sel instanceof LocationTypeDTO) {
return LocationTypeForm.class;
}
return null;
}
protected AbstractDesignForm createForm(ModelData sel) {
if (sel instanceof IsActivityDTO) {
return new ActivityForm(service, db);
} else if (sel instanceof AttributeGroupDTO) {
return new AttributeGroupForm();
} else if (sel instanceof AttributeDTO) {
return new AttributeForm();
} else if (sel instanceof IndicatorDTO) {
return new IndicatorForm();
} else if (sel instanceof LocationTypeDTO) {
return new LocationTypeForm();
}
return null;
}
public void showForm(ModelData model) {
// do we have the right form?
Class formClass = formClassForSelection(model);
AbstractDesignForm currentForm = null;
if (formContainer.getItemCount() != 0) {
currentForm = (AbstractDesignForm) formContainer.getItem(0);
}
if (formClass == null) {
if (currentForm != null) {
currentForm.getBinding().unbind();
formContainer.removeAll();
}
return;
} else {
if (currentForm == null || (!formClass.equals(currentForm.getClass()))) {
if (currentForm != null) {
formContainer.removeAll();
currentForm.getBinding().unbind();
}
currentForm = createForm(model);
currentForm.setReadOnly(!db.isDesignAllowed());
currentForm.setHeaderVisible(false);
currentForm.setBorders(false);
currentForm.setFrame(false);
currentForm.getBinding().setStore(tree.getStore());
formContainer.add(currentForm);
formContainer.layout();
}
}
currentForm.getBinding().bind(model);
}
@Override
public FormDialogTether showNewForm(EntityDTO entity, FormDialogCallback callback) {
AbstractDesignForm form = createForm(entity);
form.getBinding().bind(entity);
form.getBinding().setStore(tree.getStore());
for (FieldBinding field : form.getBinding().getBindings()) {
field.getField().clearInvalid();
}
FormDialogImpl dlg = new FormDialogImpl(form);
dlg.setWidth(form.getPreferredDialogWidth());
dlg.setHeight(form.getPreferredDialogHeight());
dlg.setScrollMode(Style.Scroll.AUTOY);
if (entity instanceof IsActivityDTO) {
dlg.setHeadingText(I18N.CONSTANTS.newActivity());
} else if (entity instanceof AttributeGroupDTO) {
dlg.setHeadingText(I18N.CONSTANTS.newAttributeGroup());
} else if (entity instanceof AttributeDTO) {
dlg.setHeadingText(I18N.CONSTANTS.newAttribute());
} else if (entity instanceof IndicatorDTO) {
dlg.setHeadingText(I18N.CONSTANTS.newIndicator());
} else if (entity instanceof LocationTypeDTO) {
dlg.setHeadingText(I18N.CONSTANTS.newLocationType());
}
dlg.show(callback);
return dlg;
}
}