001: /*
002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/widgets/CmsSelectWidgetOption.java,v $
003: * Date : $Date: 2008-02-27 12:05:43 $
004: * Version: $Revision: 1.10 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software GmbH, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.widgets;
033:
034: import org.opencms.main.CmsLog;
035: import org.opencms.util.CmsStringUtil;
036:
037: import java.util.ArrayList;
038: import java.util.Collections;
039: import java.util.List;
040:
041: import org.apache.commons.logging.Log;
042:
043: /**
044: * An option of a select type widget.<p>
045: *
046: * If options are passed from XML content schema definitions as widget configuration options,
047: * the following syntax is used for defining the option values:<p>
048: *
049: * <code>value='{text}' default='{true|false}' option='{text}' help='{text}|{more option definitions}</code><p>
050: *
051: * For example:<p>
052: *
053: * <code>value='value1' default='true' option='option1' help='help1'|value='value2' option='option2' help='help2'</code><p>
054: *
055: * The elements <code>default</code>, <code>option</code> and <code>help</code> are all optional, only a
056: * <code>value</code> must be present in the input.
057: * There should be only one <code>default</code> set to <code>true</code>
058: * in the input, if more than one is detected, only the first <code>default</code> found is actually used.
059: * If no <code>option</code> is given, the value of <code>option</code> defaults to the value of the given <code>value</code>.
060: * If no <code>help</code> is given, the default is <code>null</code>.<p>
061: *
062: * Shortcut syntax options:<p>
063: *
064: * If you don't specify the <code>value</code> key, the value is assumed to start at the first position of an
065: * option definition. In this case the value must not be surrounded by the <code>'</code> chars.
066: * Example: <code>value='some value' default='true'</code> can also be written as <code>some value default='true'</code>.<p>
067: *
068: * Only if you use the short value definition as described above, a default value can be marked with a <code>*</code>
069: * at the end of the value definition.
070: * Example: <code>value='some value' default='true'</code> can also be written as <code>some value*</code>.<p>
071: *
072: * Only if you use the short value definition as described above, you can also append the <code>option</code>
073: * to the <code>value</code> using a <code>:</code>. In this case no <code>'</code> must surround the <code>option</code>.
074: * Please keep in mind that in this case the value
075: * itself can not longer contain a <code>:</code> char, since it would then be interpreted as a delimiter.
076: * Example: <code>value='some value' option='some option'</code> can also be written as <code>some value:some option</code>.<p>
077: *
078: * Any combinations of the above described shortcuts are allowed in the configuration option String.
079: * Here are some more examples of valid configuration option Strings:<p>
080: *
081: * <code>1*|2|3|4|5|6|7</code><br>
082: * <code>1 default='true'|2|3|4|5|6|7</code><br>
083: * <code>value='1' default='true'|value='2'|value='3'</code><br>
084: * <code>value='1'|2*|value='3'</code><br>
085: * <code>1*:option text|2|3|4</code><br>
086: * <code>1* option='option text' help='some'|2|3|4</code><p>
087: *
088: * Please note: If an entry in the configuration String is malformed, this error is silently ignored (but written
089: * to the log channel of this class at <code>INFO</code>level.<p>
090: *
091: * @author Alexander Kandzior
092: *
093: * @version $Revision: 1.10 $
094: *
095: * @since 6.0.0
096: */
097: public class CmsSelectWidgetOption {
098:
099: /** Optional shortcut default marker. */
100: private static final char DEFAULT_MARKER = '*';
101:
102: /** Delimiter between option sets. */
103: private static final char INPUT_DELIMITER = '|';
104:
105: /** Key prefix for the 'default'. */
106: private static final String KEY_DEFAULT = "default='";
107:
108: /** Key prefix for the 'help' text. */
109: private static final String KEY_HELP = "help='";
110:
111: /** Key prefix for the 'option' text. */
112: private static final String KEY_OPTION = "option='";
113:
114: /** Key prefix for the 'value'. */
115: private static final String KEY_VALUE = "value='";
116:
117: /** The log object for this class. */
118: private static final Log LOG = CmsLog
119: .getLog(CmsSelectWidgetOption.class);
120:
121: /** Optional shortcut option delimiter. */
122: private static final char OPTION_DELIMITER = ':';
123:
124: /** Indicates if this is the default value of the selection. */
125: private boolean m_default;
126:
127: /** The hashcode of this object. */
128: private int m_hashcode;
129:
130: /** The (optional) help text of this select option. */
131: private String m_help;
132:
133: /** The (optional) display text of this select option. */
134: private String m_option;
135:
136: /** The value of this select option. */
137: private String m_value;
138:
139: /**
140: * Creates a new select option for the given value.<p>
141: *
142: * @param value the value of this select option
143: */
144: public CmsSelectWidgetOption(String value) {
145:
146: this (value, false, null, null);
147: }
148:
149: /**
150: * Creates a new select option form the given values.<p>
151: *
152: * @param value the value of this select option
153: * @param isDefault indicates if this is the default value of the selection (default is <code>false</code>)
154: */
155: public CmsSelectWidgetOption(String value, boolean isDefault) {
156:
157: this (value, isDefault, null, null);
158: }
159:
160: /**
161: * Creates a new select option form the given values.<p>
162: *
163: * @param value the value of this select option
164: * @param isDefault indicates if this is the default value of the selection (default is <code>false</code>)
165: * @param optionText the (optional) display text of this select option
166: */
167: public CmsSelectWidgetOption(String value, boolean isDefault,
168: String optionText) {
169:
170: this (value, isDefault, optionText, null);
171: }
172:
173: /**
174: * Creates a new select option form the given values.<p>
175: *
176: * @param value the value of this select option
177: * @param isDefault indicates if this is the default value of the selection (default is <code>false</code>)
178: * @param optionText the (optional) display text of this select option
179: * @param helpText the (optional) help text of this select option
180: */
181: public CmsSelectWidgetOption(String value, boolean isDefault,
182: String optionText, String helpText) {
183:
184: m_default = isDefault;
185: m_value = value;
186: m_option = optionText;
187: m_help = helpText;
188: }
189:
190: /**
191: * Returns a select widget configuration String created from the given list of select options.<p>
192: *
193: * If an element found in the given list is not of type
194: * <code>{@link CmsSelectWidgetOption}</code>, it is ignored.<p>
195: *
196: * @param options the list of select options to create the configuration String for
197: *
198: * @return a select widget configuration String created from the given list of select options
199: */
200: public static String createConfigurationString(List options) {
201:
202: if ((options == null) || (options.size() == 0)) {
203: return "";
204: }
205: StringBuffer result = new StringBuffer(256);
206: boolean first = true;
207: for (int i = 0; i < options.size(); i++) {
208: Object o = options.get(i);
209: if (o instanceof CmsSelectWidgetOption) {
210: if (!first) {
211: result
212: .append(CmsSelectWidgetOption.INPUT_DELIMITER);
213: } else {
214: first = false;
215: }
216: result.append(o.toString());
217: }
218: }
219: return result.toString();
220: }
221:
222: /**
223: * Returns the default option from the given list of select options,
224: * or <code>null</code> in case there is no default option in the given list.<p>
225: *
226: * If an element found in the given list is not of type
227: * <code>{@link CmsSelectWidgetOption}</code>, this is ignored.<p>
228: *
229: * @param options the list of select options to get the default from
230: *
231: * @return the default option from the given list of select options, or <code>null</code> in case there is no default option
232: */
233: public static CmsSelectWidgetOption getDefaultOption(List options) {
234:
235: if ((options == null) || (options.size() == 0)) {
236: return null;
237: }
238: for (int i = 0; i < options.size(); i++) {
239: Object o = options.get(i);
240: if (o instanceof CmsSelectWidgetOption) {
241: CmsSelectWidgetOption option = (CmsSelectWidgetOption) o;
242: if (option.isDefault()) {
243: return option;
244: }
245: }
246: }
247: return null;
248: }
249:
250: /**
251: * Returns a list of default options from the given list of select options.<p>
252: *
253: * If an element found in the given list is not of type
254: * <code>{@link CmsSelectWidgetOption}</code>, this is ignored.<p>
255: *
256: * @param options the list of select options to get the default from
257: *
258: * @return a list of <code>{@link CmsSelectWidgetOption}</code> objects
259: */
260: public static List getDefaultOptions(List options) {
261:
262: List defaults = new ArrayList();
263: if ((options == null) || (options.size() == 0)) {
264: return defaults;
265: }
266: for (int i = 0; i < options.size(); i++) {
267: Object o = options.get(i);
268: if (o instanceof CmsSelectWidgetOption) {
269: CmsSelectWidgetOption option = (CmsSelectWidgetOption) o;
270: if (option.isDefault()) {
271: defaults.add(option);
272: }
273: }
274: }
275: return defaults;
276: }
277:
278: /**
279: * Parses a widget configuration String for select option values.<p>
280: *
281: * If the input is <code>null</code> or empty, a <code>{@link Collections#EMPTY_LIST}</code>
282: * is returned.<p>
283: *
284: * Please note: No exception is thrown in case the input is malformed, all malformed entries are silently ignored.<p>
285: *
286: * @param input the widget input string to parse
287: *
288: * @return a List of <code>{@link CmsSelectWidgetOption}</code> elements
289: */
290: public static List parseOptions(String input) {
291:
292: if (CmsStringUtil.isEmptyOrWhitespaceOnly(input)) {
293: // default result for empty input
294: return Collections.EMPTY_LIST;
295: }
296:
297: // cut along the delimiter
298: String[] parts = CmsStringUtil.splitAsArray(input,
299: INPUT_DELIMITER);
300: List result = new ArrayList();
301:
302: // indicates if a default of 'true' was already set in this result list
303: boolean foundDefault = false;
304:
305: for (int i = 0; i < parts.length; i++) {
306:
307: String part = parts[i].trim();
308: if (part.length() == 0) {
309: // skip empty parts
310: continue;
311: }
312:
313: try {
314:
315: String value = null;
316: String option = null;
317: String help = null;
318: boolean isDefault = false;
319:
320: int posValue = part.indexOf(KEY_VALUE);
321: int posDefault = part.indexOf(KEY_DEFAULT);
322: int posOption = part.indexOf(KEY_OPTION);
323: int posHelp = part.indexOf(KEY_HELP);
324:
325: boolean shortValue = false;
326: if (posValue < 0) {
327: // shortcut syntax, value key must be at first position
328: if ((posDefault == 0) || (posOption == 0)
329: || (posHelp == 0)) {
330: // malformed part - no value given
331: throw new CmsWidgetException(
332: Messages
333: .get()
334: .container(
335: Messages.ERR_MALFORMED_SELECT_OPTIONS_1,
336: input));
337: }
338: posValue = 0;
339: shortValue = true;
340: }
341:
342: // a 'value' must be always present
343: int end = part.length();
344: // check where the 'value' ends
345: if (posHelp > posValue) {
346: end = posHelp;
347: }
348: if ((posDefault > posValue) && (posDefault < end)) {
349: end = posDefault;
350: }
351: if ((posOption > posValue) && (posOption < end)) {
352: end = posOption;
353: }
354: if (shortValue) {
355: // no explicit setting using the key, value must be at the first position
356: value = part.substring(0, end).trim();
357: } else {
358: value = part.substring(
359: posValue + KEY_VALUE.length(), end).trim();
360: // cut of trailing '
361: value = value.substring(0, value.length() - 1);
362: }
363:
364: boolean shortOption = false;
365: // check if the option is appended using the ':' shortcut
366: if ((shortValue) && (posOption < 0)) {
367: int pos = value.indexOf(OPTION_DELIMITER);
368: if (pos >= 0) {
369: // shortcut syntax is used
370: posOption = pos;
371: shortOption = true;
372: value = value.substring(0, pos);
373: }
374: }
375:
376: if (posDefault >= 0) {
377: // there was an explicit 'default' setting using the key, check where it ends
378: end = part.length();
379: if (posHelp > posDefault) {
380: end = posHelp;
381: }
382: if ((posOption > posDefault) && (posOption < end)) {
383: end = posOption;
384: }
385: if ((posValue > posDefault) && (posValue < end)) {
386: end = posValue;
387: }
388: String sub = part.substring(
389: posDefault + KEY_DEFAULT.length(), end)
390: .trim();
391: // cut of trailing '
392: sub = sub.substring(0, sub.length() - 1);
393: isDefault = Boolean.valueOf(sub).booleanValue();
394: } else {
395: // check for shortcut syntax, value must end with a '*'
396: if (value.charAt(value.length() - 1) == DEFAULT_MARKER) {
397: isDefault = true;
398: value = value.substring(0, value.length() - 1);
399: }
400: }
401:
402: if (posOption >= 0) {
403: // an 'option' setting is available, check where it ends
404: end = part.length();
405: if (posHelp > posOption) {
406: end = posHelp;
407: }
408: if ((posDefault > posOption) && (posDefault < end)) {
409: end = posDefault;
410: }
411: if ((posValue > posOption) && (posValue < end)) {
412: end = posValue;
413: }
414: if (shortOption) {
415: // shortcut syntax used for option with ':' appended to value
416: option = part.substring(posOption + 1, end)
417: .trim();
418: } else {
419: option = part.substring(
420: posOption + KEY_OPTION.length(), end)
421: .trim();
422: // cut of trailing '
423: option = option.substring(0,
424: option.length() - 1);
425: }
426: }
427:
428: if (posHelp >= 0) {
429: // a 'help' setting is available, check where it ends
430: end = part.length();
431: if (posOption > posHelp) {
432: end = posOption;
433: }
434: if ((posDefault > posHelp) && (posDefault < end)) {
435: end = posDefault;
436: }
437: if ((posValue > posHelp) && (posValue < end)) {
438: end = posValue;
439: }
440: help = part.substring(posHelp + KEY_HELP.length(),
441: end).trim();
442: // cut of trailing '
443: help = help.substring(0, help.length() - 1);
444: }
445:
446: // check if there was already a 'true' default, if so all other entries are 'false'
447: if (foundDefault) {
448: isDefault = false;
449: } else if (isDefault) {
450: foundDefault = true;
451: }
452:
453: result.add(new CmsSelectWidgetOption(value, isDefault,
454: option, help));
455:
456: } catch (Exception e) {
457: if (LOG.isInfoEnabled()) {
458: LOG.info(Messages.get().getBundle().key(
459: Messages.ERR_MALFORMED_SELECT_OPTIONS_1,
460: input));
461: }
462: }
463: }
464:
465: return result;
466: }
467:
468: /**
469: * @see java.lang.Object#equals(java.lang.Object)
470: */
471: public boolean equals(Object obj) {
472:
473: if (!(obj instanceof CmsSelectWidgetOption)) {
474: return false;
475: }
476: CmsSelectWidgetOption other = (CmsSelectWidgetOption) obj;
477: if (m_default != other.m_default) {
478: return false;
479: }
480: if (m_value == null) {
481: if (other.m_value != null) {
482: return false;
483: }
484: } else if (!m_value.equals(other.m_value)) {
485: return false;
486: }
487: if (m_option == null) {
488: if (other.m_option != null) {
489: return false;
490: }
491: } else if (!m_option.equals(other.m_option)) {
492: return false;
493: }
494: if (m_help == null) {
495: if (other.m_help != null) {
496: return false;
497: }
498: } else if (!m_help.equals(other.m_help)) {
499: return false;
500: }
501: return true;
502: }
503:
504: /**
505: * Returns the (optional) help text of this select option.<p>
506: *
507: * @return the (optional) help text of this select option
508: */
509: public String getHelp() {
510:
511: return m_help;
512: }
513:
514: /**
515: * Returns the option text of this select option.<p>
516: *
517: * If this has not been set, the result of <code>{@link #getValue()}</code> is returned,
518: * there will always be a result other than <code>null</code> returned.<p>
519: *
520: * @return the option text of this select option
521: */
522: public String getOption() {
523:
524: if (m_option == null) {
525: return getValue();
526: }
527: return m_option;
528: }
529:
530: /**
531: * Returns the value of this select option.<p>
532: *
533: * @return the value of this select option
534: */
535: public String getValue() {
536:
537: return m_value;
538: }
539:
540: /**
541: * @see java.lang.Object#hashCode()
542: */
543: public int hashCode() {
544:
545: if (m_hashcode == 0) {
546: StringBuffer hash = new StringBuffer(128);
547: hash.append(m_value);
548: hash.append('|');
549: hash.append(m_default);
550: hash.append('|');
551: hash.append(m_option);
552: hash.append('|');
553: hash.append(m_help);
554: m_hashcode = hash.toString().hashCode();
555: }
556: return m_hashcode;
557: }
558:
559: /**
560: * Returns <code>true</code> if this is the default value of the selection.<p>
561: *
562: * @return <code>true</code> if this is the default value of the selection
563: */
564: public boolean isDefault() {
565:
566: return m_default;
567: }
568:
569: /**
570: * @see java.lang.Object#toString()
571: */
572: public String toString() {
573:
574: StringBuffer result = new StringBuffer(128);
575:
576: result.append(KEY_VALUE);
577: result.append(m_value);
578: result.append('\'');
579: if (m_default) {
580: result.append(' ');
581: result.append(KEY_DEFAULT);
582: result.append(m_default);
583: result.append('\'');
584: }
585: if (m_option != null) {
586: result.append(' ');
587: result.append(KEY_OPTION);
588: result.append(m_option);
589: result.append('\'');
590: }
591: if (m_help != null) {
592: result.append(' ');
593: result.append(KEY_HELP);
594: result.append(m_help);
595: result.append('\'');
596: }
597: return result.toString();
598: }
599: }
|