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