View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.modules.actions.controllers;
18  
19  // Jetspeed stuff
20  import org.apache.jetspeed.om.registry.PortletEntry;
21  import org.apache.jetspeed.om.profile.IdentityElement;
22  import org.apache.jetspeed.om.profile.Entry;
23  import org.apache.jetspeed.om.profile.psml.PsmlControl;
24  import org.apache.jetspeed.om.profile.MetaInfo;
25  import org.apache.jetspeed.om.profile.Layout;
26  import org.apache.jetspeed.om.profile.Parameter;
27  import org.apache.jetspeed.om.profile.Portlets;
28  import org.apache.jetspeed.om.profile.Reference;
29  import org.apache.jetspeed.om.profile.psml.PsmlParameter;
30  import org.apache.jetspeed.om.profile.psml.PsmlLayout;
31  import org.apache.jetspeed.portal.Portlet;
32  import org.apache.jetspeed.portal.PortletSet;
33  import org.apache.jetspeed.portal.PortletController;
34  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
35  import org.apache.jetspeed.services.logging.JetspeedLogger;
36  import org.apache.jetspeed.services.rundata.JetspeedRunData;
37  import org.apache.jetspeed.services.Registry;
38  import org.apache.jetspeed.services.statemanager.SessionState;
39  import org.apache.jetspeed.services.PsmlManager;
40  
41  // Turbine stuff
42  import org.apache.turbine.modules.ActionLoader;
43  import org.apache.turbine.services.localization.Localization;
44  import org.apache.turbine.util.RunData;
45  
46  // Velocity Stuff
47  import org.apache.velocity.context.Context;
48  
49  // Java stuff
50  import java.util.ArrayList;
51  import java.util.Collections;
52  import java.util.Vector;
53  import java.util.List;
54  import java.util.Enumeration;
55  import java.util.Iterator;
56  import java.util.Map;
57  import java.util.HashMap;
58  import java.util.StringTokenizer;
59  
60  /***
61   * This action builds a context suitable for controllers handling
62   * grid positioned layout using PortletSet.Constraints
63   *
64   * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
65   * @author <a href="mailto:paulsp@apache.org">Paul Spencer</a>
66   * @version $Id: MultiColumnControllerAction.java,v 1.30 2004/02/23 02:49:58 jford Exp $
67   */
68  public class MultiColumnControllerAction extends VelocityControllerAction
69  {
70  
71      private static final String REFERENCES_REMOVED = "references-removed";
72  
73      /***
74       * Static initialization of the logger for this class
75       */    
76      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(MultiColumnControllerAction.class.getName());    
77      
78      /***
79       * Subclasses must override this method to provide default behavior
80       * for the portlet action
81       */
82      protected void buildNormalContext(PortletController controller,
83                                        Context context,
84                                        RunData rundata)
85      {
86          try
87          {
88          // retrieve the number of columns
89          String cols = controller.getConfig().getInitParameter("cols");
90          int colNum = 0;
91          int rowNum = 0;
92          try
93          {
94              colNum = Integer.parseInt(cols);
95          }
96          catch (Exception e)
97          {
98              // not an integer or null, default to standarrd value
99              colNum = 3;
100         }
101         context.put("colNum", String.valueOf(colNum));
102 
103         //retrieve the size for each of the columns
104         String sizes = controller.getConfig().getInitParameter("sizes");
105         context.put("sizes", getCellSizes(sizes));
106 
107         //retrieve the class for each of the columns
108         String columnClasses = controller.getConfig().getInitParameter("col_classes");
109         context.put("col_classes", getCellClasses(columnClasses));
110 
111         PortletSet set = controller.getPortlets();
112         // normalize the constraints and calculate max num of rows needed
113         Enumeration en = set.getPortlets();
114         int row = 0;
115         int col = 0;
116         while (en.hasMoreElements())
117         {
118             Portlet p = (Portlet) en.nextElement();
119 
120             PortletSet.Constraints
121                 constraints = p.getPortletConfig().getConstraints();
122 
123             if ((constraints != null)
124                  && (constraints.getColumn() != null)
125                  && (constraints.getRow() != null))
126             {
127                 col = constraints.getColumn().intValue();
128                 if (col > colNum)
129                 {
130                     constraints.setColumn(new Integer(col % colNum));
131                 }
132 
133                 row = constraints.getRow().intValue();
134                 if (row > rowNum)
135                 {
136                     rowNum = row;
137                 }
138             }
139         }
140         row = (int) Math.ceil(set.size() / colNum);
141         if (row > rowNum)
142         {
143             rowNum = row;
144         }
145 
146         if ( logger.isDebugEnabled() ) {
147             logger.debug("Controller calculated setSize " + set.size() + " row " + row + " colNum: " + colNum +  " rowNum: " + rowNum);
148         }
149         // initialize the result position table and the work list
150         List[] table = new List[colNum];
151         List filler = Collections.nCopies(rowNum + 1, null);
152         for (int i = 0; i < colNum; i++)
153         {
154             table[i] = new ArrayList();
155             table[i].addAll(filler);
156         }
157 
158         List work = new ArrayList();
159 
160         //position the constrained elements and keep a reference to the
161         //others
162         for (int i = 0; i < set.size(); i++)
163         {
164             Portlet p = set.getPortletAt(i);
165 
166             PortletSet.Constraints
167                 constraints = p.getPortletConfig().getConstraints();
168 
169             if ((constraints != null)
170                  && (constraints.getColumn() != null)
171                  && (constraints.getRow() != null)
172                  && (constraints.getColumn().intValue() < colNum))
173             {
174                 row = constraints.getRow().intValue();
175                 col = constraints.getColumn().intValue();
176                 table[col].set(row, p);
177             }
178             else
179             {
180                 work.add(p);
181             }
182         }
183 
184         //insert the unconstrained elements in the table
185         Iterator i = work.iterator();
186         for (row = 0; row < rowNum; row++)
187         {
188             for (col = 0; i.hasNext() && (col < colNum); col++)
189             {
190                 if (table[col].get(row) == null)
191                 {
192                     table[col].set(row, i.next());
193                 }
194             }
195         }
196 
197         // now cleanup any remaining null elements
198         for (int j = 0; j < table.length; j++)
199         {
200             i = table[j].iterator();
201             while (i.hasNext())
202             {
203                 Object obj = i.next();
204                 if (obj == null)
205                 {
206                     i.remove();
207                 }
208             }
209         }
210 
211         if (logger.isDebugEnabled())
212         {
213             dumpColumns(table);
214         }
215 
216         context.put("portlets", table);
217         }
218         catch (Exception e)
219         {
220             logger.error("Exception", e);
221         }
222     }
223 
224     /***
225      * Subclasses must override this method to provide default behavior
226      * for the portlet action
227      */
228     protected void buildCustomizeContext(PortletController controller,
229                                          Context context,
230                                          RunData rundata)
231     {
232         JetspeedRunData jdata = (JetspeedRunData) rundata;
233 
234         // get the customization state for this page
235         SessionState customizationState = jdata.getPageSessionState();
236 
237         super.buildCustomizeContext(controller, context, rundata);
238 
239         List[] columns = null;
240 
241         // retrieve the number of columns
242         String cols = controller.getConfig().getInitParameter("cols");
243         int colNum = 0;
244         try
245         {
246             colNum = Integer.parseInt(cols);
247         }
248         catch (Exception e)
249         {
250             // not an integer or null, default to standarrd value
251             colNum = 3;
252         }
253         context.put("colNum", String.valueOf(colNum));
254 
255         //retrieve the size for each of the columns
256         String sizes = controller.getConfig().getInitParameter("sizes");
257         context.put("sizes", getCellSizes(sizes));
258 
259         //retrieve the class for each of the columns
260         String columnClasses = controller.getConfig().getInitParameter("col_classes");
261         context.put("col_classes", getCellClasses(columnClasses));
262 
263         columns = (List[]) customizationState.getAttribute("customize-columns");
264         PortletSet customizedSet = (PortletSet) jdata.getCustomized();
265         Portlets set = jdata.getCustomizedProfile()
266                             .getDocument()
267                             .getPortletsById(customizedSet.getID());
268 
269         if ( logger.isDebugEnabled() ) {
270             logger.debug("MultiCol: columns " + columns + " set " + set);
271         }
272 
273         if ((columns != null) && (columns.length == colNum))
274         {
275             int eCount = 0;
276             for (int i = 0; i < columns.length; i++)
277             {
278                 eCount += columns[i].size();
279             }
280 
281             if ( logger.isDebugEnabled() ) {
282                 logger.debug("MultiCol: eCount " + eCount + " setCount" + set.getEntryCount() + set.getPortletsCount());
283             }
284             if (eCount != set.getEntryCount() + set.getPortletsCount())
285             {
286                 if ( logger.isDebugEnabled() ) {
287                     logger.debug("MultiCol: rebuilding columns ");
288                 }
289                 columns = buildColumns(set, colNum);
290             }
291 
292         }
293         else
294         {
295             if ( logger.isDebugEnabled() ) {
296                 logger.debug("MultiCol: rebuilding columns ");
297             }
298             columns = buildColumns(set, colNum);
299         }
300 
301         customizationState.setAttribute("customize-columns", columns);
302         context.put("portlets", columns);
303 
304         Map titles = new HashMap();
305         for (int col = 0; col < columns.length; col++)
306         {
307             for (int row = 0; row < columns[col].size(); row++)
308             {
309                 IdentityElement identityElement = (IdentityElement) columns[col].get(row);
310                 MetaInfo metaInfo = identityElement.getMetaInfo();
311                 if ((metaInfo != null) && (metaInfo.getTitle() != null))
312                 {
313                     titles.put(identityElement.getId(), metaInfo.getTitle());
314                     continue;
315                 }
316 
317                 if (identityElement instanceof Entry)
318                 {
319                     Entry entry = (Entry) identityElement;
320                     PortletEntry pentry = (PortletEntry) Registry.getEntry(Registry.PORTLET, entry.getParent());
321                     if ((pentry != null) && (pentry.getTitle() != null))
322                     {
323                         titles.put(entry.getId(), pentry.getTitle());
324                         continue;
325                     }
326 
327                     titles.put(entry.getId(), entry.getParent());
328                     continue;
329                 }
330 
331                 if (identityElement instanceof Reference)
332                 {
333                     titles.put(identityElement.getId(), Localization.getString(rundata, "CUSTOMIZER_REF_DEFAULTTITLE"));
334                     continue;
335                 }
336 
337                 // Let's make sure their is a title
338                 titles.put(identityElement.getId(), Localization.getString(rundata, "CUSTOMIZER_NOTITLESET"));
339             }
340         }
341 
342         context.put("titles", titles);
343         context.put("action", "controllers.MultiColumnControllerAction");
344     }
345 
346     /***
347      * Cancel the current customizations.  If this was the last customization
348      * on the stack, then return the user to the home page.
349      */
350     public void doCancel(RunData data, Context context)
351     {
352         // move one level back in customization
353         ((JetspeedRunData) data).setCustomized(null);
354 
355         // if we are all done customization
356         if (((JetspeedRunData) data).getCustomized() == null)
357         {
358             try
359             {
360                 ActionLoader.getInstance().exec(data, "controls.EndCustomize");
361             }
362             catch (Exception e)
363             {
364                 logger.error("Unable to load action controls.EndCustomize ", e);
365             }
366         }
367     }
368 
369     public void doSave(RunData data, Context context)
370     {
371         // get the customization state for this page
372         SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
373 
374         // update the changes made here to the profile being edited
375         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
376         for (int col = 0; col < columns.length; col++)
377         {
378             for (int row = 0; row < columns[col].size(); row++)
379             {
380                 setPosition((IdentityElement) columns[col].get(row), col, row);
381             }
382         }
383 
384         // move one level back in customization
385         ((JetspeedRunData) data).setCustomized(null);
386 
387         // if we are all done customization
388         if (((JetspeedRunData) data).getCustomized() == null)
389         {
390             // save the edit profile and make it current
391             try
392             {
393                 ((JetspeedRunData) data).getCustomizedProfile().store();
394 
395                 // Because of the way references are stored in memory, we have to completely refresh
396                 // the profile after a references is removed (otherwise it will continue being displayed)
397                 String referencesRemoved = (String) customizationState.getAttribute(REFERENCES_REMOVED);
398                 if (referencesRemoved != null && referencesRemoved.equals("true"))
399                 {
400                     PsmlManager.refresh(((JetspeedRunData) data).getCustomizedProfile());
401                 }                
402             }
403             catch (Exception e)
404             {
405                 logger.error("Unable to save profile ", e);
406             }
407 
408             try
409             {
410                 ActionLoader.getInstance().exec(data, "controls.EndCustomize");
411             }
412             catch (Exception e)
413             {
414                 logger.error("Unable to load action controls.EndCustomize ", e);
415             }
416         }
417     }
418 
419     public void doDelete(RunData data, Context context)
420     {
421         JetspeedRunData jdata = (JetspeedRunData) data;
422 
423         // get the customization state for this page
424         SessionState customizationState = jdata.getPageSessionState();
425 
426         PortletSet customizedSet = (PortletSet) jdata.getCustomized();
427 
428         customizationState.setAttribute(REFERENCES_REMOVED, "false");
429 
430         int col = data.getParameters().getInt("col", -1);
431         int row = data.getParameters().getInt("row", -1);
432         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
433         if (columns == null)
434         {
435             return;
436         }
437 
438         if ((col > -1) && (row > -1))
439         {
440             try
441             {
442                 IdentityElement identityElement = (IdentityElement) columns[col].get(row);
443                 columns[col].remove(row);
444 
445                 Portlets portlets = jdata.getCustomizedProfile()
446                                           .getDocument()
447                                           .getPortletsById(customizedSet.getID());
448 
449                 if (portlets != null)
450                 {
451                     if (identityElement instanceof Entry)
452                     {
453                         for (int i = 0; i < portlets.getEntryCount(); i++)
454                         {
455                             if (portlets.getEntry(i) == identityElement)
456                             {
457                                 portlets.removeEntry(i);
458                             }
459                         }
460                     }
461                     else if (identityElement instanceof Reference)
462                     {
463                         for (int i = 0; i < portlets.getReferenceCount(); i++)
464                         {
465                             if (portlets.getReference(i) == identityElement)
466                             {
467                                 customizationState.setAttribute(REFERENCES_REMOVED, "true");
468                                 portlets.removeReference(i);
469                             }
470                         }
471                     }
472                 }
473             }
474             catch (Exception e)
475             {
476                 // probably got wrong coordinates
477                 logger.error("MultiColumnControllerAction: Probably got wrong coordinates", e);
478             }
479         }
480     }
481 
482     public void doLeft(RunData data, Context context)
483     {
484         // get the customization state for this page
485         SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
486 
487         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
488         int col = data.getParameters().getInt("col", -1);
489         int row = data.getParameters().getInt("row", -1);
490         if (columns == null)
491         {
492             return;
493         }
494 
495         if ((col > 0) && (row > -1))
496         {
497             move(columns, col, row, col - 1, row);
498         }
499     }
500 
501     public void doRight(RunData data, Context context)
502     {
503         // get the customization state for this page
504         SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
505 
506         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
507         int col = data.getParameters().getInt("col", -1);
508         int row = data.getParameters().getInt("row", -1);
509         if (columns == null)
510         {
511             return;
512         }
513 
514         if ((col > -1) && (row > -1) && (col < columns.length - 1))
515         {
516             move(columns, col, row, col + 1, row);
517         }
518     }
519 
520     public void doUp(RunData data, Context context)
521     {
522         // get the customization state for this page
523         SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
524 
525         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
526         int col = data.getParameters().getInt("col", -1);
527         int row = data.getParameters().getInt("row", -1);
528         if (columns == null)
529         {
530             return;
531         }
532 
533         if ((col > -1) && (row > 0))
534         {
535             move(columns, col, row, col, row - 1);
536         }
537     }
538 
539     public void doDown(RunData data, Context context)
540     {
541         // get the customization state for this page
542         SessionState customizationState = ((JetspeedRunData) data).getPageSessionState();
543 
544         List[] columns = (List[]) customizationState.getAttribute("customize-columns");
545         int col = data.getParameters().getInt("col", -1);
546         int row = data.getParameters().getInt("row", -1);
547         if (columns == null)
548         {
549             return;
550         }
551 
552         if ((col > -1) && (row > -1) && (row < columns[col].size() - 1))
553         {
554             move(columns, col, row, col, row + 1);
555         }
556     }
557 
558     public void doControl(RunData data, Context context)
559     {
560         JetspeedRunData jdata = (JetspeedRunData) data;
561 
562         String controlName = data.getParameters().getString("control");
563         String id = data.getParameters().getString("js_peid");
564 
565         try
566         {
567             Entry entry = jdata.getCustomizedProfile().getDocument().getEntryById(id);
568 
569             if (entry != null)
570             {
571                 if (controlName != null && controlName.trim().length() > 0)
572                 {
573                     PsmlControl control = new PsmlControl();
574                     control.setName(controlName);
575                     if (control != null)
576                     {
577                         entry.setControl(control);
578                     }
579                 }
580                 else
581                 {
582                     entry.setControl(null);
583                 }
584             }
585         }
586         catch (Exception e)
587         {
588             logger.error("Exception", e);
589         }
590     }
591 
592     protected static void setPosition(IdentityElement identityElement, int col, int row)
593     {
594         boolean colFound = false;
595         boolean rowFound = false;
596 
597         if (identityElement != null)
598         {
599             Layout layout = identityElement.getLayout();
600 
601             if (layout == null)
602             {
603                 layout = new PsmlLayout();
604                 identityElement.setLayout(layout);
605             }
606 
607             for (int i = 0; i < layout.getParameterCount(); i++)
608             {
609                 Parameter p = layout.getParameter(i);
610 
611                 if (p.getName().equals("column"))
612                 {
613                     p.setValue(String.valueOf(col));
614                     colFound = true;
615                 }
616                 else if (p.getName().equals("row"))
617                 {
618                     p.setValue(String.valueOf(row));
619                     rowFound = true;
620                 }
621             }
622 
623             if (!colFound)
624             {
625                 Parameter p = new PsmlParameter();
626                 p.setName("column");
627                 p.setValue(String.valueOf(col));
628                 layout.addParameter(p);
629             }
630 
631             if (!rowFound)
632             {
633                 Parameter p = new PsmlParameter();
634                 p.setName("row");
635                 p.setValue(String.valueOf(row));
636                 layout.addParameter(p);
637             }
638         }
639     }
640 
641     protected static void move(List[] cols, int oCol, int oRow, int nCol, int nRow)
642     {
643         Object obj = null;
644 
645         if ((oCol < cols.length) && (oRow < cols[oCol].size()))
646         {
647             obj = cols[oCol].get(oRow);
648             if (obj != null)
649             {
650                 cols[oCol].remove(oRow);
651             }
652         }
653 
654         if (obj != null)
655         {
656             if (nCol < cols.length)
657             {
658                 if (nRow < cols[nCol].size())
659                 {
660                     cols[nCol].add(nRow, obj);
661                 }
662                 else
663                 {
664                     cols[nCol].add(obj);
665                 }
666             }
667         }
668     }
669 
670     protected static List[] buildColumns(Portlets set, int colNum)
671     {
672         // normalize the constraints and calculate max num of rows needed
673         Iterator iterator = set.getEntriesIterator();
674         int row = 0;
675         int col = 0;
676         int rowNum = 0;
677         while (iterator.hasNext())
678         {
679             IdentityElement identityElement = (IdentityElement) iterator.next();
680 
681             Layout layout = identityElement.getLayout();
682 
683             if (layout != null)
684             {
685                 for (int p = 0; p < layout.getParameterCount(); p++)
686                 {
687                     Parameter prop = layout.getParameter(p);
688 
689                     try
690                     {
691                         if (prop.getName().equals("row"))
692                         {
693                             row = Integer.parseInt(prop.getValue());
694                             if (row > rowNum)
695                             {
696                                 rowNum = row;
697                             }
698                         }
699                         else if (prop.getName().equals("column"))
700                         {
701                             col = Integer.parseInt(prop.getValue());
702                             if (col > colNum)
703                             {
704                                 prop.setValue(String.valueOf(col % colNum));
705                             }
706                         }
707                     }
708                     catch (Exception e)
709                     {
710                         //ignore any malformed layout properties
711                     }
712                 }
713             }
714         }
715 
716         int sCount = set.getEntryCount() + set.getPortletsCount();
717         row = (sCount / colNum) + 1;
718         if (row > rowNum)
719         {
720             rowNum = row;
721         }
722 
723         if ( logger.isDebugEnabled() ) {
724             logger.debug("Controller customize colNum: " + colNum + " rowNum: " + rowNum);
725         }
726         // initialize the result position table and the work list
727         List[] table = new List[colNum];
728         List filler = Collections.nCopies(rowNum + 1, null);
729         for (int i = 0; i < colNum; i++)
730         {
731             table[i] = new ArrayList();
732             table[i].addAll(filler);
733         }
734 
735         List work = new ArrayList();
736 
737         //position the constrained elements and keep a reference to the
738         //others
739         for (int i = 0; i < set.getEntryCount(); i++)
740         {
741             addElement(set.getEntry(i), table, work, colNum);
742         }
743 
744         // Add references
745         for (int i = 0; i < set.getReferenceCount(); i++)
746         {
747             addElement(set.getReference(i), table, work, colNum);
748         }
749 
750         //insert the unconstrained elements in the table
751         Iterator i = work.iterator();
752         for (row = 0; row < rowNum; row++)
753         {
754             for (col = 0; i.hasNext() && (col < colNum); col++)
755             {
756                 if (table[col].get(row) == null)
757                 {
758                     if ( logger.isDebugEnabled() ) {
759                         logger.debug("Set portlet at col " + col + " row " + row);
760                     }
761                     table[col].set(row, i.next());
762                 }
763             }
764         }
765 
766         // now cleanup any remaining null elements
767         for (int j = 0; j < table.length; j++)
768         {
769             if ( logger.isDebugEnabled() ) {
770                 logger.debug("Column " + j);
771             }
772             i = table[j].iterator();
773             while (i.hasNext())
774             {
775                 Object obj = i.next();
776                 if ( logger.isDebugEnabled() ) {
777                     logger.debug("Element " + obj);
778                 }
779                 if (obj == null)
780                 {
781                     i.remove();
782                 }
783 
784             }
785         }
786 
787         return table;
788     }
789 
790     /*** Parses the size config info and returns a list of
791      *  size values for the current set
792      *
793      *  @param sizeList java.lang.String a comma separated string a values
794      *  @return a List of values
795      */
796     protected static List getCellSizes(String sizeList)
797     {
798         List list = new Vector();
799 
800         if (sizeList != null)
801         {
802             StringTokenizer st = new StringTokenizer(sizeList, ",");
803             while (st.hasMoreTokens())
804             {
805                 list.add(st.nextToken());
806             }
807         }
808 
809         return list;
810     }
811 
812     protected static List getCellClasses(String classlist)
813     {
814         List list = new Vector();
815 
816         if (classlist != null)
817         {
818             StringTokenizer st = new StringTokenizer(classlist, ",");
819             while (st.hasMoreTokens())
820             {
821                 list.add(st.nextToken());
822             }
823         }
824 
825         return list;
826     }
827 
828     /***
829      * Add an element to the "table" or "work" objects.  If the element is
830      * unconstrained, and the position is within the number of columns, then
831      * the element is added to "table".  Othewise the element is added to "work"
832      *
833      * @param element to add
834      * @param table of positioned elements
835      * @param work list of un-positioned elements
836      * @param columnCount Number of colum
837      */
838     protected static void addElement(IdentityElement element, List[] table, List work, int columnCount)
839     {
840             Layout layout = element.getLayout();
841             int row = -1;
842             int col = -1;
843 
844             if (layout != null)
845             {
846                 try
847                 {
848                     for (int p = 0; p < layout.getParameterCount(); p++)
849                     {
850                         Parameter prop = layout.getParameter(p);
851 
852                         if (prop.getName().equals("row"))
853                         {
854                             row = Integer.parseInt(prop.getValue());
855                         }
856                         else if (prop.getName().equals("column"))
857                         {
858                             col = Integer.parseInt(prop.getValue());
859                         }
860                     }
861                 }
862                 catch (Exception e)
863                 {
864                     //ignore any malformed layout properties
865                 }
866             }
867 
868             if ( logger.isDebugEnabled() ) {
869                 logger.debug("Constraints col " + col + " row " + row);
870             }
871             if ((row >= 0) && (col >= 0) && (col < columnCount))
872             {
873                 table[col].set(row, element);
874             }
875             else
876             {
877                 if (layout != null)
878                 {
879                     // We got here because the column, as defined in the layout,
880                     // is greater then the numner of columns. This usually
881                     // happens when the number of column has been decreased.
882                     // Delete the offending layout.  It may be recreated with
883                     // the correct values.
884                     element.setLayout(null);
885                     layout = null;
886                 }
887                 work.add(element);
888             }
889 
890     }
891 
892     protected void dumpColumns(List[] cols)
893     {
894         for (int i = 0; i < cols.length; i++)
895         {
896             logger.debug("Column " + i);
897             for (int j = 0; j < cols[i].size(); j++)
898             {
899                 logger.debug("Row " + j + " object: " + cols[i].get(j));
900             }
901         }
902     }
903 }