001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.workplace.list;
029
030import org.opencms.main.CmsIllegalStateException;
031import org.opencms.util.CmsStringUtil;
032import org.opencms.workplace.tools.CmsIdentifiableObjectContainer;
033
034import java.util.Iterator;
035import java.util.List;
036import java.util.Set;
037import java.util.TreeSet;
038
039/**
040 * This is class contains all the information for defining a whole html list.<p>
041 *
042 * @since 6.0.0
043 */
044public class CmsListMetadata {
045
046    /**
047     * Interface used for formatting list data in text form.<p>
048     */
049    public interface I_CsvItemFormatter {
050
051        /**
052         * Generates the CSV header.
053         *
054         * @return the CSV header line
055         **/
056        String csvHeader();
057
058        /**
059         * Generates a CSV line.
060         *
061         * @param item the list item to format
062         * @return the formatted text line for the list item
063         * */
064        String csvItem(CmsListItem item);
065    }
066
067    /** the html id for the input element of the search bar. */
068    public static final String SEARCH_BAR_INPUT_ID = "listSearchFilter";
069
070    /** Container for column definitions. */
071    private CmsIdentifiableObjectContainer<CmsListColumnDefinition> m_columns = new CmsIdentifiableObjectContainer<CmsListColumnDefinition>(
072        true,
073        false);
074
075    /** The CSV item formatter. **/
076    private I_CsvItemFormatter m_csvItemFormatter;
077
078    /** Container for of independent actions. */
079    private CmsIdentifiableObjectContainer<I_CmsListAction> m_indepActions = new CmsIdentifiableObjectContainer<I_CmsListAction>(
080        true,
081        false);
082
083    /** Container for item detail definitions. */
084    private CmsIdentifiableObjectContainer<CmsListItemDetails> m_itemDetails = new CmsIdentifiableObjectContainer<CmsListItemDetails>(
085        true,
086        false);
087
088    /** The id of the list. */
089    private String m_listId;
090
091    /** Container for multi actions. */
092    private CmsIdentifiableObjectContainer<CmsListMultiAction> m_multiActions = new CmsIdentifiableObjectContainer<CmsListMultiAction>(
093        true,
094        false);
095
096    /** Search action. */
097    private CmsListSearchAction m_searchAction;
098
099    /** if the data is self managed (sorted and filtered by {@link A_CmsListDialog#getListItems()} method). */
100    private boolean m_selfManaged;
101
102    /** if this metadata object should not be cached.<p>. */
103    private boolean m_volatile;
104
105    /** The related workplace dialog object. */
106    private transient A_CmsListDialog m_wp;
107
108    /**
109     * Default Constructor.<p>
110     *
111     * @param listId the id of the list
112     */
113    public CmsListMetadata(String listId) {
114
115        m_listId = listId;
116    }
117
118    /**
119     * Adds a new column definition at the end.<p>
120     *
121     * By default a column is printable if it is the first column in the list,
122     * or if it is sorteable.<p>
123     *
124     * If you want to override this behaviour, use the
125     * {@link CmsListColumnDefinition#setPrintable(boolean)}
126     * method after calling this one.
127     *
128     * @param listColumn the column definition
129     *
130     * @see CmsIdentifiableObjectContainer
131     */
132    public void addColumn(CmsListColumnDefinition listColumn) {
133
134        addColumn(listColumn, m_columns.elementList().size());
135    }
136
137    /**
138     * Adds a new column definition at the given position.<p>
139     *
140     * By default a column is printable if it is the first column in the list,
141     * or if it is sorteable.<p>
142     *
143     * If you want to override this behaviour, use the
144     * {@link CmsListColumnDefinition#setPrintable(boolean)}
145     * method after calling this one.
146     *
147     * @param listColumn the column definition
148     * @param position the position
149     *
150     * @see CmsIdentifiableObjectContainer
151     */
152    public void addColumn(CmsListColumnDefinition listColumn, int position) {
153
154        setListIdForColumn(listColumn);
155        if (m_columns.elementList().isEmpty()) {
156            listColumn.setPrintable(true);
157        } else {
158            listColumn.setPrintable(listColumn.isSorteable());
159        }
160        if ((listColumn.getName() == null) && listColumn.isPrintable()) {
161            listColumn.setPrintable(false);
162        }
163        m_columns.addIdentifiableObject(listColumn.getId(), listColumn, position);
164    }
165
166    /**
167     * Adds a list item independent action.<p>
168     *
169     * @param action the action
170     */
171    public void addIndependentAction(I_CmsListAction action) {
172
173        action.setListId(getListId());
174        m_indepActions.addIdentifiableObject(action.getId(), action);
175    }
176
177    /**
178     * Adds a new item detail definition at the end.<p>
179     *
180     * @param itemDetail the item detail definition
181     *
182     * @see CmsIdentifiableObjectContainer
183     */
184    public void addItemDetails(CmsListItemDetails itemDetail) {
185
186        itemDetail.setListId(getListId());
187        m_itemDetails.addIdentifiableObject(itemDetail.getId(), itemDetail);
188    }
189
190    /**
191     * Adds a new item detail definition at the given position.<p>
192     *
193     * @param itemDetail the item detail definition
194     * @param position the position
195     *
196     * @see CmsIdentifiableObjectContainer
197     */
198    public void addItemDetails(CmsListItemDetails itemDetail, int position) {
199
200        itemDetail.setListId(getListId());
201        m_itemDetails.addIdentifiableObject(itemDetail.getId(), itemDetail, position);
202    }
203
204    /**
205     * Adds an action applicable to more than one list item at once.<p>
206     *
207     * It will be executed with a list of <code>{@link CmsListItem}</code>s.<p>
208     *
209     * @param multiAction the action
210     */
211    public void addMultiAction(CmsListMultiAction multiAction) {
212
213        multiAction.setListId(getListId());
214        m_multiActions.addIdentifiableObject(multiAction.getId(), multiAction);
215    }
216
217    /**
218     * Generates the csv output for an empty table.<p>
219     *
220     * @return csv output
221     */
222    public String csvEmptyList() {
223
224        StringBuffer html = new StringBuffer(512);
225        html.append("\n");
226        return html.toString();
227    }
228
229    /**
230     * Returns the csv output for the header of the list.<p>
231     *
232     * @return csv output
233     */
234    public String csvHeader() {
235
236        if (m_csvItemFormatter != null) {
237            return m_csvItemFormatter.csvHeader();
238        } else {
239            StringBuffer csv = new StringBuffer(1024);
240            Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
241            while (itCols.hasNext()) {
242                CmsListColumnDefinition col = itCols.next();
243                if (!col.isVisible()) {
244                    continue;
245                }
246                csv.append(col.csvHeader());
247                csv.append("\t");
248            }
249            csv.append("\n\n");
250            return csv.toString();
251        }
252    }
253
254    /**
255     * Returns the csv output for a list item.<p>
256     *
257     * @param item the list item to render
258     *
259     * @return csv output
260     */
261    public String csvItem(CmsListItem item) {
262
263        if (m_csvItemFormatter != null) {
264            return m_csvItemFormatter.csvItem(item);
265        } else {
266            StringBuffer csv = new StringBuffer(1024);
267            Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
268            while (itCols.hasNext()) {
269                CmsListColumnDefinition col = itCols.next();
270                if (!col.isVisible()) {
271                    continue;
272                }
273                csv.append(col.csvCell(item));
274                csv.append("\t");
275            }
276            csv.append("\n");
277            return csv.toString();
278        }
279    }
280
281    /**
282     * Returns a column definition object for a given column id.<p>
283     *
284     * @param columnId the column id
285     *
286     * @return the column definition, or <code>null</code> if not present
287     */
288    public CmsListColumnDefinition getColumnDefinition(String columnId) {
289
290        return m_columns.getObject(columnId);
291    }
292
293    /**
294     * Returns all columns definitions.<p>
295     *
296     * @return a list of <code>{@link CmsListColumnDefinition}</code>s.
297     */
298    public List<CmsListColumnDefinition> getColumnDefinitions() {
299
300        return m_columns.elementList();
301    }
302
303    /**
304     * Returns an independent action object for a given id.<p>
305     *
306     * @param actionId the id
307     *
308     * @return the independent action, or <code>null</code> if not present
309     */
310    public I_CmsListAction getIndependentAction(String actionId) {
311
312        return m_indepActions.getObject(actionId);
313    }
314
315    /**
316     * Returns the list of independent actions.<p>
317     *
318     * @return a list of <code>{@link I_CmsListAction}</code>s
319     */
320    public List<I_CmsListAction> getIndependentActions() {
321
322        return m_indepActions.elementList();
323    }
324
325    /**
326     * Returns the item details definition object for a given id.<p>
327     *
328     * @param itemDetailId the id
329     *
330     * @return the item details definition, or <code>null</code> if not present
331     */
332    public CmsListItemDetails getItemDetailDefinition(String itemDetailId) {
333
334        return m_itemDetails.getObject(itemDetailId);
335    }
336
337    /**
338     * Returns all detail definitions.<p>
339     *
340     * @return a list of <code>{@link CmsListItemDetails}</code>.
341     */
342    public List<CmsListItemDetails> getItemDetailDefinitions() {
343
344        return m_itemDetails.elementList();
345    }
346
347    /**
348     * Returns the id of the list.<p>
349     *
350     * @return the id of list
351     */
352    public String getListId() {
353
354        return m_listId;
355    }
356
357    /**
358     * Returns a multi action object for a given id.<p>
359     *
360     * @param actionId the id
361     *
362     * @return the multi action, or <code>null</code> if not present
363     */
364    public CmsListMultiAction getMultiAction(String actionId) {
365
366        return m_multiActions.getObject(actionId);
367    }
368
369    /**
370     * Returns the list of multi actions.<p>
371     *
372     * @return a list of <code>{@link CmsListMultiAction}</code>s
373     */
374    public List<CmsListMultiAction> getMultiActions() {
375
376        return m_multiActions.elementList();
377    }
378
379    /**
380     * Returns the search action.<p>
381     *
382     * @return the search action
383     */
384    public CmsListSearchAction getSearchAction() {
385
386        return m_searchAction;
387    }
388
389    /**
390     * Returns the total number of displayed columns.<p>
391     *
392     * @return the total number of displayed columns
393     */
394    public int getWidth() {
395
396        return m_columns.elementList().size() + (hasCheckMultiActions() ? 1 : 0);
397    }
398
399    /**
400     * Returns the related workplace dialog.<p>
401     *
402     * @return the related workplace dialog
403     */
404    public A_CmsListDialog getWp() {
405
406        return m_wp;
407    }
408
409    /**
410     * Returns <code>true</code> if the list definition contains an action.<p>
411     *
412     * @return <code>true</code> if the list definition contains an action
413     */
414    public boolean hasActions() {
415
416        return !m_indepActions.elementList().isEmpty();
417    }
418
419    /**
420     * Returns <code>true</code> if at least 'check' multiaction has been set.<p>
421     *
422     * @return <code>true</code> if at least 'check' multiaction has been set
423     */
424    public boolean hasCheckMultiActions() {
425
426        Iterator<CmsListMultiAction> it = m_multiActions.elementList().iterator();
427        while (it.hasNext()) {
428            CmsListMultiAction action = it.next();
429            if (!(action instanceof CmsListRadioMultiAction)) {
430                return true;
431            }
432        }
433        return false;
434    }
435
436    /**
437     * Returns <code>true</code> if the list definition contains a multi action.<p>
438     *
439     * @return <code>true</code> if the list definition contains a multi action
440     */
441    public boolean hasMultiActions() {
442
443        return !m_multiActions.elementList().isEmpty();
444    }
445
446    /**
447     * Returns <code>true</code> if any column definition contains a single action.<p>
448     *
449     * @return <code>true</code> if any column definition contains a single action
450     */
451    public boolean hasSingleActions() {
452
453        Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
454        while (itCols.hasNext()) {
455            CmsListColumnDefinition col = itCols.next();
456            if (!col.getDefaultActions().isEmpty() || !col.getDirectActions().isEmpty()) {
457                return true;
458            }
459        }
460        return false;
461    }
462
463    /**
464     * Returns the html code for the action bar.<p>
465     *
466     * @return html code
467     */
468    public String htmlActionBar() {
469
470        StringBuffer html = new StringBuffer(1024);
471        html.append("<td class='misc'>\n");
472        html.append("\t<div>\n");
473        Iterator<CmsListItemDetails> itDetails = m_itemDetails.elementList().iterator();
474        while (itDetails.hasNext()) {
475            I_CmsListAction detailAction = itDetails.next().getAction();
476            html.append("\t\t");
477            html.append(detailAction.buttonHtml());
478            if (itDetails.hasNext()) {
479                html.append("&nbsp;");
480            }
481            html.append("\n");
482        }
483        Iterator<I_CmsListAction> itActions = m_indepActions.elementList().iterator();
484        while (itActions.hasNext()) {
485            I_CmsListAction indepAction = itActions.next();
486            html.append("\t\t");
487            html.append("&nbsp;");
488            html.append(indepAction.buttonHtml());
489            html.append("\n");
490        }
491        html.append("\t</div>\n");
492        html.append("</td>\n");
493        return html.toString();
494    }
495
496    /**
497     * Generates the hml code for an empty table.<p>
498     *
499     * @return html code
500     */
501    public String htmlEmptyTable() {
502
503        StringBuffer html = new StringBuffer(512);
504        html.append("<tr class='oddrowbg'>\n");
505        html.append("\t<td align='center' colspan='");
506        html.append(getWidth());
507        html.append("'>\n");
508        html.append(Messages.get().getBundle(getWp().getLocale()).key(Messages.GUI_LIST_EMPTY_0));
509        html.append("\t</td>\n");
510        html.append("</tr>\n");
511        return html.toString();
512    }
513
514    /**
515     * Returns the html code for the header of the list.<p>
516     *
517     * @param list the list to generate the code for
518     *
519     * @return html code
520     */
521    public String htmlHeader(CmsHtmlList list) {
522
523        StringBuffer html = new StringBuffer(1024);
524        html.append("<tr>\n");
525        Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
526        while (itCols.hasNext()) {
527            CmsListColumnDefinition col = itCols.next();
528            if (!col.isVisible() && !list.isPrintable()) {
529                continue;
530            }
531            if (!col.isPrintable() && list.isPrintable()) {
532                continue;
533            }
534            html.append(col.htmlHeader(list));
535        }
536        if (!list.isPrintable() && hasCheckMultiActions()) {
537            html.append("\t<th width='0' class='select'>\n");
538            html.append(
539                "\t\t<input type='checkbox' class='checkbox' name='listSelectAll' value='true' onClick=\"listSelect('");
540            html.append(list.getId());
541            html.append("')\">\n");
542            html.append("\t</th>\n");
543        }
544        html.append("</tr>\n");
545        return html.toString();
546    }
547
548    /**
549     * Returns the html code for a list item.<p>
550     *
551     * @param item the list item to render
552     * @param odd if the position is odd or even
553     * @param isPrintable if the list is to be printed
554     *
555     * @return html code
556     */
557    public String htmlItem(CmsListItem item, boolean odd, boolean isPrintable) {
558
559        StringBuffer html = new StringBuffer(1024);
560        html.append("<tr ");
561        if (!isPrintable) {
562            html.append("class='");
563            html.append(odd ? "oddrowbg" : (getWp().useNewStyle() ? "evenrowbg" : "evenrowbgnew"));
564            html.append("'");
565        }
566        html.append(">\n");
567        Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
568        int width = 0;
569        while (itCols.hasNext()) {
570            CmsListColumnDefinition col = itCols.next();
571            if (!col.isVisible() && !isPrintable) {
572                continue;
573            }
574            if (!col.isPrintable() && isPrintable) {
575                continue;
576            }
577            width++;
578            StringBuffer style = new StringBuffer(64);
579            html.append("<td");
580            CmsListColumnAlignEnum align = col.getAlign();
581            if ((align != CmsListColumnAlignEnum.ALIGN_LEFT) && CmsStringUtil.isNotEmpty(align.toString())) {
582                style.append("text-align: ");
583                style.append(col.getAlign());
584                style.append("; ");
585            }
586            if (col.isTextWrapping()) {
587                style.append("white-space: normal;");
588            }
589            if (isPrintable) {
590                style.append("border-top: 1px solid black;");
591            }
592            if (style.length() > 0) {
593                html.append(" style='");
594                html.append(style);
595                html.append("'");
596            }
597            html.append(">\n");
598            html.append(col.htmlCell(item, isPrintable));
599            html.append("</td>\n");
600        }
601        if (!isPrintable && hasCheckMultiActions()) {
602            width++;
603            html.append("\t<td class='select' style='text-align: center'>\n");
604            html.append("\t\t<input type='checkbox' class='checkbox' name='listMultiAction' value='");
605            html.append(item.getId());
606            html.append("'>\n");
607            html.append("\t</td>\n");
608        }
609        html.append("</tr>\n");
610
611        Iterator<CmsListItemDetails> itDet = m_itemDetails.elementList().iterator();
612        while (itDet.hasNext()) {
613            CmsListItemDetails lid = itDet.next();
614            if (!lid.isVisible() && !isPrintable) {
615                continue;
616            }
617            if (!lid.isPrintable() && isPrintable) {
618                continue;
619            }
620            if ((item.get(lid.getId()) != null)
621                && CmsStringUtil.isNotEmptyOrWhitespaceOnly(item.get(lid.getId()).toString())) {
622                int padCols = 0;
623                itCols = m_columns.elementList().iterator();
624                while (itCols.hasNext()) {
625                    CmsListColumnDefinition col = itCols.next();
626                    if (col.getId().equals(lid.getAtColumn())) {
627                        break;
628                    }
629                    if (!col.isVisible() && !isPrintable) {
630                        continue;
631                    }
632                    if (!col.isPrintable() && isPrintable) {
633                        continue;
634                    }
635                    padCols++;
636                }
637                int spanCols = width - padCols;
638
639                html.append("<tr ");
640                if (!isPrintable) {
641                    html.append("class='");
642                    html.append(odd ? "oddrowbg" : (getWp().useNewStyle() ? "evenrowbg" : "evenrowbgnew"));
643                    html.append("'");
644                }
645                html.append(">\n");
646                if (padCols > 0) {
647                    html.append("<td colspan='");
648                    html.append(padCols);
649                    html.append("'>&nbsp;</td>\n");
650                }
651                html.append("<td colspan='");
652                html.append(spanCols);
653                html.append("' style='padding-left: 20px; white-space:normal;'>\n");
654                html.append(lid.htmlCell(item, isPrintable));
655                html.append("\n</td>\n");
656                html.append("\n");
657                html.append("</tr>\n");
658            }
659        }
660        return html.toString();
661    }
662
663    /**
664     * Returns the html code for the multi action bar.<p>
665     *
666     * @return html code
667     */
668    public String htmlMultiActionBar() {
669
670        StringBuffer html = new StringBuffer(1024);
671        html.append("<td class='misc'>\n");
672        html.append("\t<div>\n");
673        Iterator<CmsListMultiAction> itActions = m_multiActions.elementList().iterator();
674        while (itActions.hasNext()) {
675            CmsListMultiAction multiAction = itActions.next();
676            html.append("\t\t");
677            html.append(multiAction.buttonHtml());
678            if (itActions.hasNext()) {
679                html.append("&nbsp;&nbsp;");
680            }
681            html.append("\n");
682        }
683        html.append("\t</div>\n");
684        html.append("</td>\n");
685        return html.toString();
686    }
687
688    /**
689     * Generates the html code for the search bar.<p>
690     *
691     * @return html code
692     */
693    public String htmlSearchBar() {
694
695        if (!isSearchable()) {
696            return "";
697        }
698        StringBuffer html = new StringBuffer(1024);
699        html.append("<td class='main'>\n");
700        html.append("\t<div>\n");
701        html.append(
702            "\t\t<input type='text' name='listSearchFilter' id='"
703                + SEARCH_BAR_INPUT_ID
704                + "' value='' size='20' maxlength='245' style='vertical-align: bottom;'>\n");
705        html.append(m_searchAction.buttonHtml());
706        I_CmsListAction showAllAction = m_searchAction.getShowAllAction();
707        if (showAllAction != null) {
708            html.append("&nbsp;&nbsp;");
709            html.append(showAllAction.buttonHtml());
710        }
711        html.append("\t</div>\n");
712        html.append("</td>\n");
713        return html.toString();
714    }
715
716    /**
717     * Returns <code>true</code> if the list is searchable.<p>
718     *
719     * @return  <code>true</code> if the list is searchable
720     */
721    public boolean isSearchable() {
722
723        return m_searchAction != null;
724    }
725
726    /**
727     * Returns the self Managed flag.<p>
728     *
729     * @return the self Managed flag
730     */
731    public boolean isSelfManaged() {
732
733        return m_selfManaged;
734    }
735
736    /**
737     * Returns <code>true</code> if any column is sorteable.<p>
738     *
739     * @return <code>true</code> if any column is sorteable
740     */
741    public boolean isSorteable() {
742
743        Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
744        while (itCols.hasNext()) {
745            CmsListColumnDefinition col = itCols.next();
746            if (col.isSorteable()) {
747                return true;
748            }
749        }
750        return false;
751    }
752
753    /**
754     * Returns <code>true</code> if this metadata object should not be cached.<p>
755     *
756     * @return <code>true</code> if this metadata object should not be cached.<p>
757     */
758    public boolean isVolatile() {
759
760        return m_volatile;
761    }
762
763    /**
764     * Sets the CSV item formatter to use.<p>
765     *
766     * @param formatter the CSV item formatter
767     */
768    public void setCsvItemFormatter(I_CsvItemFormatter formatter) {
769
770        m_csvItemFormatter = formatter;
771    }
772
773    /**
774     * Sets the search action.<p>
775     *
776     * @param searchAction the search action to set
777     */
778    public void setSearchAction(CmsListSearchAction searchAction) {
779
780        m_searchAction = searchAction;
781        if (m_searchAction != null) {
782            m_searchAction.setListId(getListId());
783        }
784    }
785
786    /**
787     * Sets the self Managed flag.<p>
788     *
789     * @param selfManaged the self Managed flag to set
790     */
791    public void setSelfManaged(boolean selfManaged) {
792
793        m_selfManaged = selfManaged;
794    }
795
796    /**
797     * Sets the volatile flag.<p>
798     *
799     * @param volatileFlag the volatile flag to set
800     */
801    public void setVolatile(boolean volatileFlag) {
802
803        m_volatile = volatileFlag;
804    }
805
806    /**
807     * Sets the related workplace dialog.<p>
808     *
809     * @param wp the related workplace dialog to set
810     */
811    public void setWp(A_CmsListDialog wp) {
812
813        m_wp = wp;
814        Iterator<CmsListColumnDefinition> itCols = getColumnDefinitions().iterator();
815        while (itCols.hasNext()) {
816            CmsListColumnDefinition column = itCols.next();
817            column.setWp(wp);
818        }
819        Iterator<CmsListItemDetails> itDets = getItemDetailDefinitions().iterator();
820        while (itDets.hasNext()) {
821            CmsListItemDetails detail = itDets.next();
822            detail.setWp(wp);
823        }
824        Iterator<CmsListMultiAction> itMultiActs = getMultiActions().iterator();
825        while (itMultiActs.hasNext()) {
826            CmsListMultiAction action = itMultiActs.next();
827            action.setWp(wp);
828        }
829        Iterator<I_CmsListAction> itIndActs = getIndependentActions().iterator();
830        while (itIndActs.hasNext()) {
831            I_CmsListAction action = itIndActs.next();
832            action.setWp(wp);
833        }
834        if (m_searchAction != null) {
835            m_searchAction.setWp(wp);
836        }
837    }
838
839    /**
840     * Toggles the given item detail state from visible to hidden or
841     * from hidden to visible.<p>
842     *
843     * @param itemDetailId the item detail id
844     */
845    public void toogleDetailState(String itemDetailId) {
846
847        CmsListItemDetails lid = m_itemDetails.getObject(itemDetailId);
848        lid.setVisible(!lid.isVisible());
849    }
850
851    /**
852     * Throws a runtime exception if there are 2 identical ids.<p>
853     *
854     * This includes:<p>
855     * <ul>
856     *      <li><code>{@link CmsListIndependentAction}</code>s</li>
857     *      <li><code>{@link CmsListMultiAction}</code>s</li>
858     *      <li><code>{@link CmsListItemDetails}</code></li>
859     *      <li><code>{@link CmsListColumnDefinition}</code>s</li>
860     *      <li><code>{@link CmsListDefaultAction}</code>s</li>
861     *      <li><code>{@link CmsListDirectAction}</code>s</li>
862     * </ul>
863     */
864    /*package*/void checkIds() {
865
866        Set<String> ids = new TreeSet<String>();
867        // indep actions
868        Iterator<I_CmsListAction> itIndepActions = getIndependentActions().iterator();
869        while (itIndepActions.hasNext()) {
870            String id = itIndepActions.next().getId();
871            if (ids.contains(id)) {
872                throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
873            }
874            ids.add(id);
875        }
876        // multi actions
877        Iterator<CmsListMultiAction> itMultiActions = getMultiActions().iterator();
878        while (itMultiActions.hasNext()) {
879            String id = itMultiActions.next().getId();
880            if (ids.contains(id)) {
881                throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
882            }
883            ids.add(id);
884        }
885        // details
886        Iterator<CmsListItemDetails> itItemDetails = getItemDetailDefinitions().iterator();
887        while (itItemDetails.hasNext()) {
888            String id = itItemDetails.next().getId();
889            if (ids.contains(id)) {
890                throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
891            }
892            ids.add(id);
893        }
894        // columns
895        Iterator<CmsListColumnDefinition> itColumns = getColumnDefinitions().iterator();
896        while (itColumns.hasNext()) {
897            CmsListColumnDefinition col = itColumns.next();
898            if (ids.contains(col.getId())) {
899                throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, col.getId()));
900            }
901            ids.add(col.getId());
902            // default actions
903            Iterator<CmsListDefaultAction> itDefaultActions = col.getDefaultActions().iterator();
904            while (itDefaultActions.hasNext()) {
905                CmsListDefaultAction action = itDefaultActions.next();
906                if (ids.contains(action.getId())) {
907                    throw new CmsIllegalStateException(
908                        Messages.get().container(Messages.ERR_DUPLICATED_ID_1, action.getId()));
909                }
910                ids.add(action.getId());
911            }
912            // direct actions
913            Iterator<I_CmsListDirectAction> itDirectActions = col.getDirectActions().iterator();
914            while (itDirectActions.hasNext()) {
915                I_CmsListDirectAction action = itDirectActions.next();
916                if (ids.contains(action.getId())) {
917                    throw new CmsIllegalStateException(
918                        Messages.get().container(Messages.ERR_DUPLICATED_ID_1, action.getId()));
919                }
920                ids.add(action.getId());
921            }
922        }
923    }
924
925    /**
926     * Sets the list id for all column single actions.<p>
927     *
928     * @param col the column to set the list id for
929     */
930    private void setListIdForColumn(CmsListColumnDefinition col) {
931
932        col.setListId(getListId());
933        // default actions
934        Iterator<CmsListDefaultAction> itDefaultActions = col.getDefaultActions().iterator();
935        while (itDefaultActions.hasNext()) {
936            itDefaultActions.next().setListId(getListId());
937        }
938        // direct actions
939        Iterator<I_CmsListDirectAction> itDirectActions = col.getDirectActions().iterator();
940        while (itDirectActions.hasNext()) {
941            itDirectActions.next().setListId(getListId());
942        }
943    }
944}