001    /*
002     * Copyright 2004 Chris Nelson
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
007     * Unless required by applicable law or agreed to in writing,
008     * software distributed under the License is distributed on an "AS IS" BASIS,
009     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010     * See the License for the specific language governing permissions and limitations under the License.
011     */
012    package org.trails.component;
013    
014    import ognl.Ognl;
015    import ognl.OgnlException;
016    import org.apache.commons.logging.Log;
017    import org.apache.commons.logging.LogFactory;
018    import org.apache.tapestry.IAsset;
019    import org.apache.tapestry.IRequestCycle;
020    import org.apache.tapestry.annotations.*;
021    import org.apache.tapestry.contrib.palette.SortMode;
022    import org.apache.tapestry.form.IPropertySelectionModel;
023    import org.apache.tapestry.link.ILinkRenderer;
024    import org.trails.descriptor.CollectionDescriptor;
025    import org.trails.descriptor.DescriptorService;
026    import org.trails.descriptor.IClassDescriptor;
027    import org.trails.page.PageResolver;
028    import org.trails.persistence.PersistenceService;
029    import org.trails.util.Utils;
030    
031    import java.util.ArrayList;
032    import java.util.Collection;
033    import java.util.Collections;
034    import java.util.List;
035    
036    
037    /**
038     * This component produces a editor for a ManyToOne or ManyToMany collection. It allows a user to edit a collection
039     * property
040     *
041     * @author Chris Nelson
042     */
043    @ComponentClass(allowBody = false)
044    public abstract class EditCollection extends TrailsComponent
045    {
046    
047            protected static final Log LOG = LogFactory.getLog(EditCollection.class);
048    
049            @Parameter(required = false)
050            public abstract List getInstances();
051            
052            @Parameter(required = true)
053            public abstract Collection getCollection();
054    
055            /**
056             * The object which owns the collection being edited
057             */
058            @Parameter(required = false, defaultValue = "page.model")
059            public abstract Object getModel();
060    
061            /**
062             * Ognl expression to invoke on the model to create a new child instance
063             */
064            @Parameter(required = false)
065            public abstract String getCreateExpression();
066    
067            /**
068             * @return The CollectionDescriptor for the collection being edited
069             */
070            @Parameter(required = true)
071            public abstract CollectionDescriptor getCollectionDescriptor();
072    
073            public abstract Object getCurrentObject();
074    
075            public abstract void setCurrentObject(Object CurrentObject);
076    
077            @Parameter(defaultValue = "page.descriptorService")
078            public abstract DescriptorService getDescriptorService();
079    
080            @Parameter(defaultValue = "page.persistenceService")
081            public abstract PersistenceService getPersistenceService();
082    
083            @Parameter(defaultValue = "not(collectionDescriptor.childRelationship)")
084            public abstract boolean getAddFromExisting();
085    
086            @Parameter(defaultValue = "true")
087            public abstract boolean isAllowCreate();
088    
089            @Parameter(defaultValue = "collectionDescriptor.allowRemove")
090            public abstract boolean isAllowRemove();
091    
092            public abstract int getIndex();
093    
094            public abstract void setIndex(int index);
095    
096            @Asset("classpath:move_up.gif")
097            public abstract IAsset getUpImage();
098    
099            @Asset("classpath:move_down.gif")
100            public abstract IAsset getDownImage();
101    
102            private List<Boolean> selected = new ArrayList<Boolean>();
103    
104            /**
105             * org.apache.tapestry.contrib.link.ButtonLinkRenderer
106             *
107             * @return
108             */
109            @InjectObject(value = "service:trails.core.AddNewLinkRenderer")
110            public abstract ILinkRenderer getRenderer();
111    
112            /**
113             * (non-Javadoc)
114             *
115             * @see org.apache.tapestry.AbstractComponent#prepareForRender(org.apache.tapestry.IRequestCycle)
116             */
117            protected void prepareForRender(IRequestCycle cycle)
118            {
119                    super.prepareForRender(cycle);
120                    selected = buildSelectedList();
121            }
122    
123            public List<Boolean> buildSelectedList()
124            {
125                    ArrayList<Boolean> selected = new ArrayList<Boolean>();
126                    if (getCollection() != null)
127                    {
128                            selected = new ArrayList<Boolean>(getCollection().size());
129                            for (Object o : getCollection())
130                            {
131                                    selected.add(false);
132                            }
133                    }
134                    return selected;
135            }
136    
137            @InjectObject("service:trails.core.PageResolver")
138            public abstract PageResolver getPageResolver();
139    
140            public void remove()
141            {
142                    int i = 0;
143                    // TODO CN - This code stinks (I wrote it).  Isn't there a better way??
144                    ArrayList deleting = new ArrayList();
145                    for (Object element : getCollection())
146                    {
147                            if (getSelected().get(i))
148                            {
149                                    deleting.add(element);
150                            }
151                            i++;
152                    }
153    
154                    for (Object element : deleting)
155                    {
156                            Utils.executeOgnlExpression(getCollectionDescriptor().getRemoveExpression(), element, getModel());
157                    }
158            }
159    
160            public List getSelectedList()
161            {
162                    ArrayList selectedList = new ArrayList();
163                    selectedList.addAll(getCollection());
164                    return selectedList;
165            }
166    
167            public void setSelectedList(List selected)
168            {
169                    if (selected != null)
170                    {
171                            getCollection().clear();
172                            getCollection().addAll(selected);
173                    }
174            }
175    
176            /**
177             * @return Returns the toBeDeleted.
178             */
179            public List<Boolean> getSelected()
180            {
181                    return selected;
182            }
183    
184            protected void setSelected(List<Boolean> selected)
185            {
186                    this.selected = selected;
187            }
188    
189            /**
190             * @return
191             */
192            public String getSortMode()
193            {
194                    return isList() ? SortMode.USER : SortMode.LABEL;
195            }
196    
197            public boolean isList()
198            {
199                    return getCollection() instanceof List;
200            }
201    
202            /**
203             * @return
204             */
205            public IPropertySelectionModel getSelectionModel()
206            {
207                    IClassDescriptor elementDescriptor =
208                                    getDescriptorService().getClassDescriptor(getCollectionDescriptor().getElementType());
209                    // don't allow use to select from all here
210                    if (getInstances() != null)
211                    {
212                            return new IdentifierSelectionModel(getInstances(), elementDescriptor.getIdentifierDescriptor().getName());
213                    } else if (getCollectionDescriptor().isChildRelationship())
214                    {
215                            return new IdentifierSelectionModel(getSelectedList(),
216                                            elementDescriptor.getIdentifierDescriptor().getName());
217                    } else
218                    {
219                            // but do here
220                            return new IdentifierSelectionModel(getPersistenceService().getAllInstances(getCollectionDescriptor().getElementType()),
221                                            elementDescriptor.getIdentifierDescriptor().getName());
222                    }
223            }
224    
225            public void moveUp()
226            {
227                    List list = (List) getCollection();
228                    for (int i = 1; i < getSelected().size(); i++)
229                    {
230                            if (getSelected().get(i))
231                            {
232                                    if (getCollectionDescriptor().getSwapExpression() == null)
233                                    {
234                                            Collections.swap(list, i, i - 1);
235                                    } else
236                                    {
237                                            try
238                                            {
239                                                    Ognl.getValue(getCollectionDescriptor().getSwapExpression() + "(" + i + "," + (i - 1) + ")",
240                                                                    getModel());
241                                            } catch (OgnlException e)
242                                            {
243                                                    LOG.error(e.getMessage());
244                                            }
245                                    }
246                            }
247                    }
248            }
249    
250            public void moveDown()
251            {
252                    List list = (List) getCollection();
253                    for (int i = 0; i < getSelected().size() - 1; i++)
254                    {
255                            if (getCollectionDescriptor().getSwapExpression() == null)
256                            {
257                                    Collections.swap(list, i, i + 1);
258                            } else
259                            {
260                                    try
261                                    {
262                                            Ognl.getValue(getCollectionDescriptor().getSwapExpression() + "(" + i + "," + (i + 1) + ")",
263                                                            getModel());
264                                    } catch (OgnlException e)
265                                    {
266                                            LOG.error(e.getMessage());
267                                    }
268                            }
269                    }
270            }
271    }