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.i18n.CmsMessageContainer;
031import org.opencms.i18n.CmsMessages;
032import org.opencms.main.CmsIllegalArgumentException;
033import org.opencms.util.CmsStringUtil;
034import org.opencms.workplace.CmsWorkplace;
035import org.opencms.workplace.tools.A_CmsHtmlIconButton;
036import org.opencms.workplace.tools.CmsHtmlIconButtonStyleEnum;
037
038import java.text.MessageFormat;
039import java.util.ArrayList;
040import java.util.Collections;
041import java.util.Iterator;
042import java.util.List;
043import java.util.Locale;
044
045/**
046 * Html list column definition.<p>
047 *
048 * @since 6.0.0
049 */
050public class CmsListColumnDefinition {
051
052    /** Standard list button location. */
053    public static final String ICON_DOWN = "list/arrow_down.png";
054
055    /** Standard list button location. */
056    public static final String ICON_UP = "list/arrow_up.png";
057
058    /** Column alignment. */
059    private CmsListColumnAlignEnum m_align = CmsListColumnAlignEnum.ALIGN_LEFT;
060
061    /** Comparator for sorting. */
062    private I_CmsListItemComparator m_comparator = new CmsListItemDefaultComparator();
063
064    /** Default action. */
065    private List<CmsListDefaultAction> m_defaultActions = new ArrayList<CmsListDefaultAction>();
066
067    /** List of actions. */
068    private List<I_CmsListDirectAction> m_directActions = new ArrayList<I_CmsListDirectAction>();
069
070    /** Data formatter. */
071    private I_CmsListFormatter m_formatter;
072
073    /** Customized help text. */
074    private CmsMessageContainer m_helpText;
075
076    /** Unique id. */
077    private final String m_id;
078
079    /** List id. */
080    private String m_listId;
081
082    /** Display name. */
083    private CmsMessageContainer m_name;
084
085    /** Is printable flag. */
086    private boolean m_printable = true;
087
088    /** Flag for text wrapping. */
089    private boolean m_textWrapping;
090
091    /** Visible Flag. */
092    private boolean m_visible = true;
093
094    /** Column width. */
095    private String m_width;
096
097    /** The related workplace dialog object. */
098    private transient A_CmsListDialog m_wp;
099
100    /**
101     * Default Constructor.<p>
102     *
103     * @param id the unique id
104     */
105    public CmsListColumnDefinition(String id) {
106
107        if (CmsStringUtil.isEmptyOrWhitespaceOnly(id)) {
108            throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_LIST_INVALID_NULL_ARG_1, "id"));
109        }
110        m_id = id;
111    }
112
113    /**
114     * Adds a default Action.<p>
115     *
116     * A column could have more than one default action if the visibilities are complementary.<p>
117     *
118     * @param defaultAction the default Action to add
119     */
120    public void addDefaultAction(CmsListDefaultAction defaultAction) {
121
122        if (m_listId != null) {
123            // set the list id
124            defaultAction.setListId(m_listId);
125        }
126        // set the column id
127        defaultAction.setColumnForLink(this);
128
129        m_defaultActions.add(defaultAction);
130    }
131
132    /**
133     * Adds a new action to the column.<p>
134     *
135     * @param listAction the action to add
136     */
137    public void addDirectAction(I_CmsListDirectAction listAction) {
138
139        if (m_listId != null) {
140            listAction.setListId(m_listId);
141        }
142        m_directActions.add(listAction);
143    }
144
145    /**
146     * returns the csv output for a cell.<p>
147     *
148     * @param item the item to render the cell for
149     *
150     * @return csv output
151     */
152    public String csvCell(CmsListItem item) {
153
154        if (!isVisible()) {
155            return "";
156        }
157        StringBuffer csv = new StringBuffer(512);
158        if (m_formatter == null) {
159            // unformatted output
160            if (item.get(m_id) != null) {
161                // null values are not showed by default
162                csv.append(item.get(m_id).toString());
163            } else {
164                Iterator<I_CmsListDirectAction> itActions = m_directActions.iterator();
165                while (itActions.hasNext()) {
166                    I_CmsListDirectAction action = itActions.next();
167                    if (action.isVisible()) {
168                        action.setItem(item);
169                        csv.append(action.getName().key(getWp().getLocale()));
170                    }
171                }
172            }
173        } else {
174            // formatted output
175            csv.append(m_formatter.format(item.get(m_id), getWp().getLocale()));
176        }
177        return csv.toString();
178    }
179
180    /**
181     * Returns the csv output for a column header.<p>
182     *
183     * @return csv header
184     */
185    public String csvHeader() {
186
187        if (!isVisible()) {
188            return "";
189        }
190        return getName().key(getWp().getLocale());
191    }
192
193    /**
194     * Returns the align.<p>
195     *
196     * @return the align
197     */
198    public CmsListColumnAlignEnum getAlign() {
199
200        return m_align;
201    }
202
203    /**
204     * Returns a default action by id.<p>
205     *
206     * @param actionId the id of the action
207     *
208     * @return the action if found or null
209     */
210    public CmsListDefaultAction getDefaultAction(String actionId) {
211
212        Iterator<CmsListDefaultAction> it = m_defaultActions.iterator();
213        while (it.hasNext()) {
214            CmsListDefaultAction action = it.next();
215            if (action.getId().equals(actionId)) {
216                return action;
217            }
218        }
219        return null;
220    }
221
222    /**
223     * Returns the default Action Ids list.<p>
224     *
225     * @return the default Action Ids list
226     */
227    public List<String> getDefaultActionIds() {
228
229        List<String> ids = new ArrayList<String>();
230        Iterator<CmsListDefaultAction> itDefActions = m_defaultActions.iterator();
231        while (itDefActions.hasNext()) {
232            I_CmsListDirectAction action = itDefActions.next();
233            ids.add(action.getId());
234        }
235        return Collections.unmodifiableList(ids);
236    }
237
238    /**
239     * Returns the default Actions list.<p>
240     *
241     * @return a list of {@link CmsListDefaultAction} objects
242     */
243    public List<CmsListDefaultAction> getDefaultActions() {
244
245        return Collections.unmodifiableList(m_defaultActions);
246    }
247
248    /**
249     * Returns a direct action by id.<p>
250     *
251     * @param actionId the id of the action
252     *
253     * @return the action if found or null
254     */
255    public I_CmsListDirectAction getDirectAction(String actionId) {
256
257        Iterator<I_CmsListDirectAction> it = m_directActions.iterator();
258        while (it.hasNext()) {
259            I_CmsListDirectAction action = it.next();
260            if (action.getId().equals(actionId)) {
261                return action;
262            }
263        }
264        return null;
265    }
266
267    /**
268     * Returns the direct Action Ids list.<p>
269     *
270     * @return the direct Action Ids list
271     */
272    public List<String> getDirectActionIds() {
273
274        List<String> ids = new ArrayList<String>();
275        Iterator<I_CmsListDirectAction> itDirActions = m_directActions.iterator();
276        while (itDirActions.hasNext()) {
277            I_CmsListDirectAction action = itDirActions.next();
278            ids.add(action.getId());
279        }
280        return Collections.unmodifiableList(ids);
281    }
282
283    /**
284     * Returns all direct actions.<p>
285     *
286     * @return a list of <code>{@link I_CmsListDirectAction}</code>s.
287     */
288    public List<I_CmsListDirectAction> getDirectActions() {
289
290        return Collections.unmodifiableList(m_directActions);
291    }
292
293    /**
294     * Returns the data formatter.<p>
295     *
296     * @return the data formatter
297     */
298    public I_CmsListFormatter getFormatter() {
299
300        return m_formatter;
301    }
302
303    /**
304     * Returns the customized help Text.<p>
305     *
306     * if <code>null</code> a default help text indicating the sort actions is used.<p>
307     *
308     * @return the customized help Text
309     */
310    public CmsMessageContainer getHelpText() {
311
312        return m_helpText;
313    }
314
315    /**
316     * Returns the id.<p>
317     *
318     * @return the id
319     */
320    public String getId() {
321
322        return m_id;
323    }
324
325    /**
326     * Returns the comparator, used for sorting.<p>
327     *
328     * if no comparator was set, the default list item comparator is used.<p>
329     *
330     * @return the comparator
331     *
332     * @see CmsListItemDefaultComparator
333     */
334    public I_CmsListItemComparator getListItemComparator() {
335
336        return m_comparator;
337    }
338
339    /**
340     * Returns the name.<p>
341     *
342     * @return the name
343     */
344    public CmsMessageContainer getName() {
345
346        return m_name;
347    }
348
349    /**
350     * Returns the width.<p>
351     *
352     * @return the width
353     */
354    public String getWidth() {
355
356        return m_width;
357    }
358
359    /**
360     * Returns the workplace dialog object.<p>
361     *
362     * @return the workplace dialog object
363     */
364    public A_CmsListDialog getWp() {
365
366        return m_wp;
367    }
368
369    /**
370     * returns the html for a cell.<p>
371     *
372     * @param item the item to render the cell for
373     * @param isPrintable if the list is to be printed
374     *
375     * @return html code
376     */
377    public String htmlCell(CmsListItem item, boolean isPrintable) {
378
379        StringBuffer html = new StringBuffer(512);
380        Iterator<I_CmsListDirectAction> itActions = m_directActions.iterator();
381        while (itActions.hasNext()) {
382            I_CmsListDirectAction action = itActions.next();
383            action.setItem(item);
384            boolean enabled = action.isEnabled();
385            if (isPrintable) {
386                action.setEnabled(false);
387            }
388            html.append(action.buttonHtml());
389            if (isPrintable) {
390                action.setEnabled(enabled);
391            }
392        }
393        if (!m_defaultActions.isEmpty()) {
394            Iterator<CmsListDefaultAction> itDefaultActions = m_defaultActions.iterator();
395            while (itDefaultActions.hasNext()) {
396                CmsListDefaultAction defAction = itDefaultActions.next();
397                defAction.setItem(item);
398                boolean enabled = defAction.isEnabled();
399                if (isPrintable) {
400                    defAction.setEnabled(false);
401                }
402                html.append(defAction.buttonHtml());
403                if (isPrintable) {
404                    defAction.setEnabled(enabled);
405                }
406            }
407        } else {
408            if (m_formatter == null) {
409                // unformatted output
410                if (item.get(m_id) != null) {
411                    // null values are not showed by default
412                    html.append(item.get(m_id).toString());
413                }
414            } else {
415                // formatted output
416                html.append(m_formatter.format(item.get(m_id), getWp().getLocale()));
417            }
418        }
419        html.append("\n");
420        return html.toString();
421    }
422
423    /**
424     * Returns the html code for a column header.<p>
425     *
426     * @param list the list to generate the header code for
427     *
428     * @return html code
429     */
430    public String htmlHeader(CmsHtmlList list) {
431
432        String listId = list.getId();
433        String sortedCol = list.getSortedColumn();
434        CmsListOrderEnum order = list.getCurrentSortOrder();
435
436        StringBuffer html = new StringBuffer(512);
437        Locale locale = getWp().getLocale();
438        CmsMessages messages = Messages.get().getBundle(locale);
439        html.append("<th");
440        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getWidth())) {
441            html.append(" width='");
442            html.append(getWidth());
443            html.append("'");
444        }
445        if (!isTextWrapping()) {
446            html.append(" style='white-space: nowrap;'");
447        }
448        html.append(">\n");
449
450        boolean isSorted = getId().equals(sortedCol);
451        CmsListOrderEnum nextOrder = CmsListOrderEnum.ORDER_ASCENDING;
452        if (isSorted && (order == CmsListOrderEnum.ORDER_ASCENDING)) {
453            nextOrder = CmsListOrderEnum.ORDER_DESCENDING;
454        }
455        // button
456        String id = listId + getId() + "Sort";
457        String onClic = "listSort('" + listId + "', '" + getId() + "');";
458        String helpText = null;
459        if (m_helpText != null) {
460            helpText = new MessageFormat(m_helpText.key(locale), locale).format(new Object[] {getName().key(locale)});
461        } else {
462            if (isSorteable()) {
463                if (nextOrder.equals(CmsListOrderEnum.ORDER_ASCENDING)) {
464                    helpText = messages.key(Messages.GUI_LIST_COLUMN_ASC_SORT_1, new Object[] {getName().key(locale)});
465                } else {
466                    helpText = messages.key(Messages.GUI_LIST_COLUMN_DESC_SORT_1, new Object[] {getName().key(locale)});
467                }
468            } else {
469                helpText = messages.key(Messages.GUI_LIST_COLUMN_NO_SORT_1, new Object[] {getName().key(locale)});
470            }
471        }
472        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getWidth()) && (getWidth().indexOf('%') < 0)) {
473            html.append("\t<div style='display:block; width: ");
474            html.append(getWidth());
475            html.append("px;'>\n");
476        }
477        String sortArrow = "";
478        // sort order marker
479        if (isSorted) {
480            if (nextOrder == CmsListOrderEnum.ORDER_ASCENDING) {
481                sortArrow = "<img src='" + CmsWorkplace.getSkinUri() + ICON_DOWN + "' alt=''>&nbsp;";
482            } else {
483                sortArrow = "<img src='" + CmsWorkplace.getSkinUri() + ICON_UP + "' alt=''>&nbsp;";
484            }
485        }
486        html.append(
487            A_CmsHtmlIconButton.defaultButtonHtml(
488                CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT,
489                id,
490                id,
491                getName().key(locale),
492                helpText,
493                list.isPrintable() ? false : isSorteable(),
494                null,
495                null,
496                onClic,
497                false,
498                sortArrow));
499        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getWidth()) && (getWidth().indexOf('%') < 0)) {
500            html.append("\t</div>\n");
501        }
502        html.append("</th>\n");
503        return html.toString();
504    }
505
506    /**
507     * Returns the printable  .<p>
508     *
509     * @return the printable flag
510     */
511    public boolean isPrintable() {
512
513        return m_printable;
514    }
515
516    /**
517     * Returns the sorteable.<p>
518     *
519     * @return the sorteable
520     */
521    public boolean isSorteable() {
522
523        return getListItemComparator() != null;
524    }
525
526    /**
527     * Returns the text Wrapping flag.<p>
528     *
529     * @return the text Wrapping flag
530     */
531    public boolean isTextWrapping() {
532
533        return m_textWrapping;
534    }
535
536    /**
537     * Returns the visible.<p>
538     *
539     * @return the visible
540     */
541    public boolean isVisible() {
542
543        return m_visible;
544    }
545
546    /**
547     * Removes the default action from this column by id.<p>
548     *
549     * @param actionId the id of the action to remove
550     *
551     * @return the action if found or <code>null</code>
552     */
553    public CmsListDefaultAction removeDefaultAction(String actionId) {
554
555        Iterator<CmsListDefaultAction> it = m_defaultActions.iterator();
556        while (it.hasNext()) {
557            CmsListDefaultAction action = it.next();
558            if (action.getId().equals(actionId)) {
559                it.remove();
560                return action;
561            }
562        }
563        return null;
564    }
565
566    /**
567     * Removes a direct action from this column by id.<p>
568     *
569     * @param actionId the id of the action to remove
570     *
571     * @return the action if found or <code>null</code>
572     */
573    public I_CmsListDirectAction removeDirectAction(String actionId) {
574
575        Iterator<I_CmsListDirectAction> it = m_directActions.iterator();
576        while (it.hasNext()) {
577            I_CmsListDirectAction action = it.next();
578            if (action.getId().equals(actionId)) {
579                it.remove();
580                return action;
581            }
582        }
583        return null;
584    }
585
586    /**
587     * Sets the align.<p>
588     *
589     * @param align the align to set
590     */
591    public void setAlign(CmsListColumnAlignEnum align) {
592
593        m_align = align;
594    }
595
596    /**
597     * Sets the data formatter.<p>
598     *
599     * @param formatter the data formatter to set
600     */
601    public void setFormatter(I_CmsListFormatter formatter) {
602
603        m_formatter = formatter;
604        // set the formatter for all default actions
605        Iterator<CmsListDefaultAction> it = m_defaultActions.iterator();
606        while (it.hasNext()) {
607            CmsListDefaultAction action = it.next();
608            action.setColumnForLink(this);
609        }
610    }
611
612    /**
613     * Sets the customized help Text.<p>
614     *
615     * if <code>null</code> a default help text indicating the sort actions is used.<p>
616     *
617     * @param helpText the customized help Text to set
618     */
619    public void setHelpText(CmsMessageContainer helpText) {
620
621        m_helpText = helpText;
622    }
623
624    /**
625     * Sets the comparator, used for sorting.<p>
626     *
627     * @param comparator the comparator to set
628     */
629    public void setListItemComparator(I_CmsListItemComparator comparator) {
630
631        m_comparator = comparator;
632    }
633
634    /**
635     * Sets the name.<p>
636     *
637     * @param name the name to set
638     */
639    public void setName(CmsMessageContainer name) {
640
641        m_name = name;
642    }
643
644    /**
645     * Sets the printable flag.<p>
646     *
647     * @param printable the printable flag to set
648     */
649    public void setPrintable(boolean printable) {
650
651        m_printable = printable;
652    }
653
654    /**
655     * Indicates if the current column is sorteable or not.<p>
656     *
657     * if <code>true</code> a default list item comparator is used.<p>
658     *
659     * if <code>false</code> any previously set list item comparator is removed.<p>
660     *
661     * @param sorteable the sorteable flag
662     */
663    public void setSorteable(boolean sorteable) {
664
665        if (sorteable) {
666            setListItemComparator(new CmsListItemDefaultComparator());
667        } else {
668            setListItemComparator(null);
669        }
670    }
671
672    /**
673     * Sets the text Wrapping flag.<p>
674     *
675     * @param textWrapping the text Wrapping flag to set
676     */
677    public void setTextWrapping(boolean textWrapping) {
678
679        m_textWrapping = textWrapping;
680    }
681
682    /**
683     * Sets the visible.<p>
684     *
685     * This will set also the printable flag to <code>false</code>.<p>
686     *
687     * @param visible the visible to set
688     */
689    public void setVisible(boolean visible) {
690
691        m_visible = visible;
692        if (!m_visible) {
693            setPrintable(false);
694        }
695    }
696
697    /**
698     * Sets the width.<p>
699     *
700     * @param width the width to set
701     */
702    public void setWidth(String width) {
703
704        m_width = width;
705    }
706
707    /**
708     * Sets the workplace dialog object.<p>
709     *
710     * @param wp the workplace dialog object to set
711     */
712    public void setWp(A_CmsListDialog wp) {
713
714        m_wp = wp;
715        Iterator<I_CmsListDirectAction> itActs = getDirectActions().iterator();
716        while (itActs.hasNext()) {
717            I_CmsListDirectAction action = itActs.next();
718            action.setWp(wp);
719        }
720        Iterator<CmsListDefaultAction> itDefActs = getDefaultActions().iterator();
721        while (itDefActs.hasNext()) {
722            CmsListDefaultAction action = itDefActs.next();
723            action.setWp(wp);
724        }
725    }
726
727    /**
728     * Sets the id of the list.<p>
729     *
730     * @param listId the id of the list
731     */
732    /*package*/void setListId(String listId) {
733
734        m_listId = listId;
735    }
736}