001    package org.tynamo.components;
002    
003    import org.apache.tapestry5.*;
004    import org.apache.tapestry5.annotations.InjectComponent;
005    import org.apache.tapestry5.annotations.Parameter;
006    import org.apache.tapestry5.annotations.Property;
007    import org.apache.tapestry5.beaneditor.BeanModel;
008    import org.apache.tapestry5.corelib.components.Form;
009    import org.apache.tapestry5.corelib.components.Zone;
010    import org.apache.tapestry5.ioc.Messages;
011    import org.apache.tapestry5.ioc.annotations.Inject;
012    import org.apache.tapestry5.ioc.services.PropertyAccess;
013    import org.apache.tapestry5.ioc.services.TypeCoercer;
014    import org.apache.tapestry5.services.BeanModelSource;
015    import org.apache.tapestry5.services.ValueEncoderSource;
016    import org.tynamo.builder.BuilderDirector;
017    import org.tynamo.descriptor.CollectionDescriptor;
018    import org.tynamo.services.DescriptorService;
019    import org.tynamo.services.PersistenceService;
020    import org.tynamo.util.DisplayNameUtils;
021    import org.tynamo.util.Utils;
022    
023    import java.util.Collection;
024    import java.util.List;
025    
026    public class Composition
027    {
028    
029            @Inject
030            private DescriptorService descriptorService;
031    
032            @Inject
033            private PersistenceService persitenceService;
034    
035            @Inject
036            private PropertyAccess propertyAccess;
037    
038            @Inject
039            private BeanModelSource beanModelSource;
040    
041            @Inject
042            private Messages messages;
043    
044            @Inject
045            private BuilderDirector builderDirector;
046    
047            @Inject
048            private ComponentResources resources;
049    
050            @Inject
051            private ValueEncoderSource valueEncoderSource;
052    
053            /**
054             * The id used to generate a page-unique client-side identifier for the component. If a component renders multiple
055             * times, a suffix will be appended to the to id to ensure uniqueness. The uniqued value may be accessed via the
056             * {@link #getClientId() clientId property}.
057             */
058            @Parameter(value = "prop:resources.id", defaultPrefix = BindingConstants.LITERAL)
059            @Property(write = false)
060            private String clientId;
061    
062            /**
063             * A Block to render when the source is empty. The default is simply the text "There is no data to display".
064             * This parameter is used to customize that message.
065             */
066            @Parameter(value = "block:empty", defaultPrefix = BindingConstants.LITERAL)
067            @Property(write = false)
068            private Block empty;
069    
070            @Parameter(required = false)
071            private List instances;
072    
073            @Parameter(required = true)
074            @Property(write = false)
075            private Collection collection;
076    
077            /**
078             * The object which owns the collection being edited
079             */
080            @Parameter(required = true)
081            private Object owner;
082    
083            /**
084             * Ognl expression to invoke on the model to create a new child instance
085             */
086            @Parameter(required = false)
087            private String createExpression;
088    
089            /**
090             * @return The CollectionDescriptor for the collection being edited
091             */
092            @Parameter(required = true)
093            @Property(write = false)
094            private CollectionDescriptor collectionDescriptor;
095    
096            @Property
097            private Object collectionIterator;
098    
099            @Property
100            private Object formBean;
101    
102            @Parameter(value = "true")
103            private boolean allowCreate;
104    
105            @InjectComponent
106            private Zone compositionZone;
107    
108            @InjectComponent
109            @Property(write = false)
110            private Form form;
111    
112            @Inject
113            private TypeCoercer typeCoercer;
114    
115            public boolean isAllowCreate()
116            {
117                    return propertyAccess.get(owner, descriptorService.getClassDescriptor(owner.getClass())
118                                    .getIdentifierDescriptor().getName()) != null;
119            }
120    
121            @Parameter(value = "prop:collectionDescriptor.allowRemove")
122            private boolean allowRemove;
123    
124            @Property
125            private int index;
126    
127            @Parameter(value = "asset:move_up.gif")
128            @Property(write = false)
129            private Asset upImage;
130    
131            @Parameter(value = "asset:move_down.gif")
132            @Property(write = false)
133            private Asset downImage;
134    
135            /**
136             * The image to use for the delete icon
137             */
138            @Parameter(value = "asset:delete.png")
139            @Property(write = false)
140            private Asset deleteIcon;
141    
142            @Property(write = false)
143            private BeanModel beanModel;
144    
145            void onPrepareFromForm()
146            {
147                    resources.triggerEvent(EventConstants.PREPARE, null, null);
148    
149                    if (beanModel == null)
150                    {
151                            beanModel = beanModelSource.createEditModel(collectionDescriptor.getElementType(), messages);
152                    }
153            }
154    
155            void setupRender()
156            {
157                    beanModel = beanModelSource.createEditModel(collectionDescriptor.getElementType(), messages);
158                    formBean = builderDirector.createNewInstance(collectionDescriptor.getElementType());
159            }
160    
161            public Object onSuccess()
162            {
163                    Utils.executeOgnlExpression(collectionDescriptor.getAddExpression(), formBean, owner);
164                    persitenceService.save(owner);
165                    return compositionZone.getBody();
166            }
167    
168            public Object onActionFromDeleteChild(String elementid)
169            {
170                    ValueEncoder valueEncoder = valueEncoderSource.getValueEncoder(collectionDescriptor.getElementType());
171                    Object element = valueEncoder.toValue(elementid);
172                    Utils.executeOgnlExpression(collectionDescriptor.getRemoveExpression(), element, owner);
173    
174                    persitenceService.remove(element);
175                    persitenceService.save(owner);
176                    return compositionZone.getBody();
177            }
178    
179    
180    /*      public boolean isList()
181            {
182                    return collection instanceof List;
183            }
184    
185            public void moveUp()
186            {
187                    List list = (List) collection;
188                    for (int i = 1; i < getSelected().size(); i++)
189                    {
190                            if (getSelected().get(i))
191                            {
192                                    if (collectionDescriptor.getSwapExpression() == null)
193                                    {
194                                            Collections.swap(list, i, i - 1);
195                                    } else
196                                    {
197                                            try
198                                            {
199                                                    Ognl.getValue(collectionDescriptor.getSwapExpression() + "(" + i + "," + (i - 1) + ")", owner);
200                                            } catch (OgnlException e)
201                                            {
202                                                    LOGGER.error(e.getMessage());
203                                            }
204                                    }
205                            }
206                    }
207            }
208    
209            public void moveDown()
210            {
211                    List list = (List) collection;
212                    for (int i = 0; i < getSelected().size() - 1; i++)
213                    {
214                            if (collectionDescriptor.getSwapExpression() == null)
215                            {
216                                    Collections.swap(list, i, i + 1);
217                            } else
218                            {
219                                    try
220                                    {
221                                            Ognl.getValue(collectionDescriptor.getSwapExpression() + "(" + i + "," + (i + 1) + ")",
222                                                            owner);
223                                    } catch (OgnlException e)
224                                    {
225                                            LOG.error(e.getMessage());
226                                    }
227                            }
228                    }
229            }*/
230    
231            public Object[] getShowPageContext()
232            {
233                    return new Object[]{collectionIterator.getClass(), collectionIterator};
234            }
235    
236            public Object[] getDeleteContext()
237            {
238                    return new Object[]{collectionIterator};
239            }
240    
241            public String getLegendMessage()
242            {
243                    return messages.format("org.tynamo.i18n.add",
244                                    DisplayNameUtils.getDisplayName(collectionDescriptor.getElementType(), messages));
245            }
246    
247    }