001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.component;
042:
043: import java.io.IOException;
044: import javax.faces.component.UIComponent;
045: import javax.faces.context.FacesContext;
046: import javax.faces.el.MethodBinding;
047: import javax.faces.el.ValueBinding;
048:
049: /**
050: * <h4>About this tag</h4>
051: *
052: * <p>This tag renders two listboxes (one for available options, one
053: * for selected options) together with buttons to move the options
054: * between the lists, and optionally to order the selected options.
055: * Use the <code>items</code> attribute to associate the component
056: * with an array, collection or map of
057: * <code>com.sun.rave.web.ui.model.Option</code> and the
058: * <code>selected</code> attribute to associate the component with a
059: * model object that represents the selected items. The model object
060: * must be an array of objects, whose values must be represented by
061: * the values on the <code>com.sun.rave.web.ui.model.Option</code>s. </p>
062: *
063: * <h4>Component layout and Facet structure</h4>
064: * <p>The component can be laid out using either horizonal layout
065: * (the default) or vertical layout (if the <code>vertical</code>
066: * attribute is set to true).
067: *
068: * In the diagrams below, facet child
069: * components are shown as <span style="color:lightblue">light
070: * blue</span>. Non-facet areas are <span
071: * style="color:violet">violet</span>.</p>
072: *
073: * <h5>Horizontal layout</h5>
074: *
075: * <p> In horizontal layout, the component
076: * label (or header) may be shown either above the component
077: * (if the <code>labelOnTop</code>attribute is true) or next to the
078: * component as shown in the diagram.
079: * </p>
080: *
081: * <style type="text/css">
082: * table.AddRmvBtnTbl .Btn1 {width:100%}
083: * table.AddRmvBtnTbl .Btn1Hov {width:100%}
084: * table.AddRmvBtnTbl .Btn1Dis {width:100%}
085: * table.AddRmvBtnTbl .Btn2 {width:100%}
086: * table.AddRmvBtnTbl .Btn2Hov {width:100%}
087: * table.AddRmvBtnTbl .Btn2Dis {width:100%}
088: * .AddRmvHrzWin, .AddRmvHrzBwn {margin-top:3px}
089: * .AddRmvHrzDiv {float:left; display:inline-table; margin:3px}
090: * .AddRmvHrzLst {display:inline-table; margin:3px}
091: * select {margin:3px}
092: * .spacer {margin:3px}
093: * </style>
094: *
095: * <div id="addremove1:list_enclosing">
096: * <span class="AddRmvHrzDiv">
097: * <span style="background:lightblue">header</span>
098: * </span>
099: *
100: * <span class="AddRmvHrzDiv"> </span>
101: *
102: * <div class="AddRmvHrzDiv">
103: * <span style="background:lightblue">availableLabel</span>
104: * <br />
105: * <select style="background:violet" size="12">
106: * <option>List of available items</option>
107: * </select>
108: * </div>
109: * <div class="AddRmvHrzDiv">
110: * <span> </span>
111: * <br />
112: *
113: * <div style="padding-left:10;padding-right:10">
114: * <table class="AddRmvBtnTbl">
115: * <tr>
116: * <td align="center" width="125px">
117: *
118: * <span style="background:lightblue"> addButton </span>
119: *
120: * <div class="AddRmvHrzWin">
121: * <span style="background:lightblue"> addAllButton </span>
122: * </div>
123: *
124: * <div class="AddRmvHrzBwn">
125: * <span style="background:lightblue"> removeButton </span>
126: * </div>
127: *
128: * <div class="AddRmvHrzBwn">
129: * <span style="background:lightblue"> removeAllButton </span>
130: * </div>
131: *
132: * <div class="AddRmvHrzBwn">
133: * <span style="background:lightblue"> moveUpButton </span>
134: * </div>
135: *
136: * <div class="AddRmvHrzBwn">
137: * <span style="background:lightblue"> moveDownButton </span>
138: * </div>
139: *
140: * </td>
141: * </tr>
142: * </table>
143: * </div>
144: * </div>
145: *
146: * <div class="AddRmvHrzLst">
147: * <span style="background:lightblue">selectedLabel</span>
148: * <br />
149: * <select style="background:violet" size="12">
150: * <option>List of selected items</option>
151: * </select>
152: * </div>
153: * </div>
154: * <span> </span>
155: * <div>
156: * <span style="background:lightblue">
157: * footer
158: * </span>
159: *
160: * </div>
161: *
162: *
163: * <h5>Vertical layout</h5>
164: *
165: *
166: * <div id="addremove1:list_enclosing">
167: *
168: * <div class="spacer">
169: * <span style="background:lightblue">header</span>
170: * </div>
171: *
172: * <div class="spacer">
173: * <span style="background:lightblue">availableLabel</span>
174: * <br />
175: * <select style="background:violet" size="12">
176: * <option>List of available items</option>
177: * </select>
178: * </div>
179: *
180: * <div class="spacer">
181: * <span style="background:lightblue"> addButton </span>
182: *
183: * <span>
184: *
185: * <span style="background:lightblue"> addAllButton </span>
186: *
187: * <span>
188: *
189: * <span style="background:lightblue"> removeButton </span>
190: *
191: * <span>
192: *
193: * <span style="background:lightblue"> removeAllButton </span>
194: *
195: *
196: * <div class="spacer">
197: * <span style="background:lightblue">selectedLabel</span>
198: * <br />
199: * <select style="background:violet" size="12">
200: * <option>List of selected items</option>
201: * </select>
202: * </div>
203: *
204: *
205: * <div class="spacer">
206: * <span style="background:lightblue"> moveUpButton </span>
207: *
208: * <span> </span>
209: *
210: * <span style="background:lightblue"> moveDownButton </span>
211: * </div>
212: * </div>
213: * <div>
214: * <span style="background:lightblue">
215: * footer
216: * </span>
217: *
218: * </div>
219: *
220: *
221: *
222: *
223: * <h4>Facets</h4>
224: *
225: * <ul>
226: *
227: * <li>
228: * <code>addButton:</code>
229: * Use this facet to replace the standard "Add" button. If
230: * you use a facet to replace this component, the JSF ID of this
231: * component should be the ID given to the AddRemove component with
232: * <code>_addButton</code> appended at the end. If you wish to use the
233: * JavaScript function associated with the default button, use the <code>
234: * add()</code> function. See the section on JavaScript for details.
235: * </li>
236: *
237: * <li>
238: * <code>removeButton:</code>
239: * Use this facet to replace the standard "Remove"
240: * button. If
241: * you use a facet to replace this component, the JSF ID of this
242: * component should be the ID given to the AddRemove component with
243: * <code>_removeButton</code> appended at the end. If you wish to use the
244: * JavaScript function associated with the default button, use the <code>
245: * remove()</code> function. See the section on JavaScript for details.
246: * </li>
247: *
248: * <li>
249: * <code>addAllButton:</code>
250: * Use this facet to replace the standard "Add All"
251: * button. If
252: * you use a facet to replace this component, the JSF ID of this
253: * component should be the ID given to the AddRemove component with
254: * <code>_addAllButton</code> appended at the end. If you wish to use the
255: * JavaScript function associated with the default button, use the <code>
256: * addAll()</code> function. See the section on JavaScript for details.
257: * </li>
258: *
259: * <li>
260: * <code>removeAllButton:</code>
261: * Use this facet to replace the standard "Remove All"
262: * button. If
263: * you use a facet to replace this component, the JSF ID of this
264: * component should be the ID given to the AddRemove component with
265: * <code>_removeAllButton</code> appended at the end. If you wish to use the
266: * JavaScript function associated with the default button, use the <code>
267: * removeAll()</code> function. See the section on JavaScript for details.
268: * </li>
269: *
270: *
271: * <li>
272: * <code>moveUpButton:</code>
273: * Use this facet to replace the standard "Move Up"
274: * button. If
275: * you use a facet to replace this component, the JSF ID of this
276: * component should be the ID given to the AddRemove component with
277: * <code>_moveUpButton</code> appended at the end. If you wish to use the
278: * JavaScript function associated with the default button, use the <code>
279: * moveUp()</code> function. See the section on JavaScript for details.
280: * </li>
281: *
282: * <li>
283: * <code>moveDownButton:</code>
284: * Use this facet to replace the standard "Move Down"
285: * button. If
286: * you use a facet to replace this component, the JSF ID of this
287: * component should be the ID given to the AddRemove component with
288: * <code>_moveDownButton</code> appended at the end. If you wish to use the
289: * JavaScript function associated with the default button, use the <code>
290: * moveDown()</code> function. See the section on JavaScript for details.
291: * </li>
292: *
293: * <li>
294: * <code>header:</code>
295: * Use this facet to create a header for the
296: * component. The facet will replace the component label.
297: * </li>
298: *
299: * <li>
300: * <code>footer:</code>
301: * Use this facet to create a footer for the
302: * component.
303: *
304: * </li>
305: * </ul>
306: *
307: * <h4>Client-side JavaScript functions</h4>
308: *
309: * <p>When the component is rendered, a JavaScript object corresponding
310: * to the component is created. The name of the variable is AddRemove_
311: * followed by the component's DOM id where the colons have been replaced
312: * by underscores. For example, if the id of the component is
313: * <code>listform:addremove</code> then the JavaScript variable name will
314: * be <code>AddRemove_listform_addremove</code>. To manipulate the
315: * component on the client side, you may invoke functions on the
316: * JavaScript object. With reference to the id above, to add all elements
317: * on the available list that the user has selected, invoke
318: * <code> AddRemove_listform_addremove.add()</code>.
319: * </p>
320: *
321: * <ul>
322: * <li><code>add()</code>: the highlighted items on the available list
323: * are moved to the selected list. </li>
324: * <li><code>addAll()</code>: all non-disabled items on the available list
325: * are moved to the selected list. </li>
326: * <li><code>remove()</code>: the highlighted items on the selected list
327: * are moved to the available list. </li>
328: * <li><code>removeAll()</code>: all non-disabled items on the selected list
329: * are moved to the available list. </li>
330: * <li><code>moveUp()</code>: the highlighted items on the selected list
331: * are moved up one position. </li>
332: * <li><code>moveDown()</code>: the highlighted items on the selected list
333: * are moved down one position. </li>
334: * <li><code>updateButtons()</code>: this function ensures that the
335: * buttons are enabled/disabled based on the current selections in
336: * the lists. Invoke this function if you programmatically modify the
337: * selections on the available or selected list using client-side
338: * scripts. You do not need to invoke it when using any of the
339: * functions listed above, as they already invoke this function at
340: * the end. </li>
341: * </ul>
342: *
343: * <h4>Configuring the AddRemove tag</h4>
344: *
345: * <h4>Examples</h4>
346: * <p>The component gets the options from a managed bean called
347: * AirportBean. The selections are stored in another managed bean
348: * (AirportSelectionBean). The <code>selectAll</code> attribute indicates that the
349: * <code>Add All</code> and <code>Remove All</code> buttons should be
350: * shown. A label for the component as a whole (<code>label</code>) is shown
351: * next to the component (<code>labelOnTop</code> is false). Labels have
352: * been specified for the list of available items and for the list of
353: * selected items. The <code>sorted</code> attribute indicates that the options on
354: * the list will be shown in alphabetical order.</p>
355: * <pre>
356: * <ui:addRemove id="list"
357: * items="#{AirportBean.airports}"
358: * selected="#{AirportSelectionBean.airportSel}"
359: * label="Select airports"
360: * availableItemsLabel="Available Airports"
361: * selectedItemsLabel="Selected Airports"
362: * selectAll="true"
363: * sorted="true"
364: * labelOnTop="false"/>
365: * </pre>
366: *
367: * <p>As in the previous example, with the following exceptions: The
368: * component is rendered using vertical layout (in this case, the main
369: * component label is always rendered above the component).
370: * The <code>moveButtons</code> attribute indicates that the
371: * <code>Move Up</code> and <code>Move Down</code> buttons should be
372: * shown. </p>
373: * <pre>
374: * <ui:addRemove id="list"
375: * items="#{AirportBean.airports}"
376: * selected="#{AirportSelectionBean.airportSel}"
377: * label="Select some names"
378: * availableItemsLabel="Available Names"
379: * selectedItemsLabel="Selected Names"
380: * selectAll="true"
381: * moveButtons="true"
382: * vertical="true"/>
383: * </pre>
384: * <p>Auto-generated component class.
385: * Do <strong>NOT</strong> modify; all changes
386: * <strong>will</strong> be lost!</p>
387: */
388:
389: public abstract class AddRemoveBase extends
390: com.sun.rave.web.ui.component.ListSelector {
391:
392: /**
393: * <p>Construct a new <code>AddRemoveBase</code>.</p>
394: */
395: public AddRemoveBase() {
396: super ();
397: setRendererType("com.sun.rave.web.ui.AddRemove");
398: }
399:
400: /**
401: * <p>Return the identifier of the component family to which this
402: * component belongs. This identifier, in conjunction with the value
403: * of the <code>rendererType</code> property, may be used to select
404: * the appropriate {@link Renderer} for this component instance.</p>
405: */
406: public String getFamily() {
407: return "com.sun.rave.web.ui.AddRemove";
408: }
409:
410: // availableItemsLabel
411: private String availableItemsLabel = null;
412:
413: /**
414: * <p>The label for the available list</p>
415: */
416: public String getAvailableItemsLabel() {
417: if (this .availableItemsLabel != null) {
418: return this .availableItemsLabel;
419: }
420: ValueBinding _vb = getValueBinding("availableItemsLabel");
421: if (_vb != null) {
422: return (String) _vb.getValue(getFacesContext());
423: }
424: return null;
425: }
426:
427: /**
428: * <p>The label for the available list</p>
429: * @see #getAvailableItemsLabel()
430: */
431: public void setAvailableItemsLabel(String availableItemsLabel) {
432: this .availableItemsLabel = availableItemsLabel;
433: }
434:
435: // duplicateSelections
436: private boolean duplicateSelections = false;
437: private boolean duplicateSelections_set = false;
438:
439: /**
440: * <p>Set this attribute to true if the component should allow items
441: * from the available list to be added more than one to the
442: * selected list, that is, if the selected list should allow duplicate entries.</p>
443: */
444: public boolean isDuplicateSelections() {
445: if (this .duplicateSelections_set) {
446: return this .duplicateSelections;
447: }
448: ValueBinding _vb = getValueBinding("duplicateSelections");
449: if (_vb != null) {
450: Object _result = _vb.getValue(getFacesContext());
451: if (_result == null) {
452: return false;
453: } else {
454: return ((Boolean) _result).booleanValue();
455: }
456: }
457: return false;
458: }
459:
460: /**
461: * <p>Set this attribute to true if the component should allow items
462: * from the available list to be added more than one to the
463: * selected list, that is, if the selected list should allow duplicate entries.</p>
464: * @see #isDuplicateSelections()
465: */
466: public void setDuplicateSelections(boolean duplicateSelections) {
467: this .duplicateSelections = duplicateSelections;
468: this .duplicateSelections_set = true;
469: }
470:
471: // moveButtons
472: private boolean moveButtons = false;
473: private boolean moveButtons_set = false;
474:
475: /**
476: * <p>Show the Move Up and Move Down buttons</p>
477: */
478: public boolean isMoveButtons() {
479: if (this .moveButtons_set) {
480: return this .moveButtons;
481: }
482: ValueBinding _vb = getValueBinding("moveButtons");
483: if (_vb != null) {
484: Object _result = _vb.getValue(getFacesContext());
485: if (_result == null) {
486: return false;
487: } else {
488: return ((Boolean) _result).booleanValue();
489: }
490: }
491: return false;
492: }
493:
494: /**
495: * <p>Show the Move Up and Move Down buttons</p>
496: * @see #isMoveButtons()
497: */
498: public void setMoveButtons(boolean moveButtons) {
499: this .moveButtons = moveButtons;
500: this .moveButtons_set = true;
501: }
502:
503: // selectAll
504: private boolean selectAll = false;
505: private boolean selectAll_set = false;
506:
507: /**
508: * <p>Show the Add All and Remove All buttons</p>
509: */
510: public boolean isSelectAll() {
511: if (this .selectAll_set) {
512: return this .selectAll;
513: }
514: ValueBinding _vb = getValueBinding("selectAll");
515: if (_vb != null) {
516: Object _result = _vb.getValue(getFacesContext());
517: if (_result == null) {
518: return false;
519: } else {
520: return ((Boolean) _result).booleanValue();
521: }
522: }
523: return false;
524: }
525:
526: /**
527: * <p>Show the Add All and Remove All buttons</p>
528: * @see #isSelectAll()
529: */
530: public void setSelectAll(boolean selectAll) {
531: this .selectAll = selectAll;
532: this .selectAll_set = true;
533: }
534:
535: // selectedItemsLabel
536: private String selectedItemsLabel = null;
537:
538: /**
539: * <p>The label for the selected list</p>
540: */
541: public String getSelectedItemsLabel() {
542: if (this .selectedItemsLabel != null) {
543: return this .selectedItemsLabel;
544: }
545: ValueBinding _vb = getValueBinding("selectedItemsLabel");
546: if (_vb != null) {
547: return (String) _vb.getValue(getFacesContext());
548: }
549: return null;
550: }
551:
552: /**
553: * <p>The label for the selected list</p>
554: * @see #getSelectedItemsLabel()
555: */
556: public void setSelectedItemsLabel(String selectedItemsLabel) {
557: this .selectedItemsLabel = selectedItemsLabel;
558: }
559:
560: // sorted
561: private boolean sorted = false;
562: private boolean sorted_set = false;
563:
564: /**
565: * <p>If true, the items on the available options list are shown in alphabetical
566: * order. The item on the selected options list are also shown in alphabetical order,
567: * unless the moveButtons attribute is true, in which case the user is expected to
568: * order the elements.</p>
569: */
570: public boolean isSorted() {
571: if (this .sorted_set) {
572: return this .sorted;
573: }
574: ValueBinding _vb = getValueBinding("sorted");
575: if (_vb != null) {
576: Object _result = _vb.getValue(getFacesContext());
577: if (_result == null) {
578: return false;
579: } else {
580: return ((Boolean) _result).booleanValue();
581: }
582: }
583: return false;
584: }
585:
586: /**
587: * <p>If true, the items on the available options list are shown in alphabetical
588: * order. The item on the selected options list are also shown in alphabetical order,
589: * unless the moveButtons attribute is true, in which case the user is expected to
590: * order the elements.</p>
591: * @see #isSorted()
592: */
593: public void setSorted(boolean sorted) {
594: this .sorted = sorted;
595: this .sorted_set = true;
596: }
597:
598: // toolTip
599: private String toolTip = null;
600:
601: /**
602: * <p>Display the text as a tooltip for this component</p>
603: */
604: public String getToolTip() {
605: if (this .toolTip != null) {
606: return this .toolTip;
607: }
608: ValueBinding _vb = getValueBinding("toolTip");
609: if (_vb != null) {
610: return (String) _vb.getValue(getFacesContext());
611: }
612: return null;
613: }
614:
615: /**
616: * <p>Display the text as a tooltip for this component</p>
617: * @see #getToolTip()
618: */
619: public void setToolTip(String toolTip) {
620: this .toolTip = toolTip;
621: }
622:
623: // vertical
624: private boolean vertical = false;
625: private boolean vertical_set = false;
626:
627: /**
628: * <p>Use vertical layout instead of the default horizontal one</p>
629: */
630: public boolean isVertical() {
631: if (this .vertical_set) {
632: return this .vertical;
633: }
634: ValueBinding _vb = getValueBinding("vertical");
635: if (_vb != null) {
636: Object _result = _vb.getValue(getFacesContext());
637: if (_result == null) {
638: return false;
639: } else {
640: return ((Boolean) _result).booleanValue();
641: }
642: }
643: return false;
644: }
645:
646: /**
647: * <p>Use vertical layout instead of the default horizontal one</p>
648: * @see #isVertical()
649: */
650: public void setVertical(boolean vertical) {
651: this .vertical = vertical;
652: this .vertical_set = true;
653: }
654:
655: /**
656: * <p>Restore the state of this component.</p>
657: */
658: public void restoreState(FacesContext _context, Object _state) {
659: Object _values[] = (Object[]) _state;
660: super .restoreState(_context, _values[0]);
661: this .availableItemsLabel = (String) _values[1];
662: this .duplicateSelections = ((Boolean) _values[2])
663: .booleanValue();
664: this .duplicateSelections_set = ((Boolean) _values[3])
665: .booleanValue();
666: this .moveButtons = ((Boolean) _values[4]).booleanValue();
667: this .moveButtons_set = ((Boolean) _values[5]).booleanValue();
668: this .selectAll = ((Boolean) _values[6]).booleanValue();
669: this .selectAll_set = ((Boolean) _values[7]).booleanValue();
670: this .selectedItemsLabel = (String) _values[8];
671: this .sorted = ((Boolean) _values[9]).booleanValue();
672: this .sorted_set = ((Boolean) _values[10]).booleanValue();
673: this .toolTip = (String) _values[11];
674: this .vertical = ((Boolean) _values[12]).booleanValue();
675: this .vertical_set = ((Boolean) _values[13]).booleanValue();
676: }
677:
678: /**
679: * <p>Save the state of this component.</p>
680: */
681: public Object saveState(FacesContext _context) {
682: Object _values[] = new Object[14];
683: _values[0] = super .saveState(_context);
684: _values[1] = this .availableItemsLabel;
685: _values[2] = this .duplicateSelections ? Boolean.TRUE
686: : Boolean.FALSE;
687: _values[3] = this .duplicateSelections_set ? Boolean.TRUE
688: : Boolean.FALSE;
689: _values[4] = this .moveButtons ? Boolean.TRUE : Boolean.FALSE;
690: _values[5] = this .moveButtons_set ? Boolean.TRUE
691: : Boolean.FALSE;
692: _values[6] = this .selectAll ? Boolean.TRUE : Boolean.FALSE;
693: _values[7] = this .selectAll_set ? Boolean.TRUE : Boolean.FALSE;
694: _values[8] = this .selectedItemsLabel;
695: _values[9] = this .sorted ? Boolean.TRUE : Boolean.FALSE;
696: _values[10] = this .sorted_set ? Boolean.TRUE : Boolean.FALSE;
697: _values[11] = this .toolTip;
698: _values[12] = this .vertical ? Boolean.TRUE : Boolean.FALSE;
699: _values[13] = this.vertical_set ? Boolean.TRUE : Boolean.FALSE;
700: return _values;
701: }
702:
703: }
|