/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.dm.action;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.FlexoEditor;
import org.openflexo.foundation.FlexoException;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.action.FlexoAction;
import org.openflexo.foundation.action.FlexoActionExecutionFailed;
import org.openflexo.foundation.action.FlexoActionType;
import org.openflexo.foundation.bindings.BindingValue;
import org.openflexo.foundation.bindings.BindingVariable;
import org.openflexo.foundation.bindings.ComponentBindingDefinition;
import org.openflexo.foundation.bindings.MethodCall;
import org.openflexo.foundation.dm.DMEntity;
import org.openflexo.foundation.dm.DMMethod;
import org.openflexo.foundation.dm.DMProperty;
import org.openflexo.foundation.dm.DMType;
import org.openflexo.foundation.dm.Typed;
import org.openflexo.foundation.dm.eo.DMEOAttribute;
import org.openflexo.foundation.ie.action.DropIEElement;
import org.openflexo.foundation.ie.cl.action.AddComponent;
import org.openflexo.foundation.ie.cl.action.AddComponent.ComponentType;
import org.openflexo.foundation.ie.util.TextFieldType;
import org.openflexo.foundation.ie.util.WidgetType;
import org.openflexo.foundation.ie.widget.ColumnIsNotEmpty;
import org.openflexo.foundation.ie.widget.IEAbstractListWidget;
import org.openflexo.foundation.ie.widget.IEBlocWidget;
import org.openflexo.foundation.ie.widget.IECheckBoxWidget;
import org.openflexo.foundation.ie.widget.IEEditableTextWidget;
import org.openflexo.foundation.ie.widget.IEHTMLTableWidget;
import org.openflexo.foundation.ie.widget.IELabelWidget;
import org.openflexo.foundation.ie.widget.IERadioButtonWidget;
import org.openflexo.foundation.ie.widget.IEStringWidget;
import org.openflexo.foundation.ie.widget.IETextFieldWidget;
import org.openflexo.foundation.ie.widget.IEWidget;
import org.openflexo.foundation.ie.widget.RowIsNotEmpty;
import org.openflexo.localization.FlexoLocalization;
public class CreateComponentFromEntity extends FlexoAction<CreateComponentFromEntity, DMEntity, DMEntity> {
public static class DMAccessorWidget {
public WidgetType widget;
public DMProperty property;
public DMMethod method;
/**
* Overrides toString
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "DMAccessorWidget: accessor=" + (property != null ? property : method) + " widget=" + widget;
}
}
static final Logger logger = Logger.getLogger(CreateComponentFromEntity.class.getPackage().getName());
public static FlexoActionType<CreateComponentFromEntity, DMEntity, DMEntity> actionType = new FlexoActionType<CreateComponentFromEntity, DMEntity, DMEntity>(
"create_component_from_entity", FlexoActionType.exportMenu, FlexoActionType.defaultGroup) {
/**
* Factory method
*/
@Override
public CreateComponentFromEntity makeNewAction(DMEntity focusedObject, Vector<DMEntity> globalSelection, FlexoEditor editor) {
return new CreateComponentFromEntity(focusedObject, globalSelection, editor);
}
@Override
public boolean isVisibleForSelection(DMEntity object, Vector<DMEntity> globalSelection) {
return true;
}
@Override
public boolean isEnabledForSelection(DMEntity object, Vector<DMEntity> globalSelection) {
return object != null
&& (globalSelection == null || globalSelection.size() == 0 || globalSelection.size() == 1
&& globalSelection.firstElement() == object);
}
};
static {
FlexoModelObject.addActionForClass(actionType, DMEntity.class);
}
private ComponentType componentType;
private String name;
private Vector<DMAccessorWidget> widgets;
private boolean copyDescription = true;
protected CreateComponentFromEntity(DMEntity focusedObject, Vector<DMEntity> globalSelection, FlexoEditor editor) {
super(actionType, focusedObject, globalSelection, editor);
}
/**
* Overrides doAction
*
* @throws ColumnIsNotEmpty
* @throws RowIsNotEmpty
* @see org.openflexo.foundation.action.FlexoAction#doAction(java.lang.Object)
*/
@Override
protected void doAction(Object context) throws FlexoException, ColumnIsNotEmpty, RowIsNotEmpty {
if (getFocusedObject() == null) {
throw new NullPointerException("No entity selected");
}
AddComponent addComponent = AddComponent.actionType.makeNewEmbeddedAction(getFocusedObject().getProject()
.getFlexoComponentLibrary().getRootFolder(), null, this);
addComponent.setComponentType(getComponentType());
addComponent.setNewComponentName(getName());
addComponent.doAction();
if (!addComponent.hasActionExecutionSucceeded()) {
throw new FlexoActionExecutionFailed(addComponent);
}
ComponentBindingDefinition cbd = addComponent.getNewComponent().createNewBinding();
cbd.setVariableName(getVariableName());
cbd.setIsMandatory(true);
cbd.setIsSettable(true);
cbd.setType(DMType.makeResolvedDMType(getFocusedObject()));
DropIEElement dropBlock = DropIEElement.actionType.makeNewEmbeddedAction(addComponent.getNewComponent().getWOComponent(), null,
this);
dropBlock.setElementType(WidgetType.BLOCK);
dropBlock.setContainer(addComponent.getNewComponent().getWOComponent().getRootSequence());
dropBlock.setIndex(0);
dropBlock.doAction();
if (!dropBlock.hasActionExecutionSucceeded()) {
throw new FlexoActionExecutionFailed(dropBlock);
}
((IEBlocWidget) dropBlock.getDroppedWidget()).setTitle(FlexoLocalization.localizedForKey("edit") + " " + cbd.getVariableName());
DropIEElement dropTable = DropIEElement.actionType.makeNewEmbeddedAction(dropBlock.getDroppedWidget(), null, this);
dropTable.setElementType(WidgetType.HTMLTable);
dropTable.setContainer(dropBlock.getDroppedWidget());
dropTable.doAction();
if (!dropTable.hasActionExecutionSucceeded()) {
throw new FlexoActionExecutionFailed(dropTable);
}
IEHTMLTableWidget table = (IEHTMLTableWidget) dropTable.getDroppedWidget();
table.setColCount(4);
int rows = (getWidgets().size() + 1) / 2;
table.setRowCount(rows);
for (int i = 0; i < getWidgets().size(); i++) {
DMAccessorWidget aw = getWidgets().get(i);
if (aw.widget == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("No widget selected for " + aw);
}
continue;
}
String label;
String description;
Map<String, String> descriptions;
if (aw.property != null) {
label = extractLabel(aw.property.getName());
description = aw.property.getDescription();
descriptions = aw.property.getSpecificDescriptions();
// The next snippet is a little hack so that attributes declared
// as boolean ends up bound on the methods that really returns a
// boolean (instead of the default accessor that return a
// String)
if (aw.property instanceof DMEOAttribute) {
if (((DMEOAttribute) aw.property).isBoolean()) {
DMProperty p = aw.property.getEntity().getDMProperty(getName() + DMEOAttribute.BOOLEAN_METHOD_POSTFIX);
if (p != null) {
aw.property = p;
}
}
}
} else if (aw.method != null) {
label = extractLabel(aw.method.getName());
description = aw.method.getDescription();
descriptions = aw.method.getSpecificDescriptions();
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Left a widget without property nor method");
}
continue;
}
// Here nor label nor widget are null, `continue´ calls automatically skip those
DropIEElement dropLabel = DropIEElement.actionType.makeNewEmbeddedAction(addComponent.getNewComponent().getWOComponent(), null,
this);
dropLabel.setElementType(WidgetType.LABEL);
dropLabel.setContainer(table.getTDAt(i < rows ? i : i - rows, i < rows ? 0 : 2).getSequenceWidget());
dropLabel.setIndex(0);
dropLabel.doAction();
if (!dropLabel.hasActionExecutionSucceeded()) {
throw new FlexoActionExecutionFailed(dropLabel);
}
((IELabelWidget) dropLabel.getDroppedWidget()).setValue(label + ":");
DropIEElement dropWidget = DropIEElement.actionType.makeNewEmbeddedAction(addComponent.getNewComponent().getWOComponent(),
null, this);
dropWidget.setElementType(aw.widget);
dropWidget.setContainer(table.getTDAt(i < rows ? i : i - rows, i < rows ? 1 : 3).getSequenceWidget());
dropWidget.setIndex(0);
dropWidget.doAction();
if (!dropWidget.hasActionExecutionSucceeded()) {
throw new FlexoActionExecutionFailed(dropLabel);
}
dropWidget.getDroppedWidget().setLabel(label);
if (copyDescription) {
dropWidget.getDroppedWidget().setDescription(description);
dropWidget.getDroppedWidget().setSpecificDescriptions(descriptions);
}
IEWidget droppedWidget = dropWidget.getDroppedWidget();
BindingVariable var = addComponent.getNewComponent().getBindingModel().getBindingVariableAt(0);
switch (aw.widget) {
case BROWSER:
case DROPDOWN:
BindingValue bv = new BindingValue(((IEAbstractListWidget) droppedWidget).getBindingSelectionDefinition(), droppedWidget);
bv.setBindingVariable(var);
DMProperty property = var.getType().getBaseEntity().getProperty(cbd.getVariableName());
bv.addBindingPathElement(property);
bv.addBindingPathElement(aw.property != null ? aw.property : new MethodCall(bv, aw.method));
((IEAbstractListWidget) droppedWidget).setBindingSelection(bv);
break;
case STRING:
bv = new BindingValue(((IEStringWidget) droppedWidget).getBindingValueDefinition(), droppedWidget);
bv.setBindingVariable(var);
property = var.getType().getBaseEntity().getProperty(cbd.getVariableName());
bv.addBindingPathElement(property);
bv.addBindingPathElement(aw.property != null ? aw.property : new MethodCall(bv, aw.method));
((IEStringWidget) droppedWidget).setBindingValue(bv);
Typed p = aw.property != null ? aw.property : aw.method;
if (p.getType() == null) {
break;
}
/*
* if(p.getType().isBoolean()) ((IEStringWidget)droppedWidget).setFieldType(TextFieldType.) else
*/
if (p.getType().isString() || p.getType().isChar()) {
((IEStringWidget) droppedWidget).setFieldType(TextFieldType.TEXT);
} else if (p.getType().isInteger()) {
((IEStringWidget) droppedWidget).setFieldType(TextFieldType.INTEGER);
} else if (p.getType().isFloat()) {
((IEStringWidget) droppedWidget).setFieldType(TextFieldType.FLOAT);
} else if (p.getType().isDouble()) {
((IEStringWidget) droppedWidget).setFieldType(TextFieldType.DOUBLE);
} else if (p.getType().isDate()) {
((IEStringWidget) droppedWidget).setFieldType(TextFieldType.DATE);
}
break;
case TEXTFIELD:
case TEXTAREA:
bv = new BindingValue(((IEEditableTextWidget) droppedWidget).getBindingValueDefinition(), droppedWidget);
bv.setBindingVariable(var);
property = var.getType().getBaseEntity().getProperty(cbd.getVariableName());
bv.addBindingPathElement(property);
bv.addBindingPathElement(aw.property != null ? aw.property : new MethodCall(bv, aw.method));
((IEEditableTextWidget) droppedWidget).setBindingValue(bv);
p = aw.property != null ? aw.property : aw.method;
if (aw.widget == WidgetType.TEXTFIELD) {
if (p.getType().isString() || p.getType().isChar()) {
((IETextFieldWidget) droppedWidget).setFieldType(TextFieldType.TEXT);
} else if (p.getType().isInteger()) {
((IETextFieldWidget) droppedWidget).setFieldType(TextFieldType.INTEGER);
} else if (p.getType().isFloat()) {
((IETextFieldWidget) droppedWidget).setFieldType(TextFieldType.FLOAT);
} else if (p.getType().isDouble()) {
((IETextFieldWidget) droppedWidget).setFieldType(TextFieldType.DOUBLE);
} else if (p.getType().isDate()) {
((IETextFieldWidget) droppedWidget).setFieldType(TextFieldType.DATE);
}
}
break;
case CHECKBOX:
bv = new BindingValue(((IECheckBoxWidget) droppedWidget).getBindingCheckedDefinition(), droppedWidget);
bv.setBindingVariable(var);
property = var.getType().getBaseEntity().getProperty(cbd.getVariableName());
bv.addBindingPathElement(property);
bv.addBindingPathElement(aw.property != null ? aw.property : new MethodCall(bv, aw.method));
((IECheckBoxWidget) droppedWidget).setBindingChecked(bv);
break;
case RADIO:
bv = new BindingValue(((IERadioButtonWidget) droppedWidget).getBindingCheckedDefinition(), droppedWidget);
bv.setBindingVariable(var);
property = var.getType().getBaseEntity().getProperty(cbd.getVariableName());
bv.addBindingPathElement(property);
bv.addBindingPathElement(aw.property != null ? aw.property : new MethodCall(bv, aw.method));
((IERadioButtonWidget) droppedWidget).setBindingChecked(bv);
break;
default:
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unimplemented type for export " + aw.widget);
}
break;
}
}
}
/**
* @return
*/
public String getVariableName() {
return extractNameFromEntity(getFocusedObject());
}
private String extractLabel(String name) {
StringBuilder sb = new StringBuilder();
boolean previousCharsAreUpperCase = false;
while (name.startsWith("_")) {
name = name.substring(1);
}
if (name.startsWith("get")) {
name = name.substring(3);
}
if (name.startsWith("set")) {
name = name.substring(3);
}
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (Character.isUpperCase(c)) {
if (i == 0 || previousCharsAreUpperCase) {
sb.append(c);
} else {
if (i + 1 < name.length() && Character.isLowerCase(name.charAt(i + 1))) {
sb.append(' ').append(Character.toLowerCase(c));
} else {
if (previousCharsAreUpperCase) {
sb.append(c);
} else {
sb.append(' ').append(c);
}
}
}
previousCharsAreUpperCase = true;
} else {
if (i == 0) {
sb.append(Character.toUpperCase(c));
} else {
sb.append(c);
}
previousCharsAreUpperCase = false;
}
}
return sb.toString();
}
private String extractNameFromEntity(DMEntity entity) {
String name = entity.getName();
int i = 0;
while (i + 1 < name.length() && Character.isUpperCase(name.charAt(i + 1))) {
i++;
}
return Character.toLowerCase(name.charAt(i)) + name.substring(i + 1);
}
public ComponentType getComponentType() {
if (componentType == null) {
return ComponentType.OPERATION_COMPONENT;
}
return componentType;
}
public void setComponentType(ComponentType componentType) {
this.componentType = componentType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Vector<DMAccessorWidget> getWidgets() {
return widgets;
}
public void setWidgets(Vector<DMAccessorWidget> widgets) {
this.widgets = widgets;
}
public boolean getCopyDescription() {
return copyDescription;
}
public void setCopyDescription(boolean copyDescription) {
this.copyDescription = copyDescription;
}
}