/*
* (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.ie.operator;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.bindings.AbstractBinding;
import org.openflexo.foundation.bindings.BindingDefinition.BindingDefinitionType;
import org.openflexo.foundation.bindings.BindingValue;
import org.openflexo.foundation.bindings.BindingValue.BindingPathElement;
import org.openflexo.foundation.bindings.WidgetBindingDefinition;
import org.openflexo.foundation.dm.DMEntity;
import org.openflexo.foundation.dm.DMMethod;
import org.openflexo.foundation.dm.DMProperty;
import org.openflexo.foundation.dm.DMPropertyImplementationType;
import org.openflexo.foundation.dm.DMType;
import org.openflexo.foundation.dm.DMTypeOwner;
import org.openflexo.foundation.ie.IEObject;
import org.openflexo.foundation.ie.IEWOComponent;
import org.openflexo.foundation.ie.dm.ExcellButtonStateChange;
import org.openflexo.foundation.ie.dm.IEDataModification;
import org.openflexo.foundation.ie.dm.RefreshButtonStateChange;
import org.openflexo.foundation.ie.util.ListType;
import org.openflexo.foundation.ie.widget.IEBlocWidget;
import org.openflexo.foundation.ie.widget.IEControlWidget;
import org.openflexo.foundation.ie.widget.IEEditableFieldWidget;
import org.openflexo.foundation.ie.widget.IEHyperlinkWidget;
import org.openflexo.foundation.ie.widget.IESequence;
import org.openflexo.foundation.param.ParameterDefinition;
import org.openflexo.foundation.param.TextFieldParameter;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.foundation.validation.FixProposal;
import org.openflexo.foundation.validation.ParameteredFixProposal;
import org.openflexo.foundation.validation.ValidationError;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.node.ActionNode;
import org.openflexo.foundation.wkf.node.OperationNode;
import org.openflexo.foundation.wkf.node.SubProcessNode;
import org.openflexo.foundation.wkf.node.WorkflowPathToOperationNode;
import org.openflexo.foundation.xml.FlexoComponentBuilder;
import org.openflexo.logging.FlexoLogger;
public class RepetitionOperator extends IEOperator implements DMTypeOwner {
protected static final Logger logger = FlexoLogger.getLogger(RepetitionOperator.class.getPackage().getName());
// private RepetitionBindingModel _bindingModel;
private BindingValue _bindingItem; // Could be considered as a BindingValue because defined as GET_SET
private AbstractBinding _listAccessor;
private boolean _fetchObjects = false;
private boolean _refreshButton = true;
private boolean _excelButton = false;
private boolean _hasBatch = true;
private int _defaultBatchValue = 20;
private ListType _listType = ListType.FETCH;
private DMEntity entity;
private String entityName;
private DMMethod permanentFilter;
private String permanentFilterMethodSignature;
private DMType _contentType;
private WidgetBindingDefinition _bindingListDefinition = null;
private WidgetBindingDefinition _bindingItemDefinition = null;
public RepetitionOperator(FlexoComponentBuilder builder) {
this(builder.woComponent, null, builder.getProject());
initializeDeserialization(builder);
}
public RepetitionOperator(IEWOComponent wo, IESequence sequence, FlexoProject project) {
super(wo, sequence, project);
}
@Override
public String getFullyQualifiedName() {
return "Repetition." + getName();
}
@Override
public String getClassNameKey() {
return "repetition";
}
@Override
public String getDefaultInspectorName() {
return "Repetition.inspector";
}
@Override
public String getInspectorName() {
return getDefaultInspectorName();
}
public DMType getContentType() {
if (_contentType == null) {
if (_bindingItem != null && _bindingItem.getAccessedType() != null) {
_contentType = _bindingItem.getAccessedType().clone();
_contentType.setOwner(this);
} else {
_contentType = DMType.makeResolvedDMType(Object.class, getProject());
_contentType.setOwner(this);
}
}
return _contentType;
}
public void setContentType(DMType contentType) {
DMType oldContentType = _contentType;
_contentType = contentType;
if (_contentType != null) {
_contentType.setOwner(this);
}
_bindingListDefinition = null;
_bindingItemDefinition = null;
setChanged();
notifyObservers(new IEDataModification("contentType", oldContentType, contentType));
}
public DMType getItemType() {
DMType type = getContentType();
if (_listType == ListType.FETCH && !_fetchObjects) {
type = DMType.makeResolvedDMType(getProject().getDataModel().getDMEntity("com.webobjects.foundation", "NSDictionary"));
}
return type.clone();
}
public WidgetBindingDefinition getBindingItemDefinition() {
if (_bindingItemDefinition == null) {
/*DMType type = getContentType();
if (_listType==ListType.FETCH && !_fetchObjects)
type = DMType.makeResolvedDMType(getProject().getDataModel().getDMEntity("com.webobjects.foundation", "NSDictionary"));*/
_bindingItemDefinition = new WidgetBindingDefinition("bindingItem", getContentType(), this, BindingDefinitionType.GET_SET, true);
if (_bindingItem != null) {
_bindingItem.setBindingDefinition(_bindingItemDefinition);
}
}
return _bindingItemDefinition;
}
public BindingValue getBindingItem() {
return _bindingItem;
}
public void setBindingItem(BindingValue bindingItem) {
if (_bindingItem != null) {
BindingPathElement element = _bindingItem.getBindingPathLastElement();
if (element instanceof DMProperty) {
((DMProperty) element).setIsStaticallyDefinedInTemplate(false);
} else if (element instanceof DMMethod) {
((DMMethod) element).setIsStaticallyDefinedInTemplate(false);
} else {
if (logger.isLoggable(Level.WARNING) && element != null) {
logger.warning("Unknown Binding path element: " + element.getClass().getName() + " Please fix me!");
}
}
}
_bindingItem = bindingItem;
if (_bindingItem != null) {
_bindingItem.setOwner(this);
_bindingItem.setBindingDefinition(getBindingItemDefinition());
BindingPathElement element = _bindingItem.getBindingPathLastElement();
if (element instanceof DMProperty) {
((DMProperty) element).setIsStaticallyDefinedInTemplate(true);
((DMProperty) element).setIsBindable(false);
} else if (element instanceof DMMethod) {
((DMMethod) element).setIsStaticallyDefinedInTemplate(true);
} else {
if (logger.isLoggable(Level.WARNING) && element != null) {
logger.warning("Unknown Binding path element: " + element.getClass().getName() + " Please fix me!");
}
}
}
setChanged();
notifyObservers(new IEDataModification("itemVariable", null, bindingItem));
}
public BindingValue getItemVariable() {
return getBindingItem();
}
public DMProperty getItemProperty() {
if (getItemVariable() != null) {
BindingValue bv = getItemVariable();
return (DMProperty) bv.getBindingPath().get(bv.getBindingPath().size() - 1);
}
return null;
}
public void setItemVariable(BindingValue bindingItem) {
setBindingItem(bindingItem);
}
public AbstractBinding getListAccessor() {
return _listAccessor;
}
public void setListAccessor(AbstractBinding value) {
_listAccessor = value;
if (_listAccessor != null) {
_listAccessor.setOwner(this);
_listAccessor.setBindingDefinition(getBindingListDefinition());
}
setChanged();
notifyObservers(new IEDataModification("listAccessor", null, value));
}
public WidgetBindingDefinition getBindingListDefinition() {
if (_bindingListDefinition == null) {
_bindingListDefinition = new WidgetBindingDefinition("bindingList", DMType.makeListDMType(getContentType(), getProject()),
this, BindingDefinitionType.GET, true);
if (_listAccessor != null) {
_listAccessor.setBindingDefinition(_bindingListDefinition);
}
}
return _bindingListDefinition;
}
public boolean getFetchObjects() {
return _fetchObjects;
}
public void setFetchObjects(boolean objects) {
_fetchObjects = objects;
_bindingItemDefinition = null;
setChanged();
notifyObservers(new IEDataModification("fetchObjects", null, new Boolean(_fetchObjects)));
}
public boolean excelButton() {
return _excelButton;
}
public boolean refreshButton() {
return _refreshButton;
}
public void setExcelButton(boolean excelButton) {
_excelButton = excelButton;
setChanged();
notifyObservers(new IEDataModification("excelButton", null, new Boolean(_excelButton)));
notifyParentBloc(new ExcellButtonStateChange(excelButton));
}
public void setRefreshButton(boolean refreshButton) {
_refreshButton = refreshButton;
setChanged();
notifyObservers(new IEDataModification("refreshButton", null, new Boolean(_refreshButton)));
notifyParentBloc(new RefreshButtonStateChange(refreshButton));
}
public boolean getHasBatch() {
return _hasBatch;
}
public void setHasBatch(boolean objects) {
_hasBatch = objects;
setChanged();
notifyObservers(new IEDataModification("hasBatch", null, new Boolean(_hasBatch)));
}
public int getDefaultBatchValue() {
return _defaultBatchValue;
}
public void setDefaultBatchValue(int object) {
_defaultBatchValue = object;
setChanged();
notifyObservers(new IEDataModification("defaultBatchValue", null, new Integer(_defaultBatchValue)));
}
private void notifyParentBloc(IEDataModification modif) {
IEBlocWidget bloc = findBlocInParent();
if (bloc != null) {
bloc.notifyListActionButtonStateChange(modif);
}
}
public DMEntity getEntity() {
if (getItemVariable() != null) {
return getItemVariable().getBindingPath().lastElement().getType().getBaseEntity();
}
if (entity == null && entityName != null) {
entity = getProject().getDataModel().getEntityNamed(entityName);
if (entity == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Entity named: " + entityName + " could not be found");
}
}
}
return entity;
}
@Deprecated
public void setEntity(DMEntity ent) {
DMEntity old = this.entity;
this.entity = ent;
if (old != null && old != ent) {
removeBindingVariable("fetchObjectOfList" + getFlexoID());
}
if (ent != null) {
if (old != ent) {
entityName = ent.getFullyQualifiedName();
}
createsBindingVariable("fetchObjectOfList" + getFlexoID(), DMType.makeResolvedDMType(ent),
DMPropertyImplementationType.PUBLIC_ACCESSORS_PRIVATE_FIELD, false);
} else {
entityName = null;
}
if (old != ent) {
setChanged();
notifyObservers(new IEDataModification("entity", old, ent));
}
}
public String getEntityName() {
return entityName;
}
public void setEntityName(String ent_name) {
this.entityName = ent_name;
this.entity = null;
}
@Override
public ListType getListType() {
return _listType;
}
@Override
public void setListType(ListType type) {
_listType = type;
_bindingItemDefinition = null;
_bindingListDefinition = null;
setChanged();
notifyObservers(new IEDataModification("listType", null, _listType));
}
public boolean useListAccessor() {
return _listType == ListType.ACCESSOR;
}
public DMMethod getPermanentFilter() {
if (permanentFilter == null && permanentFilterMethodSignature != null) {
permanentFilter = getWOComponent().getComponentDMEntity().getMethod(permanentFilterMethodSignature);
if (permanentFilter == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find method with signature " + permanentFilterMethodSignature
+ " in component entity named: " + getWOComponent().getName());
}
permanentFilterMethodSignature = null;
}
}
return permanentFilter;
}
public void setPermanentFilter(DMMethod f) {
DMMethod old = this.permanentFilter;
this.permanentFilter = f;
if (f == null) {
permanentFilterMethodSignature = null;
}
setChanged();
notifyObservers(new IEDataModification("permanentFilter", old, f));
}
public Vector<DMMethod> getAvailableQualifiers() {
DMEntity qual = getProject().getDataModel().getEntityNamed("com.webobjects.eocontrol.EOQualifier");
if (qual == null) {
return new Vector<DMMethod>();
}
Vector<DMMethod> ret = new Vector<DMMethod>();
Enumeration en = getComponentDMEntity().getMethods().keys();
while (en.hasMoreElements()) {
DMMethod method = getComponentDMEntity().getMethods().get(en.nextElement());
if (method.getReturnType() != null && method.getReturnType().getBaseEntity() != null
&& method.getReturnType().getBaseEntity().equals(qual) && method.getParameters().size() == 0) {
ret.add(method);
}
}
return ret;
}
public String getPermanentFilterMethodSignature() {
if (getPermanentFilter() != null) {
return this.permanentFilter.getSignature();
} else {
return null;
}
}
public void setPermanentFilterMethodSignature(String signature) {
permanentFilterMethodSignature = signature;
permanentFilter = null;
}
/**
* Returns all the widgets that are meant to be used for filtering this list. This method should be used with great care since it parses
* the all component to retrieve all those widgets
*
* @return all the widgets that are meant to be used for filtering this list
*/
public Vector<IEControlWidget> getFilterWidgets() {
Vector<IEControlWidget> result = getWOComponent().getFilterWidgetsForRepetition(this);
Collections.sort(result, new Comparator<IEControlWidget>() {
@Override
public int compare(IEControlWidget o1, IEControlWidget o2) {
return o1.compareTo(o2);
}
});
return result;
}
/**
* Try to infer the business data listed:<br>
* 1. If the list is bound, return the Flexo process if it is used as a business data in a process, otherwise return null 2. Retrieve
* all operations linked to the component, if all operations are inside the a sub process activity targeting the same process, return
* this process.<br>
* 3. Retrieve all action in this list, if all actions retrieved targets the same process, return this one.<br>
* 3. Otherwise return null
*
* @return the inferred flexo process
*/
public FlexoProcess getInferredListProcess() {
if (getContentType() == null) {
return null;
}
if (!"java.lang.Object".equals(getContentType().getStringRepresentation())) {
DMEntity entity = getContentType().getBaseEntity();
if (entity != null && getProject().getAllLocalFlexoProcesses() != null) {
Enumeration<FlexoProcess> en = getProject().getAllLocalFlexoProcesses().elements();
while (en.hasMoreElements()) {
FlexoProcess process = en.nextElement();
if (entity.equals(process.getBusinessDataType())) {
return process;
}
}
}
return null;
}
Set<FlexoProcess> foundProcessFromActions = new HashSet<FlexoProcess>();
Set<FlexoProcess> foundProcessFromSubProcessActivity = new HashSet<FlexoProcess>();
for (OperationNode operationNode : getWOComponent().getComponentDefinition().getAllOperationNodesLinkedToThisComponent()) {
if (foundProcessFromActions.size() <= 1) {
for (ActionNode actionNode : operationNode.getAllActionNodes()) {
IEHyperlinkWidget widget = actionNode.getAssociatedButtonWidget();
if (widget != null && widget.isInRepetition() && widget.repetition().getFlexoID() == getFlexoID()) {
for (WorkflowPathToOperationNode workflowPath : actionNode.getNextOperationsForAction()) {
foundProcessFromActions.addAll(workflowPath.getCreatedProcesses());
foundProcessFromActions.addAll(workflowPath.getDeletedProcesses());
if (workflowPath.getOperationNode() != null) {
foundProcessFromActions.add(workflowPath.getOperationNode().getProcess());
}
if (foundProcessFromActions.size() > 1) {
break;
}
}
if (foundProcessFromActions.size() > 1) {
break;
}
}
}
}
if (operationNode.getAbstractActivityNode().isSubProcessNode()) {
foundProcessFromSubProcessActivity.add(((SubProcessNode) operationNode.getAbstractActivityNode()).getSubProcess());
}
}
if (foundProcessFromSubProcessActivity.size() == 1) {
return foundProcessFromSubProcessActivity.iterator().next();
}
if (foundProcessFromActions.size() == 1) {
return foundProcessFromActions.iterator().next();
}
return null;
}
/* public class RepetitionBindingModel extends BindingModel
{
public static final String COMPONENT_BINDING_VARIABLE_NAME = "component";
public static final String ITEM_BINDING_VARIABLE_NAME = "itemOfRepetition";
private BindingVariable _componentVariable;
private BindingVariable _itemVariable;
public RepetitionBindingModel()
{
super();
_componentVariable = new BindingVariable(RepetitionOperator.this, getProject().getDataModel(), FlexoLocalization
.localizedForKey("access_to_the_current_component"));
_componentVariable.setVariableName(COMPONENT_BINDING_VARIABLE_NAME);
_componentVariable.setType(DMType.makeResolvedDMType(getComponentDMEntity()));
createOrUpdateItemVariable();
}
protected void createOrUpdateItemVariable() {
if (getBindingItem()!=null && getBindingItem().getBindingPathLastElement() instanceof DMProperty){
_itemVariable = new BindingVariable(RepetitionOperator.this, getProject().getDataModel(), FlexoLocalization
.localizedForKey("access_to_the_item_of_the_repetition"));
_itemVariable.setVariableName(((DMProperty)getBindingItem().getBindingPathLastElement()).getName());
_itemVariable.setType(getContentType().clone());
} else {
_itemVariable = null;
}
}
@Override
public int getBindingVariablesCount()
{
return _itemVariable!=null?2:1;
}
@Override
public BindingVariable getBindingVariableAt(int index)
{
if (index==0)
return getItemBindingVariable();
else
return getComponentBindingVariable();
}
public BindingVariable getItemBindingVariable() {
return _itemVariable;
}
public BindingVariable getComponentBindingVariable()
{
return _componentVariable;
}
@Override
public boolean allowsNewBindingVariableCreation()
{
return false;
}
}
*/
public static class ListMustHaveAName extends ValidationRule<ListMustHaveAName, RepetitionOperator> {
public ListMustHaveAName() {
super(RepetitionOperator.class, "list_must_have_a_name");
}
@Override
public ValidationIssue<ListMustHaveAName, RepetitionOperator> applyValidation(RepetitionOperator object) {
ValidationError<ListMustHaveAName, RepetitionOperator> error = null;
if (object.getName() == null || object.getName().trim().length() == 0) {
error = new ValidationError<ListMustHaveAName, RepetitionOperator>(this, object, "list_must_have_a_name",
new EnterNewListName());
}
return error;
}
public static class EnterNewListName extends ParameteredFixProposal<ListMustHaveAName, RepetitionOperator> {
public EnterNewListName() {
super("enter_new_list_name", parameters());
}
private static ParameterDefinition[] parameters() {
return new ParameterDefinition[] { new TextFieldParameter("name", "list_name", null) };
}
@Override
protected void fixAction() {
String s = (String) getValueForParameter("name");
if (s != null && s.trim().length() != 0) {
getObject().setName(s);
}
}
}
}
public static class RawRowRepetitionCanNotContainEditableField extends
ValidationRule<RawRowRepetitionCanNotContainEditableField, RepetitionOperator> {
/**
* @author gpolet
*
*/
public class SetListTypeToFetch extends FixProposal<RawRowRepetitionCanNotContainEditableField, RepetitionOperator> {
/**
* @param aMessage
*/
public SetListTypeToFetch() {
super("set_list_type_to_fetch_objects");
}
/**
* Overrides fixAction
*
* @see org.openflexo.foundation.validation.FixProposal#fixAction()
*/
@Override
protected void fixAction() {
getObject().setFetchObjects(true);
}
}
/**
* @param objectType
* @param ruleName
*/
public RawRowRepetitionCanNotContainEditableField() {
super(RepetitionOperator.class, "raw_row_repetition_cannot_contain_editable_field");
}
/**
* Overrides applyValidation
*
* @see org.openflexo.foundation.validation.ValidationRule#applyValidation(org.openflexo.foundation.validation.Validable)
*/
@Override
public ValidationIssue<RawRowRepetitionCanNotContainEditableField, RepetitionOperator> applyValidation(RepetitionOperator rep) {
if (rep.getFetchObjects()) {
return null;
}
Vector v = rep.getOperatedSequence().getAllEmbeddedIEObjects();
Enumeration<IEObject> en = v.elements();
while (en.hasMoreElements()) {
IEObject element = en.nextElement();
if (element instanceof IEEditableFieldWidget) {
ValidationError<RawRowRepetitionCanNotContainEditableField, RepetitionOperator> err = new ValidationError<RawRowRepetitionCanNotContainEditableField, RepetitionOperator>(
this, rep, "raw_row_repetition_cannot_contain_editable_field");
err.addToFixProposals(new SetListTypeToFetch());
return err;
}
}
return null;
}
}
}