View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.datascroller;
20  
21  import javax.faces.FacesException;
22  import javax.faces.component.ActionSource;
23  import javax.faces.component.UIComponent;
24  import javax.faces.component.UIData;
25  import javax.faces.component.UIPanel;
26  import javax.faces.context.FacesContext;
27  import javax.faces.el.EvaluationException;
28  import javax.faces.el.MethodBinding;
29  import javax.faces.el.ValueBinding;
30  import javax.faces.event.AbortProcessingException;
31  import javax.faces.event.ActionEvent;
32  import javax.faces.event.ActionListener;
33  import javax.faces.event.FacesEvent;
34  import javax.faces.event.PhaseId;
35  
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.apache.myfaces.component.DisplayValueOnlyAware;
39  import org.apache.myfaces.component.ForceIdAware;
40  import org.apache.myfaces.component.StyleAware;
41  import org.apache.myfaces.component.UniversalProperties;
42  import org.apache.myfaces.component.UserRoleAware;
43  import org.apache.myfaces.component.UserRoleUtils;
44  import org.apache.myfaces.component.html.util.HtmlComponentUtils;
45  import org.apache.myfaces.shared_tomahawk.component.DisplayValueOnlyCapable;
46  
47  /**
48   * Scroller for UIData components eg. dataTable
49   *
50   * Must be nested inside footer facet of dataTable OR for
51   * attribute must be given so that corresponding uiData can be found.
52   *
53   * Unless otherwise specified, all attributes accept static values or EL expressions.
54   *
55   * A component which works together with a UIData component to allow a
56   * user to view a large list of data one "page" at a time, and navigate
57   * between pages.
58   *
59   * @JSFComponent
60   *   name = "t:dataScroller"
61   *   class = "org.apache.myfaces.custom.datascroller.HtmlDataScroller"
62   *   tagClass = "org.apache.myfaces.custom.datascroller.HtmlDataScrollerTag"
63   * @since 1.1.7
64   * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
65   * @version $Revision: 955086 $ $Date: 2010-06-15 18:32:00 -0500 (Tue, 15 Jun 2010) $
66   */
67  public abstract class AbstractHtmlDataScroller extends UIPanel
68      implements ActionSource, UserRoleAware, DisplayValueOnlyCapable,
69      DisplayValueOnlyAware, ForceIdAware, UniversalProperties, StyleAware
70  {
71  
72      public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataScroller";
73      public static final String COMPONENT_FAMILY = "javax.faces.Panel";
74      private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.DataScroller";
75      private static final boolean DEFAULT_IMMEDIATE = false;
76  
77      private static final Log log = LogFactory.getLog(AbstractHtmlDataScroller.class);
78  
79      private static final String FIRST_FACET_NAME = "first";
80      private static final String LAST_FACET_NAME = "last";
81      private static final String NEXT_FACET_NAME = "next";
82      private static final String PREVIOUS_FACET_NAME = "previous";
83      private static final String FAST_FORWARD_FACET_NAME = "fastforward";
84      private static final String FAST_REWIND_FACET_NAME = "fastrewind";
85  
86      public static final String FACET_FIRST = "first".intern();
87      public static final String FACET_PREVIOUS = "previous".intern();
88      public static final String FACET_NEXT = "next".intern();
89      public static final String FACET_LAST = "last".intern();
90      public static final String FACET_FAST_FORWARD = "fastf".intern();
91      public static final String FACET_FAST_REWIND = "fastr".intern();
92  
93      private static final String TABLE_LAYOUT = "table";
94      private static final String LIST_LAYOUT = "list";
95      private static final String SINGLE_LIST_LAYOUT = "singleList";
96      private static final String SINGLE_TABLE_LAYOUT = "singleTable";
97  
98      // just for caching the associated uidata
99      private transient UIData _UIData;
100 
101     private transient Boolean _listLayout;
102 
103     private transient Boolean _singleElementLayout;
104 
105     private MethodBinding _actionListener;
106 
107     public String getClientId(FacesContext context)
108     {
109         String clientId = HtmlComponentUtils.getClientId(this, getRenderer(context), context);
110         if (clientId == null)
111         {
112             clientId = super.getClientId(context);
113         }
114 
115         return clientId;
116     }
117 
118     public boolean isRendered()
119     {
120         if (!UserRoleUtils.isVisibleOnUserRole(this)) return false;
121         return super.isRendered();
122     }
123 
124     public boolean isSetDisplayValueOnly(){
125         return getDisplayValueOnly() != null ? true : false;
126     }
127 
128     public boolean isDisplayValueOnly(){
129         return getDisplayValueOnly() != null ? getDisplayValueOnly().booleanValue() : false;
130     }
131 
132     public void setDisplayValueOnly(boolean displayValueOnly){
133         this.setDisplayValueOnly((Boolean) Boolean.valueOf(displayValueOnly));
134     }
135 
136     /**
137      *  The layout this scroller should render with. Default is 'table',
138      *  'list' is implemented as well. Additionally you can use
139      *  'singleList' - then the data-scroller will render a list, but
140      *  not the paginator - same with the value 'singleTable'.
141      *
142      * @JSFProperty
143      *   defaultValue = "table"
144      */
145     public abstract String getLayout();
146 
147     /**
148      * standard html colspan attribute for table cell
149      *
150      * @JSFProperty
151      *   defaultValue = "Integer.MIN_VALUE"
152      */
153     public abstract int getColspan();
154 
155     /**
156      * HTML: Script to be invoked when the element is clicked.
157      *
158      * @JSFProperty
159      */
160     public abstract String getOnclick();
161 
162     /**
163      * HTML: Script to be invoked when the element is double-clicked.
164      *
165      * @JSFProperty
166      */
167     public abstract String getOndblclick();
168 
169     public boolean isListLayout()
170     {
171         if(_listLayout == null)
172         {
173             String layout=getLayout();
174             if(layout == null || layout.equals(TABLE_LAYOUT) || layout.equals(SINGLE_TABLE_LAYOUT))
175                 _listLayout = Boolean.FALSE;
176             else if(layout.equals(LIST_LAYOUT) || layout.equals(SINGLE_LIST_LAYOUT))
177             {
178                 _listLayout = Boolean.TRUE;
179             }
180             else
181             {
182                 log.error("Invalid layout-parameter : "+layout +" provided. Defaulting to table-layout.");
183                 _listLayout = Boolean.FALSE;
184             }
185         }
186 
187         return _listLayout.booleanValue();
188     }
189 
190     public boolean isSingleElementLayout()
191     {
192         if(_singleElementLayout == null)
193         {
194             String layout=getLayout();
195             if(layout == null || layout.equals(SINGLE_LIST_LAYOUT) || layout.equals(SINGLE_TABLE_LAYOUT))
196                 _singleElementLayout = Boolean.TRUE;
197             else
198                 _singleElementLayout = Boolean.FALSE;
199         }
200 
201         return _singleElementLayout.booleanValue();
202     }
203 
204     /**
205      * Catch any attempts to queue events for this component, and ensure
206      * the event's phase is set appropriately. Events are expected to be
207      * queued by this component's renderer.
208      * <p>
209      * When this component is marked "immediate", any ActionEvent will
210      * be marked to fire in the "apply request values" phase. When this
211      * component is not immediate the event will fire during the
212      * "invoke application" phase instead.
213      */
214     public void queueEvent(FacesEvent event)
215     {
216         if (event != null && event instanceof ActionEvent)
217         {
218             if (isImmediate())
219             {
220                 event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
221             }
222             else
223             {
224                 event.setPhaseId(PhaseId.INVOKE_APPLICATION);
225             }
226         }
227         super.queueEvent(event);
228     }
229 
230     /**
231      * Invoke any action listeners attached to this class.
232      * <p>
233      * After listener invocation, the associated UIData's properties get
234      * updated:
235      * <ul>
236      * <li>if the user selected an absolute page# then setFirst is called with
237      * uiData.getRows() * pageNumber.
238      * <li>if the user selected the "first page" option then setFirst(0) is called.
239      * <li>if the user selected the "previous page" option then setFirst is decremented
240      * by uiData.getRows().
241      * <li>if the user selected the "fast rewind" option then setFirst is decremented
242      * by uiData.getRows() * fastStep.
243      * <li>next, fast-forward and last options have the obvious effect.
244      * </ul>
245      */
246     public void broadcast(FacesEvent event) throws AbortProcessingException
247     {
248         super.broadcast(event);
249 
250         if (event instanceof ScrollerActionEvent)
251         {
252             ScrollerActionEvent scrollerEvent = (ScrollerActionEvent) event;
253 
254             // huh? getUIData never returns null.
255             UIData uiData = getUIData();
256             if (uiData == null)
257             {
258                 return;
259             }
260 
261             int pageindex = scrollerEvent.getPageIndex();
262             if (pageindex == -1)
263             {
264                 String facet = scrollerEvent.getScrollerfacet();
265                 if (FACET_FIRST.equals(facet))
266                 {
267                     setFirst(uiData, 0);
268                 }
269                 else if (FACET_PREVIOUS.equals(facet))
270                 {
271                     int previous = uiData.getFirst() - uiData.getRows();
272                     if (previous >= 0)
273                         setFirst(uiData, previous);
274                 }
275                 else if (FACET_NEXT.equals(facet))
276                 {
277                     int next = uiData.getFirst() + uiData.getRows();
278                     if (next < uiData.getRowCount())
279                         setFirst(uiData, next);
280                 }
281                 else if (FACET_FAST_FORWARD.equals(facet))
282                 {
283                     int fastStep = getFastStep();
284                     if (fastStep <= 0)
285                         fastStep = 1;
286                     int next = uiData.getFirst() + uiData.getRows() * fastStep;
287                     int rowcount = uiData.getRowCount();
288                     if (next >= rowcount)
289                         next = (rowcount - 1) - ((rowcount - 1) % uiData.getRows());
290                     setFirst(uiData, next);
291                 }
292                 else if (FACET_FAST_REWIND.equals(facet))
293                 {
294                     int fastStep = getFastStep();
295                     if (fastStep <= 0)
296                         fastStep = 1;
297                     int previous = uiData.getFirst() - uiData.getRows() * fastStep;
298                     if (previous < 0)
299                         previous = 0;
300                     setFirst(uiData, previous);
301                 }
302                 else if (FACET_LAST.equals(facet))
303                 {
304                     int rowcount = uiData.getRowCount();
305                     int rows = uiData.getRows();
306                     int delta = (rows != 0) ? (rowcount % rows) : 0;
307                     int first = delta > 0 && delta < rows ? rowcount - delta : rowcount - rows;
308                     if (first >= 0)
309                     {
310                         setFirst(uiData, first);
311                     }
312                     else
313                     {
314                         setFirst(uiData, 0);
315                     }
316                 }
317             }
318             else
319             {
320                 int pageCount = getPageCount();
321                 if (pageindex > pageCount)
322                 {
323                     pageindex = pageCount;
324                 }
325                 if (pageindex <= 0)
326                 {
327                     pageindex = 1;
328                 }
329                 setFirst(uiData, uiData.getRows() * (pageindex - 1));
330             }
331             broadcastToActionListener(scrollerEvent);
332         }
333     }
334 
335     protected void setFirst(UIData uiData, int value) {
336         //there might be special cases where the first-property of the data-table
337         //is bound to a backing bean. If this happens, the user probably wants
338         //the data-scroller to update this backing-bean value - if not, you can always
339         //override this method in a subclass.
340         if(uiData.getValueBinding("first")!=null)
341         {
342             ValueBinding vb = uiData.getValueBinding("first");
343             vb.setValue(getFacesContext(),new Integer(value));
344         }
345         else
346         {
347             uiData.setFirst(value);
348         }
349     }
350 
351     /**
352      * @param event
353      */
354     protected void broadcastToActionListener(ScrollerActionEvent event)
355     {
356         FacesContext context = getFacesContext();
357 
358         MethodBinding actionListenerBinding = getActionListener();
359         if (actionListenerBinding != null)
360         {
361             try
362             {
363                 actionListenerBinding.invoke(context, new Object[] {event});
364             }
365             catch (EvaluationException e)
366             {
367                 Throwable cause = e.getCause();
368                 if (cause != null && cause instanceof AbortProcessingException)
369                 {
370                     throw (AbortProcessingException)cause;
371                 }
372                 throw e;
373             }
374         }
375 
376         ActionListener defaultActionListener
377                 = context.getApplication().getActionListener();
378         if (defaultActionListener != null)
379         {
380             defaultActionListener.processAction((ActionEvent)event);
381         }
382     }
383 
384     /**
385      * @return int
386      */
387     public UIData getUIData()
388     {
389         if (_UIData == null)
390         {
391             _UIData = findUIData();
392         }
393         return _UIData;
394     }
395 
396     /**
397      * @return the page index of the uidata
398      */
399     public int getPageIndex()
400     {
401         UIData uiData = getUIData();
402         int rows = uiData.getRows();
403         if (0 == rows)
404         {
405             throw new FacesException("You need to set a value to the 'rows' attribute of component '" + uiData.getClientId(getFacesContext()) + "'" );
406         }
407 
408         int pageIndex;
409         if (rows > 0)
410         {
411             pageIndex = uiData.getFirst() / rows + 1;
412         }
413         else
414         {
415             log.warn("DataTable " + uiData.getClientId(FacesContext.getCurrentInstance())
416                             + " has invalid rows attribute.");
417             pageIndex = 0;
418         }
419         if (uiData.getFirst() % rows > 0)
420         {
421             pageIndex++;
422         }
423         return pageIndex;
424     }
425 
426     /**
427      * @return the page count of the uidata
428      */
429     public int getPageCount()
430     {
431         UIData uiData = getUIData();
432         int rows = uiData.getRows();
433         int pageCount;
434         if (rows > 0)
435         {
436             pageCount = rows <= 0 ? 1 : uiData.getRowCount() / rows;
437             if (uiData.getRowCount() % rows > 0)
438             {
439                 pageCount++;
440             }
441         }
442         else
443         {
444             rows = 1;
445             pageCount = 1;
446         }
447         return pageCount;
448     }
449 
450     /**
451      * @return int
452      */
453     public int getRowCount()
454     {
455         return getUIData().getRowCount();
456     }
457 
458     /**
459      * @return int
460      */
461     public int getRows()
462     {
463         return getUIData().getRows();
464     }
465 
466     /**
467      * @return int
468      */
469     public int getFirstRow()
470     {
471         return getUIData().getFirst();
472     }
473 
474     /**
475      * Find the UIData component associated with this scroller.
476      * <p>
477      * If the "for" attribute is not null then that value is used to find the
478      * specified component by id. Both "relative" and "absolute" ids are allowed;
479      * see method UIComponent.findComponent for details.
480      * <p>
481      * If the "for" attribute is not defined, then this component is expected to
482      * be a child of a UIData component.
483      *
484      * @throws IllegalArgumentException if an associated UIData component
485      * cannot be found.
486      */
487     protected UIData findUIData()
488     {
489         String forStr = getFor();
490         UIComponent forComp;
491         if (forStr == null)
492         {
493             // DataScroller may be a child of uiData
494             forComp = getParent();
495         }
496         else
497         {
498             forComp = findComponent(forStr);
499         }
500         if (forComp == null)
501         {
502             throw new IllegalArgumentException(
503                     "could not find UIData referenced by attribute dataScroller@for = '"
504                     + forStr + "'");
505         }
506         else if (!(forComp instanceof UIData))
507         {
508             throw new IllegalArgumentException(
509                 "uiComponent referenced by attribute dataScroller@for = '"
510                 + forStr + "' must be of type " + UIData.class.getName()
511                 + ", not type " + forComp.getClass().getName());
512         }
513         return (UIData) forComp;
514     }
515 
516     public void setFirst(UIComponent first)
517     {
518         getFacets().put(FIRST_FACET_NAME, first);
519     }
520 
521     /**
522      * @JSFFacet
523      */
524     public UIComponent getFirst()
525     {
526         return (UIComponent) getFacets().get(FIRST_FACET_NAME);
527     }
528 
529     public void setLast(UIComponent last)
530     {
531         getFacets().put(LAST_FACET_NAME, last);
532     }
533 
534     /**
535      * @JSFFacet
536      */
537     public UIComponent getLast()
538     {
539         return (UIComponent) getFacets().get(LAST_FACET_NAME);
540     }
541 
542     public void setNext(UIComponent next)
543     {
544         getFacets().put(NEXT_FACET_NAME, next);
545     }
546 
547     /**
548      * @JSFFacet
549      */
550     public UIComponent getNext()
551     {
552         return (UIComponent) getFacets().get(NEXT_FACET_NAME);
553     }
554 
555     public void setFastForward(UIComponent previous)
556     {
557         getFacets().put(FAST_FORWARD_FACET_NAME, previous);
558     }
559 
560     /**
561      * @JSFFacet
562      */
563     public UIComponent getFastForward()
564     {
565         return (UIComponent) getFacets().get(FAST_FORWARD_FACET_NAME);
566     }
567 
568     public void setFastRewind(UIComponent previous)
569     {
570         getFacets().put(FAST_REWIND_FACET_NAME, previous);
571     }
572 
573     /**
574      * @JSFFacet
575      */
576     public UIComponent getFastRewind()
577     {
578         return (UIComponent) getFacets().get(FAST_REWIND_FACET_NAME);
579     }
580 
581     public void setPrevious(UIComponent previous)
582     {
583         getFacets().put(PREVIOUS_FACET_NAME, previous);
584     }
585 
586     /**
587      * @JSFFacet
588      */
589     public UIComponent getPrevious()
590     {
591         return (UIComponent) getFacets().get(PREVIOUS_FACET_NAME);
592     }
593 
594     public boolean getRendersChildren()
595     {
596         return true;
597     }
598 
599     /**
600      * @see javax.faces.component.ActionSource#getAction()
601      */
602     public MethodBinding getAction()
603     {
604         // not used
605         return null;
606     }
607 
608     /**
609      * @see javax.faces.component.ActionSource#setAction(javax.faces.el.MethodBinding)
610      */
611     public void setAction(MethodBinding action)
612     {
613         throw new UnsupportedOperationException(
614                         "defining an action is not supported. use an actionlistener");
615     }
616 
617     /**
618      * @see javax.faces.component.ActionSource#setActionListener(javax.faces.el.MethodBinding)
619      */
620     public void setActionListener(MethodBinding actionListener)
621     {
622         _actionListener = actionListener;
623     }
624 
625     /**
626      * MethodBinding pointing at method acception an ActionEvent with return type void.
627      *
628      * @JSFProperty
629      *   returnSignature="void"
630      *   methodSignature="javax.faces.event.ActionEvent"
631      * @see javax.faces.component.ActionSource#getActionListener()
632      */
633     public MethodBinding getActionListener()
634     {
635         return _actionListener;
636     }
637 
638     /**
639      * @see javax.faces.component.ActionSource#addActionListener(javax.faces.event.ActionListener)
640      */
641     public void addActionListener(ActionListener listener)
642     {
643         addFacesListener(listener);
644     }
645 
646     /**
647      * @see javax.faces.component.ActionSource#getActionListeners()
648      */
649     public ActionListener[] getActionListeners()
650     {
651         return (ActionListener[]) getFacesListeners(ActionListener.class);
652     }
653 
654     /**
655      * @see javax.faces.component.ActionSource#removeActionListener(javax.faces.event.ActionListener)
656      */
657     public void removeActionListener(ActionListener listener)
658     {
659         removeFacesListener(listener);
660     }
661 
662     public Object saveState(FacesContext context)
663     {
664         Object values[] = new Object[2];
665         values[0] = super.saveState(context);
666         values[1] = saveAttachedState(context, _actionListener);
667         return values;
668     }
669 
670     public void restoreState(FacesContext context, Object state)
671     {
672         Object values[] = (Object[]) state;
673         super.restoreState(context, values[0]);
674         _actionListener = (MethodBinding)restoreAttachedState(context, values[1]);
675     }
676 
677     /**
678      * The JSF id of a UIData component that this scroller will affect.
679      *
680      * If this attribute is not present then the datascroller must be
681      * a child of a UIData component.
682      *
683      * @JSFProperty
684      */
685     public abstract String getFor();
686 
687     /**
688      * step (pages) used for fastforward and fastrewind
689      *
690      * @JSFProperty
691      *   defaultValue="Integer.MIN_VALUE"
692      */
693     public abstract int getFastStep();
694 
695     /**
696      * A parameter name, under which the actual page index is set
697      * in request scope similar to the var parameter.
698      *
699      * @JSFProperty
700      */
701     public abstract String getPageIndexVar();
702 
703     /**
704      * A parameter name, under which the actual page count is set
705      * in request scope similar to the var parameter.
706      *
707      * @JSFProperty
708      */
709     public abstract String getPageCountVar();
710 
711     /**
712      * A parameter name, under which the actual rows count is set
713      * in request scope similar to the var parameter.
714      *
715      * @JSFProperty
716      */
717     public abstract String getRowsCountVar();
718 
719     /**
720      * A parameter name, under which the actual displayed rows count
721      * is set in request scope similar to the var parameter.
722      *
723      * @JSFProperty
724      */
725     public abstract String getDisplayedRowsCountVar();
726 
727     /**
728      * A parameter name, under which the actual first displayed row
729      * index is set in request scope similar to the var parameter.
730      *
731      * @JSFProperty
732      */
733     public abstract String getFirstRowIndexVar();
734 
735     /**
736      * A parameter name, under which the actual last displayed row
737      * index is set in request scope similar to the var parameter.
738      *
739      * @JSFProperty
740      */
741     public abstract String getLastRowIndexVar();
742 
743     /**
744      * If set true, then the paginator gets rendered
745      *
746      * @JSFProperty
747      *   defaultValue = "false"
748      */
749     public abstract boolean isPaginator();
750 
751     /**
752      * The maximum amount of pages to be displayed in the paginator.
753      *
754      * @JSFProperty
755      *   defaultValue = "Integer.MIN_VALUE"
756      */
757     public abstract int getPaginatorMaxPages();
758 
759     /**
760      * styleclass for pagingator
761      *
762      * @JSFProperty
763      */
764     public abstract String getPaginatorTableClass();
765 
766     /**
767      * style for pagingator
768      *
769      * @JSFProperty
770      */
771     public abstract String getPaginatorTableStyle();
772 
773     /**
774      * styleClass for paginator's column
775      *
776      * @JSFProperty
777      */
778     public abstract String getPaginatorColumnClass();
779 
780     /**
781      * style for paginator's column
782      *
783      * @JSFProperty
784      */
785     public abstract String getPaginatorColumnStyle();
786 
787     /**
788      * styleClass for paginator's column with pageIndex = currentPageIndex
789      *
790      * @JSFProperty
791      */
792     public abstract String getPaginatorActiveColumnClass();
793 
794     /**
795      * 'true' - render a link for the paginator's column with
796      * pageIndex = currentPageIndex. Default-value is 'true'.
797      *
798      * @JSFProperty
799      *   defaultValue = "true"
800      */
801     public abstract boolean isPaginatorRenderLinkForActive();
802 
803     /**
804      * style-class for data-scroller first-element
805      *
806      * @JSFProperty
807      */
808     public abstract String getFirstStyleClass();
809 
810     /**
811      * style-class for data-scroller last-element
812      *
813      * @JSFProperty
814      */
815     public abstract String getLastStyleClass();
816 
817     /**
818      * style-class for data-scroller previous-element
819      *
820      * @JSFProperty
821      */
822     public abstract String getPreviousStyleClass();
823 
824     /**
825      * style-class for dataScroller next-element
826      *
827      * @JSFProperty
828      */
829     public abstract String getNextStyleClass();
830 
831     /**
832      * style-class for data-scroller fast-forward-element
833      *
834      * @JSFProperty
835      */
836     public abstract String getFastfStyleClass();
837 
838     /**
839      * style-class for data-scroller fast-rewind-element
840      *
841      * @JSFProperty
842      */
843     public abstract String getFastrStyleClass();
844 
845     /**
846      * style for paginator's column with pageIndex = currentPageIndex
847      *
848      * @JSFProperty
849      */
850     public abstract String getPaginatorActiveColumnStyle();
851 
852     /**
853      * If set to false, the facets aren't renderd if all the
854      * lines are contained on a single page. Default is true.
855      *
856      * @JSFProperty
857      *   defaultValue="true"
858      */
859     public abstract boolean isRenderFacetsIfSinglePage();
860 
861     /**
862      * True means that the default ActionListener should be
863      * executed immediately (i.e. during Apply Request
864      * Values phase of the request processing lifecycle),
865      * rather than waiting until the Invoke Application phase.
866      *
867      * @JSFProperty
868      *   defaultValue="false"
869      */
870     public abstract boolean isImmediate();
871 
872     /**
873      * If the dataScroller is on the first page (index is at 1), links for
874      * first, prev and fastprev are disabled. Default is false.
875      * 
876      * @JSFProperty
877      *   defaultValue="false"
878      */
879     public abstract boolean isDisableFacetLinksIfFirstPage();
880 
881     /**
882      * If the dataScroller is on the last page (index is at pagecount), links for
883      * last, next and fastnext are disabled. Default is false.
884      * 
885      * @JSFProperty
886      *   defaultValue="false"
887      */
888     public abstract boolean isDisableFacetLinksIfLastPage();
889 
890     /**
891      * If the dataScroller is on the first page (index is at 1), links for
892      * first, prev and fastprev are rendered. Default is true.
893      * 
894      * @JSFProperty
895      *   defaultValue="true"
896      */
897     public abstract boolean isRenderFacetLinksIfFirstPage();
898 
899     /**
900      * If the dataScroller is on the last page (index is at pagecount), links for
901      * last, next and fastnext are rendered. Default is true.
902      * 
903      * @JSFProperty
904      *   defaultValue="true"
905      */
906     public abstract boolean isRenderFacetLinksIfLastPage();
907     
908 }