package org.ovirt.engine.ui.webadmin.editor;
import java.util.Collection;
import java.util.Map;
import org.ovirt.engine.core.compat.Event;
import org.ovirt.engine.core.compat.EventArgs;
import org.ovirt.engine.core.compat.IEventListener;
import org.ovirt.engine.core.compat.PropertyChangedEventArgs;
import org.ovirt.engine.ui.uicommonweb.models.EntityModel;
import org.ovirt.engine.ui.uicommonweb.models.ListModel;
import org.ovirt.engine.ui.uicommonweb.models.Model;
import org.ovirt.engine.ui.webadmin.widget.HasAccess;
import org.ovirt.engine.ui.webadmin.widget.HasValidation;
import org.ovirt.engine.ui.webadmin.widget.editor.TakesConstrainedValueEditor;
import org.ovirt.engine.ui.webadmin.widget.editor.WidgetWithLabelEditor;
import com.google.gwt.editor.client.EditorContext;
import com.google.gwt.editor.client.EditorVisitor;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.HasEnabled;
public class UiCommonEditorVisitor<M extends Model> extends EditorVisitor {
private final UiCommonEventMap eventMap;
private final Map<String, EntityModel> ownerModels;
private int tabIndexCounter = 0;
/**
* A Visitor for UICommon Edited Models.
*/
public UiCommonEditorVisitor(UiCommonEventMap eventMap, Map<String, EntityModel> ownerModels) {
this.eventMap = eventMap;
this.ownerModels = ownerModels;
}
@SuppressWarnings("unchecked")
@Override
public <T> boolean visit(final EditorContext<T> ctx) {
String absolutePath = ctx.getAbsolutePath();
LeafValueEditor<T> currentLeafEditor = ctx.asLeafValueEditor();
if (currentLeafEditor == null) {
// Ignore non-leaf Editors
return super.visit(ctx);
}
final LeafValueEditor<T> editor = getActualEditor(currentLeafEditor);
// If this Editor implements HasValueChangeHandlers, register a value change listener
if (editor instanceof HasValueChangeHandlers) {
((HasValueChangeHandlers<T>) editor).addValueChangeHandler(new ValueChangeHandler<T>() {
@Override
public void onValueChange(ValueChangeEvent<T> event) {
ctx.setInModel(event.getValue());
}
});
}
final WidgetWithLabelEditor<T, ? extends LeafValueEditor<T>, ?> functionalEditor =
getFunctionalEditor(currentLeafEditor);
if (functionalEditor != null) {
// Set tab index
functionalEditor.setTabIndex(++tabIndexCounter);
// Add key press handler
functionalEditor.addKeyPressHandler(new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
if (KeyCodes.KEY_ENTER == event.getNativeEvent().getKeyCode()) {
// Set value in model
ctx.setInModel(editor.getValue());
}
}
});
}
// Handle owner entity models
if (ownerModels.containsKey(absolutePath)) {
EntityModel ownerModel = ownerModels.get(absolutePath);
// If this editor edits a ListModel, initialize it
if (editor instanceof TakesConstrainedValueEditor && ownerModel instanceof ListModel) {
updateListEditor((TakesConstrainedValueEditor<T>) editor, (ListModel) ownerModel);
}
if (functionalEditor != null) {
// Register a property change listener on the owner entity model
ownerModel.getPropertyChangedEvent().addListener(new IEventListener() {
@Override
public void eventRaised(Event ev, Object sender, EventArgs args) {
EntityModel ownerModel = (EntityModel) sender;
String propName = ((PropertyChangedEventArgs) args).PropertyName;
// IsValid
if ("IsValid".equals(propName)) {
onIsValidPropertyChange(functionalEditor, ownerModel);
}
// IsChangable
else if ("IsChangable".equals(propName)) {
onIsChangablePropertyChange(functionalEditor, ownerModel);
}
// IsAvailable
else if ("IsAvailable".equals(propName)) {
onIsAvailablePropertyChange(functionalEditor, ownerModel);
}
}
});
// Update editor since we might have missed property change
// events fired as part of the entity model constructor
onIsValidPropertyChange(functionalEditor, ownerModel);
onIsChangablePropertyChange(functionalEditor, ownerModel);
onIsAvailablePropertyChange(functionalEditor, ownerModel);
}
}
// Register listeners
eventMap.registerListener(absolutePath, "EntityChanged", new IEventListener() {
@Override
public void eventRaised(Event ev, Object sender, EventArgs args) {
editor.setValue((T) ((EntityModel) sender).getEntity());
}
});
eventMap.registerListener(absolutePath, "ItemsChanged", new IEventListener() {
@Override
public void eventRaised(Event ev, Object sender, EventArgs args) {
updateListEditor((TakesConstrainedValueEditor<T>) editor, (ListModel) sender);
}
});
eventMap.registerListener(absolutePath, "SelectedItemChanged", new IEventListener() {
@Override
public void eventRaised(Event ev, Object sender, EventArgs args) {
editor.setValue((T) ((ListModel) sender).getSelectedItem());
}
});
return super.visit(ctx);
}
@SuppressWarnings("unchecked")
<T> LeafValueEditor<T> getActualEditor(LeafValueEditor<T> editor) {
if (editor instanceof WidgetWithLabelEditor) {
return ((WidgetWithLabelEditor<T, ? extends LeafValueEditor<T>, ?>) editor).getSubEditor();
} else {
return editor;
}
}
@SuppressWarnings("unchecked")
<T> WidgetWithLabelEditor<T, ? extends LeafValueEditor<T>, ?> getFunctionalEditor(LeafValueEditor<T> editor) {
if (editor instanceof WidgetWithLabelEditor) {
return (WidgetWithLabelEditor<T, ? extends LeafValueEditor<T>, ?>) editor;
} else {
return null;
}
}
/**
* Update a ListEditor according to the items in the ListModel <BR>
* (this is required since the Editor is bound to the "selectedItem" property, and not to the "items" property).
*
* @param listEditor
* @param parentModel
*/
@SuppressWarnings("unchecked")
<O> void updateListEditor(TakesConstrainedValueEditor<O> listEditor, ListModel parentModel) {
Collection<O> items = (Collection<O>) parentModel.getItems();
if (items != null) {
if (items.size() > 0) {
// Order is important
parentModel.setSelectedItem(items.iterator().next());
listEditor.setValue(items.iterator().next());
}
listEditor.setAcceptableValues(items);
}
}
void onIsValidPropertyChange(HasValidation editor, EntityModel model) {
if (model.getIsValid()) {
editor.markAsValid();
} else {
editor.markAsInvalid(model.getInvalidityReasons());
}
}
void onIsChangablePropertyChange(HasEnabled editor, EntityModel model) {
boolean isChangable = model.getIsChangable();
editor.setEnabled(isChangable);
}
void onIsAvailablePropertyChange(HasAccess editor, EntityModel model) {
boolean isAvailable = model.getIsAvailable();
editor.setAccessible(isAvailable);
}
}