001    // ===========================================================================
002    // Copyright (c) 1996 Mort Bay Consulting Pty. Ltd. All rights reserved.
003    // $Id: Composite.java,v 1.1 2004/03/23 13:59:49 laurent Exp $
004    // ---------------------------------------------------------------------------
005    
006    package org.objectweb.jac.aspects.gui.web.html;
007    
008    // Laurent Martelli <laurent@aopsys.com> - 21 mar. 2004:
009    // Added add(int position, Object element) method
010    
011    import java.io.IOException;
012    import java.io.OutputStream;
013    import java.io.OutputStreamWriter;
014    import java.io.Writer;
015    import java.util.ArrayList;
016    import org.mortbay.util.Code;
017    import org.mortbay.html.Page;
018    
019    /* -------------------------------------------------------------------- */
020    /** HTML Composite Element.
021     * <p>This class is can be used a either an abstract or concrete
022     * holder of other HTML elements.
023     * Used directly, it allow multiple HTML Elements to be added which
024     * are produced sequentially.
025     * Derived used of Composite may wrap each contain Element in
026     * special purpose HTML tags (e.g. list).
027     *
028     * <p>Notes<br>
029     * Elements are added to the Composite either as HTML Elements or as
030     * Strings.  Other objects added to the Composite are converted to Strings
031     * @see Element
032     * @version $Id: Composite.java,v 1.1 2004/03/23 13:59:49 laurent Exp $
033     * @author Greg Wilkins
034    */
035    public class Composite extends Element
036    {
037        /* ----------------------------------------------------------------- */
038        /** The vector of elements in this Composite.
039         */
040        protected ArrayList elements= new ArrayList(8);
041    
042        /* ----------------------------------------------------------------- */
043        protected Composite nest=null;
044    
045        /* ----------------------------------------------------------------- */
046        /** Default constructor.
047         */
048        public Composite()
049        {}
050        
051        /* ----------------------------------------------------------------- */
052        /** Default constructor.
053         */
054        public Composite(String attributes)
055        {
056            super(attributes);
057        }
058    
059        /* ----------------------------------------------------------------- */
060        /** Add an Object to the Composite by converting it to a Element or.
061         * String
062         * @param o The Object to add. If it is a String or Element, it is
063         * added directly, otherwise toString() is called.
064         * @return This Composite (for chained commands)
065         */
066        public Composite add(Object o)
067        {
068            return add(elements.size(),o);
069        }
070    
071    
072        /* ----------------------------------------------------------------- */
073        /** Add an Object to the Composite by converting it to a Element or.
074         * String
075         * @param o The Object to add. If it is a String or Element, it is
076         * added directly, otherwise toString() is called.
077         * @param position the position at which to insert the object
078         * @return This Composite (for chained commands)
079         */
080        public Composite add(int position, Object o)
081        {
082            if (nest!=null)
083                nest.add(position,o);
084            else
085            {
086                if (o!=null)
087                {
088                    if (o instanceof Element)
089                    {
090                        Code.assertTrue(!(o instanceof Page),
091                                        "Can't insert Page in Composite");
092                        elements.add(position,o);
093                    }
094                    else if (o instanceof String)
095                        elements.add(position,o);
096                    else 
097                        elements.add(position,o.toString());
098                }
099            }
100            return this;
101        }
102        
103        /* ----------------------------------------------------------------- */
104        /** Nest a Composite within a Composite.
105         * The passed Composite is added to this Composite. Adds to
106         * this composite are actually added to the nested Composite.
107         * Calls to nest are passed the nested Composite
108         * @return The Composite to unest on to return to the original
109         * state.
110         */
111        public Composite nest(Composite c)
112        {
113            if (nest!=null)
114                return nest.nest(c);
115            else
116            {
117                add(c);
118                nest=c;
119            }
120            return this;
121        }
122    
123        /* ----------------------------------------------------------------- */
124        /** Explicit set of the Nested component.
125         * No add is performed. setNest() obeys any current nesting and
126         * sets the nesting of the nested component.
127         */
128        public Composite setNest(Composite c)
129        {
130            if (nest!=null)
131                nest.setNest(c);
132            else
133                nest=c;
134            return this;
135        }
136        
137        /* ----------------------------------------------------------------- */
138        /** Recursively unnest the composites.
139         */
140        public Composite unnest()
141        {
142            if (nest!=null)
143                nest.unnest();
144            nest = null;
145            return this;
146        }
147    
148    
149        /* ----------------------------------------------------------------- */
150        /** The number of Elements in this Composite.
151         * @return The number of elements in this Composite
152         */
153        public int size()
154        {
155            return elements.size();
156        }
157        
158        /* ----------------------------------------------------------------- */
159        /** Write the composite.
160         * The default implementation writes the elements sequentially. May
161         * be overridden for more specialized behaviour.
162         * @param out Writer to write the element to.
163         */
164        public void write(Writer out)
165             throws IOException
166        {
167            for (int i=0; i <elements.size() ; i++)
168            {
169                Object element = elements.get(i);
170              
171                if (element instanceof Element)
172                    ((Element)element).write(out);
173                else if (element==null)
174                    out.write("null");
175                else 
176                    out.write(element.toString());
177            }
178        }
179        
180        /* ----------------------------------------------------------------- */
181        /** Contents of the composite.
182         */
183        public String contents()
184        {
185            StringBuffer buf = new StringBuffer();
186            synchronized(buf)
187            {
188                for (int i=0; i <elements.size() ; i++)
189                {
190                    Object element = elements.get(i);
191                    if (element==null)
192                        buf.append("null");
193                    else 
194                        buf.append(element.toString());
195                }
196            }
197            return buf.toString();
198        }
199    
200        /* ------------------------------------------------------------ */
201        /** Empty the contents of this Composite .
202         */
203        public Composite reset()
204        {
205            elements.clear();
206            return unnest();
207        }
208        
209        /* ----------------------------------------------------------------- */
210        /* Flush is a package method used by Page.flush() to locate the
211         * most nested composite, write out and empty its contents.
212         */
213        void flush(Writer out)
214             throws IOException
215        {
216            if (nest!=null)
217                nest.flush(out);
218            else
219            {
220                write(out);
221                elements.clear();
222            }
223        }
224        
225        /* ----------------------------------------------------------------- */
226        /* Flush is a package method used by Page.flush() to locate the
227         * most nested composite, write out and empty its contents.
228         */
229        void flush(OutputStream out)
230             throws IOException
231        {
232            flush(new OutputStreamWriter(out));
233        }
234        
235        /* ----------------------------------------------------------------- */
236        /* Flush is a package method used by Page.flush() to locate the
237         * most nested composite, write out and empty its contents.
238         */
239        void flush(OutputStream out, String encoding)
240             throws IOException
241        {
242            flush(new OutputStreamWriter(out,encoding));
243        }
244    
245        /* ------------------------------------------------------------ */
246        /** Replace an object within the composite.
247         */
248        public boolean replace(Object oldObj, Object newObj)
249        {  
250            if (nest != null)
251            {
252                return nest.replace(oldObj, newObj);
253            }
254            else
255            {
256                int sz = elements.size();
257                for (int i = 0; i < sz; i++)
258                {
259                    if (elements.get(i) == oldObj)
260                    {
261                        elements.set(i,newObj);
262                        return true;
263                    }     
264                }
265            }
266            
267            return false;
268        }           
269    
270    }