/*
* RHQ Management Platform
* Copyright (C) 2005-2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.coregui.client.components.form;
import java.util.Date;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemIfFunction;
import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.form.validator.Validator;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.Messages;
/**
* This form item can be used to display a value normally in "read-only" form (i.e. as a StaticTextItem),
* but can be toggled into an "editable" form that allows the user to enter a different value.
*
* This default implementation provides editing the value within a text field. However, this class
* is designed to be extended, thus allowing the subclasses to edit values via checkboxes, radio buttons, etc.
*
* @author John Mazzitelli
*/
public class SimpleEditableFormItem extends CanvasItem {
protected static final Messages MSG = CoreGUI.getMessages();
protected FormItem staticItem;
protected FormItem editItem;
protected DynamicForm innerForm;
private boolean readOnly = false;
private boolean editing = false;
private ValueEditedHandler valueEditedHandler;
public SimpleEditableFormItem() {
this(null, null, null);
}
public SimpleEditableFormItem(String name, String title) {
this(name, title, null);
}
public SimpleEditableFormItem(String name, String title, ValueEditedHandler handler) {
if (name != null) {
setName(name);
}
if (title != null) {
setTitle(title);
}
if (handler != null) {
setValueEditedHandler(handler);
}
this.innerForm = new DynamicForm();
this.staticItem = prepareStaticFormItem();
this.editItem = prepareEditFormItem();
this.innerForm.setCanFocus(true);
this.innerForm.setNumCols(1);
addHandlers();
this.innerForm.setItems(staticItem, editItem);
setCanvas(this.innerForm);
setCanFocus(true);
}
protected void addHandlers() {
this.editItem.addBlurHandler(new BlurHandler() {
public void onBlur(BlurEvent event) {
if (SimpleEditableFormItem.this.innerForm.validate(false)) {
Object newValue = event.getItem().getValue();
setApprovedNewValue(newValue);
}
}
});
}
protected FormItem prepareStaticFormItem() {
FormItem item = instantiateStaticFormItem();
item.setShowTitle(false);
item.setShowIfCondition(new FormItemIfFunction() {
public boolean execute(FormItem item, Object value, DynamicForm form) {
return !isEditing();
}
});
return item;
}
protected FormItem prepareEditFormItem() {
FormItem item = instantiateEditFormItem();
item.setShowTitle(false);
item.setShowIfCondition(new FormItemIfFunction() {
public boolean execute(FormItem item, Object value, DynamicForm form) {
return isEditing();
}
});
return item;
}
/**
* This instantiates the static item. The form item created by this method will
* be further customized by {@link #prepareStaticFormItem()}.
*
* @return the form item used to show the static (read-only) value
*/
protected FormItem instantiateStaticFormItem() {
StaticTextItem item = new StaticTextItem();
return item;
}
/**
* This instantiates the edit item. The form item created by this method will
* be further customized by {@link #prepareEditFormItem()}.
*
* Subclasses will usually override this method to provide a different form
* item such as a checkbox, radio buttons, etc.
*
* @return the form item used to edit the value
*/
protected FormItem instantiateEditFormItem() {
TextItem item = new TextItem();
return item;
}
/**
* This sets the {@link #setEditing(boolean) edit flag} to false and ensures
* the component switches to the static, read-only mode.
*/
public void switchToStaticMode() {
if (isEditing()) {
setEditing(false);
markForRedraw();
}
}
/**
* This sets the {@link #setEditing(boolean) edit flag} to true and ensures
* the component switches to the edit, read-write mode.
*/
public void switchToEditMode() {
if (!isEditing()) {
setEditing(true);
setEditItemValue(this.editItem, this.staticItem.getValue());
markForRedraw();
}
}
public boolean isEditing() {
return this.editing;
}
/**
* This just sets the internal flag indicating if the form is in editing mode.
* To switch modes, you use {@link #switchToEditMode()} and {@link #switchToStaticMode()}.
*
* @param editing the new editing flag
*/
protected void setEditing(boolean editing) {
this.editing = editing;
}
/**
* When the user has accepted a new edited value for this form item, this method is called.
* This method is responsible for invoking the {@link #getValueEditedHandler() handler}.
*
* @param newValue the new value just accepted by the user and validated by the system
*/
protected void setApprovedNewValue(Object newValue) {
setStaticItemValue(this.staticItem, newValue);
if (this.valueEditedHandler != null) {
this.valueEditedHandler.editedValue(newValue);
}
}
/**
* When a user first elects to edit a value (i.e. switches from static, read-only mode
* to edit mode), the static value needs to be converted to an object that is appropriate
* for the edit form item value. This method performs that necessary conversion and
* sets the edit item's value to that converted value. The converted value is also returned.
*
* @param editItem the edit form item whose value needs to be set
* @param value the static value that needs to be converted and set in the given edit item
*
* @return the converted value that was set in the edit item
*/
protected Object setEditItemValue(FormItem editItem, Object value) {
String convertedValue = (value != null) ? value.toString() : null;
editItem.setValue(convertedValue);
return convertedValue;
}
/**
* When a user enters and accepts a new value, the new value needs to be converted
* to an appropriate value for display in the static, read-only item.
* This method performs that necessary conversion and sets the static item's value
* to that converted value. The converted value is also returned.
*
* @param staticItem the static form item whose value needs to be set
* @param value the value that needs to be converted for display in the static item
*
* @return the converted value that was set in the static item
*/
protected Object setStaticItemValue(FormItem staticItem, Object value) {
String convertedValue = (value != null) ? value.toString() : null;
staticItem.setValue(convertedValue);
return convertedValue;
}
//
// Below are delegating methods to setValue().
// When setting this form item's value, we are really setting the static item's value.
//
@Override
public void setValue(boolean value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(Date value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(double value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(float value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(int value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(Object value) {
this.staticItem.setValue(value);
}
@Override
public void setValue(String value) {
if (this.staticItem instanceof StaticTextItem) {
((StaticTextItem) this.staticItem).setEscapeHTML(!(null == value || value.isEmpty()));
}
this.staticItem.setValue(value);
}
@Override
public Object getValue() {
return this.staticItem.getValue();
}
// this delegates to the edit item allowing custom validators to be added
@Override
public void setValidators(Validator... validators) {
this.editItem.setValidators(validators);
}
// direct outer-form validation to the edit item, which would have any set validators
@Override
public Boolean validate() {
return !editing || editItem.validate();
}
/**
* If the user is not allowed to edit this form item, <code>true</code> is returned.
* @return flag to indicate if the user is allowed to change the value or not
*/
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
this.staticItem.setTextBoxStyle((!readOnly) ? "editableText" : null);
markForRedraw();
}
/**
* Returns the handler that will be called when a user edits the current value.
* This is only called after the user accepts the new value and it passes validation.
*
* @return the callback handler that is invoked when the old value is edited resulting in a new value
*/
public ValueEditedHandler getValueEditedHandler() {
return this.valueEditedHandler;
}
public void setValueEditedHandler(ValueEditedHandler handler) {
this.valueEditedHandler = handler;
}
/**
* Marks the canvas item for redraw, which enables both the static and edit items to redraw themselves.
*/
protected void markForRedraw() {
getForm().markForRedraw();
this.innerForm.markForRedraw();
}
/**
* When a user has changed the value of the editable field item, this
* is the type of callback that is called to be informed of the change.
*/
public static interface ValueEditedHandler {
public void editedValue(Object newValue);
}
}