package org.sigmah.client.ui.view.project.logframe;
/*
* #%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.Collection;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.ui.notif.N10N;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Label;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.DateField;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.form.LabelField;
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.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayout;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayoutData;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayout;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayout.VBoxLayoutAlign;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayoutData;
/**
* A pop-up window to fill a form.
*
* @author tmi (v1.3)
* @author Denis Colliot (dcolliot@ideia.fr) (v2.0)
*/
// TODO Should be transformed into a proper presenter.
final class FormWindow {
/**
* Listen the form completion.
*
* @author tmi
*/
public static interface FormSubmitListener {
/**
* Method called when the form is correctly filled (values can be <code>null</code> if the null input is allowed for
* some fields). The values are returned in the same order in which fields have been added.
*
* @param values
* The input values.
*/
void formSubmitted(Object... values);
}
/**
* Manages a field displayed by this window.
*
* @author tmi
*/
private static final class FieldWrapper {
/**
* The form field.
*/
private final Field<?> field;
/**
* If the field allows blank value.
*/
private final boolean allowBlank;
public FieldWrapper(Field<?> field, boolean allowBlank) {
this.field = field;
this.allowBlank = allowBlank;
}
}
/**
* Combobox preferred height.
*/
private static final int FIELD_HEIGHT = 32;
/**
* Listeners.
*/
private final ArrayList<FormSubmitListener> listeners;
/**
* The pop-up window.
*/
private Window window;
/**
* The form title.
*/
private Label titleLabel;
/**
* The vertical panel to display fields.
*/
private ContentPanel fieldsPanel;
/**
* List of all fields.
*/
private final ArrayList<FieldWrapper> fields;
/**
* Initialize the window.
*/
public FormWindow() {
listeners = new ArrayList<FormSubmitListener>();
fields = new ArrayList<FieldWrapper>();
}
/**
* Adds a listener.
*
* @param l
* The new listener.
*/
public void addFormSubmitListener(FormSubmitListener l) {
if (l == null) {
return;
}
listeners.add(l);
}
/**
* Removes a listener.
*
* @param l
* The old listener.
*/
public void removeFormSubmitListener(FormSubmitListener l) {
if (l == null) {
return;
}
listeners.remove(l);
}
/**
* Informs the listeners that the form has been filled.
*
* @param values
* The input values.
*/
protected void fireFormSubmitted(Object... values) {
for (final FormSubmitListener l : listeners) {
l.formSubmitted(values);
}
}
/**
* Builds the pop-up window.
*/
private void init() {
// Build the form label.
titleLabel = new Label();
// Builds the submit button.
final Button selectButton = new Button(I18N.CONSTANTS.formWindowSubmitAction());
selectButton.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
final ArrayList<Object> values = new ArrayList<Object>();
// Retrieves each value.
for (final FieldWrapper field : fields) {
final Object value = field.field.getValue();
// Checks if null value is allowed for this field.
if (!field.allowBlank && value == null) {
N10N.warn(I18N.CONSTANTS.formWindowFieldsUnfilled(), I18N.CONSTANTS.formWindowFieldsUnfilledDetails());
return;
}
values.add(value);
}
fireFormSubmitted(values.toArray(new Object[values.size()]));
// Closes the window.
window.hide();
}
});
// Builds the fields panel.
fieldsPanel = new ContentPanel();
final VBoxLayout fieldsPanelLayout = new VBoxLayout();
fieldsPanelLayout.setVBoxLayoutAlign(VBoxLayoutAlign.STRETCH);
fieldsPanel.setHeaderVisible(false);
fieldsPanel.setLayout(fieldsPanelLayout);
fieldsPanel.setBorders(false);
fieldsPanel.setWidth("100%");
// Builds the main panel.
final ContentPanel mainPanel = new ContentPanel();
final VBoxLayout layout = new VBoxLayout();
layout.setVBoxLayoutAlign(VBoxLayoutAlign.STRETCH);
mainPanel.setHeaderVisible(false);
mainPanel.setLayout(layout);
mainPanel.setBorders(true);
mainPanel.setWidth("100%");
mainPanel.setTopComponent(null);
mainPanel.add(titleLabel, new VBoxLayoutData(new Margins(4, 8, 0, 8)));
mainPanel.add(fieldsPanel, new VBoxLayoutData(new Margins(4, 8, 0, 8)));
mainPanel.add(selectButton, new VBoxLayoutData(new Margins(4, 8, 0, 8)));
// Builds window.
window = new Window();
window.setWidth(445);
window.setPlain(true);
window.setModal(true);
window.setBlinkModal(true);
window.setLayout(new FitLayout());
window.add(mainPanel);
}
/**
* Initialize the window and open it.
*
* @param title
* The window title.
* @param header
* The heading label of the selection form.
*/
public void show(String title, String header) {
// Lazy building.
if (window == null) {
init();
}
titleLabel.setHtml(header);
// Open the window.
window.setHeadingHtml(title);
window.setHeight(100 + (FIELD_HEIGHT * (fields.size())));
window.show();
}
/**
* Removes all the fields of this window.
* This method removes also the listeners.
*/
public void clear() {
if (window != null) {
fieldsPanel.removeAll();
fields.clear();
listeners.clear();
window = null;
}
}
/**
* Cleans all fields.
*/
public void clean() {
for (final FieldWrapper field : fields) {
field.field.reset();
}
}
/**
* Adds a text field in the window.
*
* @param fieldLabelString
* The label of the text field. Can be <code>null</code>.
* @param allowBlank
* If the field is required.
* @return The field.
*/
public TextField<String> addTextField(String fieldLabelString, boolean allowBlank) {
// Lazy building.
if (window == null) {
init();
}
// Builds the text field.
final TextField<String> field = new TextField<String>();
field.setAllowBlank(allowBlank);
field.setFieldLabel(fieldLabelString);
fields.add(new FieldWrapper(field, allowBlank));
addField(field, fieldLabelString);
return field;
}
/**
* Adds a number field in the window.
*
* @param fieldLabelString
* The label of the number field. Can be <code>null</code>.
* @param allowBlank
* If the field is required.
* @return The field.
*/
public NumberField addNumberField(String fieldLabelString, boolean allowBlank) {
// Lazy building.
if (window == null) {
init();
}
// Builds the text field.
final NumberField field = new NumberField();
field.setAllowBlank(allowBlank);
field.setFieldLabel(fieldLabelString);
fields.add(new FieldWrapper(field, allowBlank));
addField(field, fieldLabelString);
return field;
}
/**
* Adds a date field in the window.
*
* @param fieldLabelString
* The label of the date field. Can be <code>null</code>.
* @param allowBlank
* If the field is required.
* @return The field.
*/
public DateField addDateField(String fieldLabelString, boolean allowBlank) {
// Lazy building.
if (window == null) {
init();
}
// Builds the text field.
final DateField field = new DateField();
field.setAllowBlank(allowBlank);
field.setFieldLabel(fieldLabelString);
fields.add(new FieldWrapper(field, allowBlank));
addField(field, fieldLabelString);
return field;
}
/**
* Adds a label field in the window.
*
* @param fieldLabelString
* The label of the date field. Can be <code>null</code>.
* @return The field.
*/
public LabelField addLabelField(String fieldLabelString) {
// Lazy building.
if (window == null) {
init();
}
// Builds the text field.
final LabelField field = new LabelField();
field.setFieldLabel(fieldLabelString);
fields.add(new FieldWrapper(field, true));
addField(field, fieldLabelString);
return field;
}
/**
* Adds a list of choices available in the window. The elements are shown in a combobox with uses the field
* <code>label</code>. Ensure that your model provides this attribute.
*
* @param <E>
* The type of selectable elements.
* @param fieldLabelString
* The label of the list of choices. Can be <code>null</code>.
* @param choices
* The list of choices.
* @param allowBlank
* If the selection for this list is required.
* @param displayField
* The underlying data field name to bind to this list. Must not be <code>null</code>.
* @return The field.
*/
public <E extends ModelData> ComboBox<E> addChoicesList(String fieldLabelString, Collection<E> choices, boolean allowBlank, String displayField) {
// Checks if the display field is specified.
if (displayField == null || "".equals(displayField.trim())) {
throw new IllegalArgumentException("the display field must not be null");
}
// Checks if the list of choices is correct.
if (choices == null || choices.isEmpty()) {
throw new IllegalArgumentException("the list of choices must contain at least one choice");
}
// Lazy building.
if (window == null) {
init();
}
// Builds the store.
final ListStore<E> store = new ListStore<E>();
store.add(new ArrayList<E>(choices));
// Builds the combobox.
final ComboBox<E> combobox = new ComboBox<E>();
combobox.setStore(store);
combobox.setEditable(true);
combobox.setAllowBlank(allowBlank);
combobox.setEmptyText(I18N.CONSTANTS.formWindowListEmptyText());
combobox.setLoadingText(I18N.CONSTANTS.loading());
combobox.setFieldLabel(fieldLabelString);
combobox.setDisplayField(displayField.trim());
combobox.setTriggerAction(TriggerAction.ALL);
fields.add(new FieldWrapper(combobox, allowBlank));
addField(combobox, fieldLabelString);
return combobox;
}
/**
* Adds a field in the form.
*
* @param field
* The field.
* @param fieldLabelString
* The label of the field. Can be <code>null</code>.
*/
private void addField(Field<?> field, String fieldLabelString) {
// Builds the field label.
final Label fieldLabel = new Label(fieldLabelString);
fieldLabel.setWidth("165px");
fieldLabel.addStyleName("flexibility-element-label");
// Builds the field panel.
final ContentPanel fieldPanel = new ContentPanel();
fieldPanel.setBodyBorder(false);
fieldPanel.setHeaderVisible(false);
fieldPanel.setLayout(new HBoxLayout());
fieldPanel.add(fieldLabel, new HBoxLayoutData(new Margins(4, 20, 0, 0)));
final HBoxLayoutData flex = new HBoxLayoutData(new Margins(0, 20, 0, 0));
flex.setFlex(1);
fieldPanel.add(field, flex);
// Adds the field in the panel.
fieldsPanel.setHeight(FIELD_HEIGHT * fields.size());
fieldsPanel.add(fieldPanel, new VBoxLayoutData(new Margins(4, 0, 0, 0)));
fieldsPanel.layout();
}
}