001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id: DirectoryEntryOutputComponent.java 23036 2007-07-27 11:34:11Z btatar $
018 */
019
020package org.nuxeo.ecm.platform.ui.web.directory;
021
022import java.io.Serializable;
023import java.util.ArrayList;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Locale;
027import java.util.Map;
028
029import javax.faces.component.UIOutput;
030import javax.faces.context.FacesContext;
031import javax.faces.el.ValueBinding;
032
033import org.apache.commons.lang.StringUtils;
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.nuxeo.common.utils.i18n.I18NUtils;
037
038/**
039 * Component to display a chained directory entry.
040 *
041 * @author <a href="mailto:glefter@nuxeo.com">George Lefter</a>
042 */
043public class ChainSelectOutputComponent extends UIOutput {
044
045    public static final String COMPONENT_TYPE = "nxdirectory.ChainSelectOutput";
046
047    public static final String COMPONENT_FAMILY = "nxdirectory.ChainSelectOutput";
048
049    @SuppressWarnings("unused")
050    private static final Log log = LogFactory.getLog(ChainSelect.class);
051
052    private static final String DISPLAY_ID_AND_LABEL_SEPARATOR = " ";
053
054    private static final String DEFAULT_ENTRY_SEPARATOR = ", ";
055
056    protected Boolean displayIdAndLabel;
057
058    protected Boolean localize;
059
060    protected String display;
061
062    protected String directoryNameList;
063
064    protected Boolean displayObsoleteEntries;
065
066    protected String keySeparator;
067
068    protected String displayKeySeparator;
069
070    protected Boolean qualifiedParentKeys;
071
072    protected Boolean handleMultipleValues = false;
073
074    private String entrySeparator;
075
076    private String cssStyle;
077
078    private String cssStyleClass;
079
080    public ChainSelectOutputComponent() {
081        setRendererType(COMPONENT_TYPE);
082    }
083
084    @Override
085    public String getFamily() {
086        return COMPONENT_FAMILY;
087    }
088
089    public String getKeySeparator() {
090        String ret = null;
091        ValueBinding vb = getValueBinding("keySeparator");
092        if (vb != null) {
093            ret = (String) vb.getValue(getFacesContext());
094        } else {
095            ret = keySeparator;
096        }
097        if (ret == null) {
098            ret = ChainSelect.DEFAULT_KEY_SEPARATOR;
099        }
100        return ret;
101    }
102
103    public void setDisplayKeySeparator(String keySeparator) {
104        displayKeySeparator = keySeparator;
105    }
106
107    public String getDisplayKeySeparator() {
108        String ret = null;
109        ValueBinding vb = getValueBinding("displayKeySeparator");
110        if (vb != null) {
111            ret = (String) vb.getValue(getFacesContext());
112        } else {
113            ret = displayKeySeparator;
114        }
115        if (ret == null) {
116            ret = getKeySeparator();
117        }
118        return ret;
119    }
120
121    public void setKeySeparator(String keySeparator) {
122        this.keySeparator = keySeparator;
123    }
124
125    public boolean getQualifiedParentKeys() {
126        Boolean ret = null;
127        ValueBinding vb = getValueBinding("qualifiedParentKeys");
128        if (vb != null) {
129            ret = (Boolean) vb.getValue(getFacesContext());
130        } else {
131            ret = qualifiedParentKeys;
132        }
133        return Boolean.TRUE.equals(ret);
134    }
135
136    public boolean getHandleMultipleValues() {
137        Boolean ret = null;
138        ValueBinding vb = getValueBinding("handleMultipleValues");
139        if (vb != null) {
140            ret = (Boolean) vb.getValue(getFacesContext());
141        } else {
142            ret = handleMultipleValues;
143        }
144        return Boolean.TRUE.equals(ret);
145    }
146
147    public void setHandleMultipleValues(boolean handleMultipleValues) {
148        this.handleMultipleValues = handleMultipleValues;
149    }
150
151    public void setQualifiedParentKeys(boolean qualifiedParentKeys) {
152        this.qualifiedParentKeys = qualifiedParentKeys;
153    }
154
155    /**
156     * @deprecated use display=id|label|idAndLabel instead
157     */
158    @Deprecated
159    public boolean getDisplayIdAndLabel() {
160        Boolean ret;
161        ValueBinding vb = getValueBinding("displayIdAndLabel");
162        if (vb != null) {
163            ret = (Boolean) vb.getValue(getFacesContext());
164        } else {
165            ret = displayIdAndLabel;
166        }
167        return Boolean.TRUE.equals(ret);
168    }
169
170    public void setDisplayIdAndLabel(boolean displayIdAndLabel) {
171        this.displayIdAndLabel = displayIdAndLabel;
172    }
173
174    public boolean getLocalize() {
175        return Boolean.TRUE.equals(localize);
176    }
177
178    public void setLocalize(boolean localize) {
179        this.localize = localize;
180    }
181
182    /**
183     * Hide legacy "displayIdAndLabel" property. Use "display" if set; else if "displayIdAndLabel" is true, return
184     * "idAndLabel", else default to "label".
185     *
186     * @return whether to display the id, the label or both
187     */
188    public String getDisplay() {
189        String ret;
190        ValueBinding vb = getValueBinding("display");
191        if (vb != null) {
192            ret = (String) vb.getValue(getFacesContext());
193        } else {
194            ret = display;
195        }
196
197        if (ret == null) {
198            boolean displayIdAndLabel = getDisplayIdAndLabel();
199            ret = displayIdAndLabel ? "idAndLabel" : "label";
200        }
201
202        return ret;
203    }
204
205    public void setDisplay(String display) {
206        this.display = display;
207    }
208
209    @Override
210    public Object saveState(FacesContext context) {
211        Object[] values = new Object[12];
212        values[0] = super.saveState(context);
213        values[1] = displayIdAndLabel;
214        values[2] = localize;
215        values[3] = display;
216        values[4] = displayObsoleteEntries;
217        values[5] = directoryNameList;
218        values[6] = qualifiedParentKeys;
219        values[7] = keySeparator;
220        values[8] = cssStyle;
221        values[9] = cssStyleClass;
222        values[10] = entrySeparator;
223        values[11] = handleMultipleValues;
224        return values;
225    }
226
227    @Override
228    public void restoreState(FacesContext context, Object state) {
229        Object[] values = (Object[]) state;
230        super.restoreState(context, values[0]);
231        displayIdAndLabel = (Boolean) values[1];
232        localize = (Boolean) values[2];
233        display = (String) values[3];
234        displayObsoleteEntries = (Boolean) values[4];
235        directoryNameList = (String) values[5];
236        qualifiedParentKeys = (Boolean) values[6];
237        keySeparator = (String) values[7];
238        cssStyle = (String) values[8];
239        cssStyleClass = (String) values[9];
240        entrySeparator = (String) values[10];
241        handleMultipleValues = (Boolean) values[11];
242    }
243
244    public boolean getDisplayObsoleteEntries() {
245        return Boolean.TRUE.equals(displayObsoleteEntries);
246    }
247
248    /**
249     * Transform a comma-separated list of keys into a selection. The list can be separated by the <b>keySeparator</b>
250     * string
251     *
252     * @param keyEnum the comma-separated list of keys
253     * @return
254     */
255    public Selection createSelection(String keyEnum) {
256        String keySeparator = getKeySeparator();
257        String[] columns = StringUtils.split(keyEnum, keySeparator);
258
259        List<String> keyList = new ArrayList<String>();
260        List<DirectorySelectItem> itemList = new ArrayList<DirectorySelectItem>();
261        String directoryNameList = getDirectoryNameList();
262        String[] directoryNames = StringUtils.split(directoryNameList, ",");
263        boolean qualifiedParentKeys = getQualifiedParentKeys();
264        boolean displayObsoleteEntries = getDisplayObsoleteEntries();
265        String display = getDisplay();
266
267        for (int i = 0; i < directoryNames.length; i++) {
268            directoryNames[i] = directoryNames[i].trim();
269        }
270
271        for (int i = 0; i < columns.length; i++) {
272            String id = columns[i];
273
274            String directoryName = directoryNames[i];
275
276            Map<String, Serializable> filter = new HashMap<String, Serializable>();
277            filter.put("id", id);
278
279            if (i == 0) {
280                if (DirectoryHelper.instance().hasParentColumn(directoryName)) {
281                    // explicitely filter on NULL parent in a xvocabulary
282                    filter.put("parent", null);
283                }
284            } else {
285                String parentId;
286                if (qualifiedParentKeys) {
287                    parentId = StringUtils.join(keyList.iterator(), keySeparator);
288                } else {
289                    parentId = columns[i - 1];
290                }
291                filter.put("parent", parentId);
292            }
293
294            keyList.add(id);
295
296            if (!displayObsoleteEntries) {
297                filter.put("obsolete", 0);
298            }
299            DirectorySelectItem item = DirectoryHelper.instance().getSelectItem(directoryName, filter);
300            if (item == null) {
301                item = new DirectorySelectItem(id, id);
302            }
303            String itemId = (String) item.getValue();
304            String label = item.getLabel();
305            if (getLocalize()) {
306                label = translate(getFacesContext(), label);
307            }
308            if ("id".equals(display)) {
309                label = id;
310            } else if ("idAndLabel".equals(display)) {
311                label = itemId + DISPLAY_ID_AND_LABEL_SEPARATOR + label;
312            }
313            item.setLabel(label);
314            itemList.add(item);
315        }
316        return new Selection(itemList.toArray(new DirectorySelectItem[columns.length]));
317    }
318
319    protected static String translate(FacesContext context, String label) {
320        String bundleName = context.getApplication().getMessageBundle();
321        Locale locale = context.getViewRoot().getLocale();
322        label = I18NUtils.getMessageString(bundleName, label, null, locale);
323        return label;
324    }
325
326    public String getEntrySeparator() {
327        String ret = null;
328        ValueBinding vb = getValueBinding("entrySeparator");
329        if (vb != null) {
330            ret = (String) vb.getValue(getFacesContext());
331        } else {
332            ret = entrySeparator;
333        }
334        return entrySeparator == null ? DEFAULT_ENTRY_SEPARATOR : entrySeparator;
335    }
336
337    public void setEntrySeparator(String entrySeparator) {
338        this.entrySeparator = entrySeparator;
339    }
340
341    public String getCssStyle() {
342        return cssStyle;
343    }
344
345    public void setCssStyle(String cssStyle) {
346        this.cssStyle = cssStyle;
347    }
348
349    public String getCssStyleClass() {
350        return cssStyleClass;
351    }
352
353    public void setCssStyleClass(String cssStyleClass) {
354        this.cssStyleClass = cssStyleClass;
355    }
356
357    public void setDisplayObsoleteEntries(Boolean displayObsoleteEntries) {
358        this.displayObsoleteEntries = displayObsoleteEntries;
359    }
360
361    public void setDisplayObsoleteEntries(boolean displayObsoleteEntries) {
362        this.displayObsoleteEntries = displayObsoleteEntries;
363    }
364
365    public void setQualifiedParentKeys(Boolean qualifiedParentKeys) {
366        this.qualifiedParentKeys = qualifiedParentKeys;
367    }
368
369    public String getDirectoryNameList() {
370        String ret;
371        ValueBinding vb = getValueBinding("directoryNameList");
372        if (vb != null) {
373            ret = (String) vb.getValue(getFacesContext());
374        } else {
375            ret = directoryNameList;
376        }
377        return ret;
378    }
379
380    public void setDirectoryNameList(String directoryNameList) {
381        this.directoryNameList = directoryNameList;
382    }
383
384}