package org.sigmah.client.ui.widget.form;
/*
* #%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.List;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.ui.res.icon.IconImageBundle;
import org.sigmah.client.ui.widget.Loadable;
import org.sigmah.client.ui.widget.button.Button;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.shared.util.Pair;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.AdapterField;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.MultiField;
/**
* <p>
* Custom field implementation composed of one (or multiple) {@link ComboBox} and a {@link Button} (horizontally
* aligned).
* </p>
* <p>
* This field is not parameterized with generic argument to allow multiple fields types.
* </p>
*
* @author Denis Colliot (dcolliot@ideia.fr)
*/
public class ComboboxButtonField extends MultiField<ModelData> implements Loadable {
private final List<ComboBox<ModelData>> comboBoxes;
private final Button button;
private final AdapterField buttonAdapter;
/**
* Initializes a new {@code ComboboxButtonField} field instance with <b>one</b> comboBox.<br>
* To initialize multiple comboBoxes, see {@link #ComboboxButtonField(String, Pair...)} constructor.
*
* @param fieldLabel
* The field label.
* @param valueField
* The comboBox value field.
* @param displayField
* The comboBox display field.
*/
public ComboboxButtonField(String fieldLabel, String valueField, String displayField) {
this(fieldLabel, new Pair<String, String>(valueField, displayField));
}
/**
* Initializes a new {@code ComboboxButtonField} field instance with multiple comboBoxes.
*
* @param fieldLabel
* The field label.
* @param comboBoxFields
* The comboBox(es) { value ; display } fields.
*/
@SafeVarargs
public ComboboxButtonField(String fieldLabel, Pair<String, String>... comboBoxFields) {
assert ClientUtils.isNotEmpty(comboBoxFields) : "Provide at least one comboBox configuration.";
comboBoxes = new ArrayList<ComboBox<ModelData>>(comboBoxFields.length);
button = Forms.button(I18N.CONSTANTS.addItem(), IconImageBundle.ICONS.add()); // Default configuration.
buttonAdapter = Forms.adapter(fieldLabel, button);
if (ClientUtils.isNotBlank(fieldLabel)) {
setFieldLabel(fieldLabel);
} else {
setLabelSeparator("");
}
setSpacing(7);
for (final Pair<String, String> comboBoxField : comboBoxFields) {
if (comboBoxField == null) {
continue;
}
final ComboBox<ModelData> comboBox = Forms.combobox(null, false, comboBoxField.left, comboBoxField.right);
comboBoxes.add(comboBox);
add(comboBox);
}
add(buttonAdapter);
}
/**
* {@inheritDoc}
*/
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
int buttonWidth = buttonAdapter.el().getParent().getWidth();
if (buttonWidth <= 0) {
// TODO Try to 'always' determine dynamic button width (see 'EditFlexibleElementAdminView' problem).
buttonWidth = 70; // Arbitrary width considering all i18n translations widths.
button.setWidth(buttonWidth);
}
final int comboBoxesNumber = comboBoxes.size();
final int comboBoxesTotalWidth = width - buttonWidth - (comboBoxesNumber * spacing);
final int comboBoxWidth = comboBoxesTotalWidth / comboBoxesNumber;
for (final ComboBox<ModelData> comboBox : comboBoxes) {
comboBox.setSize(comboBoxWidth, height);
}
}
/**
* {@inheritDoc}
*/
@Override
public void setLoading(boolean loading) {
button.setLoading(loading);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isLoading() {
return button.isLoading();
}
/**
* Returns the given {@code index} corresponding inner {@link ComboBox} field.<br>
* The returned field type is automatically cast to the referenced type.
*
* @param index
* The comboBox index.
* @return The inner {@link ComboBox} field.
* @throws IndexOutOfBoundsException
* If the given {@code index} is out of bounds.
*/
@SuppressWarnings("unchecked")
public <M extends ModelData> ComboBox<M> getComboBox(final int index) {
return (ComboBox<M>) comboBoxes.get(index);
}
/**
* Returns the given {@code index} corresponding inner {@code ComboBox}'s {@link ListStore}.<br>
* The returned store type is automatically cast to the referenced type.
*
* @param index
* The comboBox index.
* @return The given {@code index} corresponding inner {@code ComboBox}'s {@link ListStore}.
* @throws IndexOutOfBoundsException
* If the given {@code index} is out of bounds.
*/
@SuppressWarnings("unchecked")
public <M extends ModelData> ListStore<M> getStore(final int index) {
return (ListStore<M>) getComboBox(index).getStore();
}
/**
* Returns the inner {@link Button}.
*
* @return The inner {@link Button} (never {@code null}).
*/
public Button getButton() {
return button;
}
/**
* Clears any text/value currently set in the comboBox(es) field(s).
*/
public void clearSelections() {
for (final ComboBox<ModelData> comboBox : comboBoxes) {
comboBox.clearSelections();
}
}
}