/**
* Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
*
* Project home : http://code.daikit.com/daikit4gxt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.daikit.daikit4gxt.client.ui.forms;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.daikit.daikit4gxt.client.DkMain;
import com.daikit.daikit4gxt.client.model.propertyaccess.EditDeletePropertyAccess;
import com.daikit.daikit4gxt.client.ui.UIInvalidatable;
import com.daikit.daikit4gxt.client.ui.cell.IconButtonCell;
import com.daikit.daikit4gxt.client.ui.cell.ListStoreIconButtonCell;
import com.daikit.daikit4gxt.client.ui.fields.MyDynamicAsyncPagingCombobox;
import com.daikit.daikit4gxt.client.ui.fields.MyDynamicComboBox;
import com.daikit.daikit4gxt.client.utils.miscs.UIUtils;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.PropertyAccess;
import com.sencha.gxt.data.shared.event.StoreAddEvent;
import com.sencha.gxt.data.shared.event.StoreAddEvent.StoreAddHandler;
import com.sencha.gxt.data.shared.event.StoreClearEvent;
import com.sencha.gxt.data.shared.event.StoreClearEvent.StoreClearHandler;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.form.ComboBox;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.tips.QuickTip;
import com.sencha.gxt.widget.core.client.toolbar.FillToolItem;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;
/**
* Reference Selector for for bean List property. (grid with top toolbar with dropdown and add button)
*
* @author tcaselli
* @version $Revision$ Last modifier: $Author$ Last commit: $Date$
* @param <M>
*/
public abstract class MyReferenceEditorGrid<M extends Serializable> extends AbstractDkHideableAdapterField<List<M>> implements
UIInvalidatable
{
private final Grid<M> grid;
private final ListStore<M> store;
private final IconButtonCell deleteCell;
private final TextButton buttonAdd;
private final ComboBox<M> combobox;
private boolean headerVisible = false;
private boolean enabled = true;
private final VerticalLayoutContainer verticalLayoutContainer;
/**
* Constructor
*
* @param listStore
* the {@link ListStore}
* @param columnConfigs
* the {@link ColumnConfig}s
* @param props
* a {@link PropertyAccess} for edited bean
*/
public MyReferenceEditorGrid(final ListStore<M> listStore, final List<ColumnConfig<M, ?>> columnConfigs,
final EditDeletePropertyAccess<M> props)
{
super(new ContentPanel());
verticalLayoutContainer = new VerticalLayoutContainer();
getContentPanel().add(verticalLayoutContainer);
getContentPanel().setHeaderVisible(false);
setHeight(DkMain.config().getEditorGridHeight());
this.store = listStore;
// this because driver calls setValue directly on the store.
store.addStoreClearHandler(new StoreClearHandler<M>()
{
@Override
public void onClear(final StoreClearEvent<M> event)
{
resetComboboxSelection();
}
});
// this because driver calls setValue directly on the store.
store.addStoreAddHandler(new StoreAddHandler<M>()
{
@Override
public void onAdd(final StoreAddEvent<M> event)
{
resetComboboxSelection();
}
});
final List<ColumnConfig<M, ?>> columns = new ArrayList<ColumnConfig<M, ?>>(columnConfigs);
final ColumnConfig<M, String> columnDelete = new ColumnConfig<M, String>(props.delete(), 30, "");
columnDelete.setMenuDisabled(true);
columnDelete.setResizable(false);
columnDelete.setSortable(false);
columnDelete.setFixed(true);
deleteCell = new ListStoreIconButtonCell<M>(DkMain.icons().delete2_16(), getDeleteTooltip(), listStore)
{
@Override
protected void onClick(final M model, final int column, final int row, final String modelKey)
{
if (isEnabled())
{
onDeleteButtonClicked(model);
}
}
@Override
protected boolean isCellIconVisible(final M model, final int column, final int row, final String modelKey)
{
return isModelDeletable(model, column, row, modelKey);
}
};
columnDelete.setCell(deleteCell);
columns.add(columnDelete);
final ColumnModel<M> cm = new ColumnModel<M>(columns);
grid = new Grid<M>(listStore, cm);
new QuickTip(grid);
verticalLayoutContainer.setBorders(false);
final ToolBar toolbar = new ToolBar();
combobox = createSelectionCombobox();
toolbar.add(combobox);
if (combobox instanceof MyDynamicAsyncPagingCombobox || combobox instanceof MyDynamicComboBox)
{
combobox.setWidth(300);
if (combobox instanceof MyDynamicAsyncPagingCombobox)
{
((MyDynamicAsyncPagingCombobox<M>) combobox).getPagingToolBar().setShowMenu(false);
}
}
toolbar.add(new FillToolItem());
buttonAdd = new TextButton(DkMain.i18n().label_add(), new SelectEvent.SelectHandler()
{
@Override
public void onSelect(final SelectEvent event)
{
onAddButtonClicked();
}
});
buttonAdd.setIcon(DkMain.icons().file_plus_16());
toolbar.add(buttonAdd);
toolbar.setHeight(29);
verticalLayoutContainer.add(toolbar, new VerticalLayoutData(1, 29));
verticalLayoutContainer.add(grid, new VerticalLayoutData(1, 1));
}
protected abstract ComboBox<M> createSelectionCombobox();
/**
* Method to be overridden to provide custom behavior
*
* @param model
* @param column
* @param row
* @param modelKey
* @return
*/
protected boolean isModelDeletable(final M model, final int column, final int row, final String modelKey)
{
return true;
};
/**
* Enable or disable buttons
*
* @param enabled
*/
@Override
public void setEnabled(final boolean enabled)
{
buttonAdd.setEnabled(enabled);
combobox.setEnabled(enabled);
this.enabled = enabled;
UIUtils.setGridContentEnabled(grid, enabled, disabledStyle);
}
@Override
public final boolean isEnabled()
{
return enabled;
}
/**
* @return the delete tooltip
*/
public abstract String getDeleteTooltip();
/**
* Set the add button tooltip
*
* @param tooltip
* the tooltip
*/
public void setAddTooltip(final String tooltip)
{
if (buttonAdd != null)
{
buttonAdd.setTitle(tooltip);
}
}
/**
* Set the add button label
*
* @param label
* the label
*/
public void setAddLabel(final String label)
{
if (buttonAdd != null)
{
buttonAdd.setText(label);
}
}
/**
* Delete button clicked
*/
protected void onDeleteButtonClicked(final M model)
{
store.remove(model);
}
/**
* Add button clicked
*/
protected void onAddButtonClicked()
{
final M model = getCombobox().getCurrentValue();
if (model != null && !store.getAll().contains(model))
{
store.add(model);
}
resetComboboxSelection();
}
/**
* @return the store
*/
public ListStore<M> getStore()
{
return store;
}
/**
* @return the grid
*/
public Grid<M> getGrid()
{
return grid;
}
/**
* @return the combobox
*/
public ComboBox<M> getCombobox()
{
return combobox;
}
@Override
public List<M> getValue()
{
return store.getAll();
}
/**
* Method not called in edition process. The editor/driver will call setValue on the store directly.
*/
@Override
public void setValue(final List<M> value)
{
store.clear();
if (value != null && value.size() > 0)
{
store.addAll(value);
}
resetComboboxSelection();
}
/**
* Reset the combo box selection.
*/
protected void resetComboboxSelection()
{
getCombobox().clear();
}
/**
* @return the buttonAdd
*/
public TextButton getButtonAdd()
{
return buttonAdd;
}
/**
* @return this editor grid {@link ContentPanel}
*/
public ContentPanel getContentPanel()
{
return (ContentPanel) getWidget();
}
/**
* Sets the heading of the {@link ContentPanel}
*
* @param heading
* the heading to be set
*/
public void setHeadingHtml(final String heading)
{
getContentPanel().setHeaderVisible(true);
getContentPanel().setHeadingHtml(heading);
headerVisible = true;
}
/**
* @return the headerVisible
*/
public boolean isHeaderVisible()
{
return headerVisible;
}
/**
* Editor.forceLayout -> ResizeContainer.forceLayout -> SimpleContainer.forceLayout -> ResizeContainer.applyLayout ->
* ContentPanel.setPixelSize<br>
*
* if(lastSize != new size) ContentPanel.onResize -> Dans cette methode on a getContainerTarget().setHeight(...)<br>
* <br>
* The ContentPanel onResize method was not called when the ContentPanel becomes visible due to size caching
*/
@Override
public void setVisible(final boolean visible)
{
if (visible && !isVisible())
{
getContentPanel().clearSizeCache();
}
super.setVisible(visible);
}
}