All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.custom.datascroller.AbstractHtmlDataScroller Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF1.2 features. A JSF1.2 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.custom.datascroller;

import javax.faces.FacesException;
import javax.faces.component.ActionSource;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIPanel;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.component.DisplayValueOnlyAware;
import org.apache.myfaces.component.ForceIdAware;
import org.apache.myfaces.component.StyleAware;
import org.apache.myfaces.component.UniversalProperties;
import org.apache.myfaces.component.UserRoleAware;
import org.apache.myfaces.component.UserRoleUtils;
import org.apache.myfaces.component.html.util.HtmlComponentUtils;
import org.apache.myfaces.shared_tomahawk.component.DisplayValueOnlyCapable;

/**
 * Scroller for UIData components eg. dataTable
 *
 * Must be nested inside footer facet of dataTable OR for
 * attribute must be given so that corresponding uiData can be found.
 *
 * Unless otherwise specified, all attributes accept static values or EL expressions.
 *
 * A component which works together with a UIData component to allow a
 * user to view a large list of data one "page" at a time, and navigate
 * between pages.
 *
 * @JSFComponent
 *   name = "t:dataScroller"
 *   class = "org.apache.myfaces.custom.datascroller.HtmlDataScroller"
 *   tagClass = "org.apache.myfaces.custom.datascroller.HtmlDataScrollerTag"
 * @since 1.1.7
 * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
 * @version $Revision: 955086 $ $Date: 2010-06-15 18:32:00 -0500 (Tue, 15 Jun 2010) $
 */
public abstract class AbstractHtmlDataScroller extends UIPanel
    implements ActionSource, UserRoleAware, DisplayValueOnlyCapable,
    DisplayValueOnlyAware, ForceIdAware, UniversalProperties, StyleAware
{

    public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataScroller";
    public static final String COMPONENT_FAMILY = "javax.faces.Panel";
    private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.DataScroller";
    private static final boolean DEFAULT_IMMEDIATE = false;

    private static final Log log = LogFactory.getLog(AbstractHtmlDataScroller.class);

    private static final String FIRST_FACET_NAME = "first";
    private static final String LAST_FACET_NAME = "last";
    private static final String NEXT_FACET_NAME = "next";
    private static final String PREVIOUS_FACET_NAME = "previous";
    private static final String FAST_FORWARD_FACET_NAME = "fastforward";
    private static final String FAST_REWIND_FACET_NAME = "fastrewind";

    public static final String FACET_FIRST = "first".intern();
    public static final String FACET_PREVIOUS = "previous".intern();
    public static final String FACET_NEXT = "next".intern();
    public static final String FACET_LAST = "last".intern();
    public static final String FACET_FAST_FORWARD = "fastf".intern();
    public static final String FACET_FAST_REWIND = "fastr".intern();

    private static final String TABLE_LAYOUT = "table";
    private static final String LIST_LAYOUT = "list";
    private static final String SINGLE_LIST_LAYOUT = "singleList";
    private static final String SINGLE_TABLE_LAYOUT = "singleTable";

    // just for caching the associated uidata
    private transient UIData _UIData;

    private transient Boolean _listLayout;

    private transient Boolean _singleElementLayout;

    private MethodBinding _actionListener;

    public String getClientId(FacesContext context)
    {
        String clientId = HtmlComponentUtils.getClientId(this, getRenderer(context), context);
        if (clientId == null)
        {
            clientId = super.getClientId(context);
        }

        return clientId;
    }

    public boolean isRendered()
    {
        if (!UserRoleUtils.isVisibleOnUserRole(this)) return false;
        return super.isRendered();
    }

    public boolean isSetDisplayValueOnly(){
        return getDisplayValueOnly() != null ? true : false;
    }

    public boolean isDisplayValueOnly(){
        return getDisplayValueOnly() != null ? getDisplayValueOnly().booleanValue() : false;
    }

    public void setDisplayValueOnly(boolean displayValueOnly){
        this.setDisplayValueOnly((Boolean) Boolean.valueOf(displayValueOnly));
    }

    /**
     *  The layout this scroller should render with. Default is 'table',
     *  'list' is implemented as well. Additionally you can use
     *  'singleList' - then the data-scroller will render a list, but
     *  not the paginator - same with the value 'singleTable'.
     *
     * @JSFProperty
     *   defaultValue = "table"
     */
    public abstract String getLayout();

    /**
     * standard html colspan attribute for table cell
     *
     * @JSFProperty
     *   defaultValue = "Integer.MIN_VALUE"
     */
    public abstract int getColspan();

    /**
     * HTML: Script to be invoked when the element is clicked.
     *
     * @JSFProperty
     */
    public abstract String getOnclick();

    /**
     * HTML: Script to be invoked when the element is double-clicked.
     *
     * @JSFProperty
     */
    public abstract String getOndblclick();

    public boolean isListLayout()
    {
        if(_listLayout == null)
        {
            String layout=getLayout();
            if(layout == null || layout.equals(TABLE_LAYOUT) || layout.equals(SINGLE_TABLE_LAYOUT))
                _listLayout = Boolean.FALSE;
            else if(layout.equals(LIST_LAYOUT) || layout.equals(SINGLE_LIST_LAYOUT))
            {
                _listLayout = Boolean.TRUE;
            }
            else
            {
                log.error("Invalid layout-parameter : "+layout +" provided. Defaulting to table-layout.");
                _listLayout = Boolean.FALSE;
            }
        }

        return _listLayout.booleanValue();
    }

    public boolean isSingleElementLayout()
    {
        if(_singleElementLayout == null)
        {
            String layout=getLayout();
            if(layout == null || layout.equals(SINGLE_LIST_LAYOUT) || layout.equals(SINGLE_TABLE_LAYOUT))
                _singleElementLayout = Boolean.TRUE;
            else
                _singleElementLayout = Boolean.FALSE;
        }

        return _singleElementLayout.booleanValue();
    }

    /**
     * Catch any attempts to queue events for this component, and ensure
     * the event's phase is set appropriately. Events are expected to be
     * queued by this component's renderer.
     * 

* When this component is marked "immediate", any ActionEvent will * be marked to fire in the "apply request values" phase. When this * component is not immediate the event will fire during the * "invoke application" phase instead. */ public void queueEvent(FacesEvent event) { if (event != null && event instanceof ActionEvent) { if (isImmediate()) { event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else { event.setPhaseId(PhaseId.INVOKE_APPLICATION); } } super.queueEvent(event); } /** * Invoke any action listeners attached to this class. *

* After listener invocation, the associated UIData's properties get * updated: *

    *
  • if the user selected an absolute page# then setFirst is called with * uiData.getRows() * pageNumber. *
  • if the user selected the "first page" option then setFirst(0) is called. *
  • if the user selected the "previous page" option then setFirst is decremented * by uiData.getRows(). *
  • if the user selected the "fast rewind" option then setFirst is decremented * by uiData.getRows() * fastStep. *
  • next, fast-forward and last options have the obvious effect. *
*/ public void broadcast(FacesEvent event) throws AbortProcessingException { super.broadcast(event); if (event instanceof ScrollerActionEvent) { ScrollerActionEvent scrollerEvent = (ScrollerActionEvent) event; // huh? getUIData never returns null. UIData uiData = getUIData(); if (uiData == null) { return; } int pageindex = scrollerEvent.getPageIndex(); if (pageindex == -1) { String facet = scrollerEvent.getScrollerfacet(); if (FACET_FIRST.equals(facet)) { setFirst(uiData, 0); } else if (FACET_PREVIOUS.equals(facet)) { int previous = uiData.getFirst() - uiData.getRows(); if (previous >= 0) setFirst(uiData, previous); } else if (FACET_NEXT.equals(facet)) { int next = uiData.getFirst() + uiData.getRows(); if (next < uiData.getRowCount()) setFirst(uiData, next); } else if (FACET_FAST_FORWARD.equals(facet)) { int fastStep = getFastStep(); if (fastStep <= 0) fastStep = 1; int next = uiData.getFirst() + uiData.getRows() * fastStep; int rowcount = uiData.getRowCount(); if (next >= rowcount) next = (rowcount - 1) - ((rowcount - 1) % uiData.getRows()); setFirst(uiData, next); } else if (FACET_FAST_REWIND.equals(facet)) { int fastStep = getFastStep(); if (fastStep <= 0) fastStep = 1; int previous = uiData.getFirst() - uiData.getRows() * fastStep; if (previous < 0) previous = 0; setFirst(uiData, previous); } else if (FACET_LAST.equals(facet)) { int rowcount = uiData.getRowCount(); int rows = uiData.getRows(); int delta = (rows != 0) ? (rowcount % rows) : 0; int first = delta > 0 && delta < rows ? rowcount - delta : rowcount - rows; if (first >= 0) { setFirst(uiData, first); } else { setFirst(uiData, 0); } } } else { int pageCount = getPageCount(); if (pageindex > pageCount) { pageindex = pageCount; } if (pageindex <= 0) { pageindex = 1; } setFirst(uiData, uiData.getRows() * (pageindex - 1)); } broadcastToActionListener(scrollerEvent); } } protected void setFirst(UIData uiData, int value) { //there might be special cases where the first-property of the data-table //is bound to a backing bean. If this happens, the user probably wants //the data-scroller to update this backing-bean value - if not, you can always //override this method in a subclass. if(uiData.getValueBinding("first")!=null) { ValueBinding vb = uiData.getValueBinding("first"); vb.setValue(getFacesContext(),new Integer(value)); } else { uiData.setFirst(value); } } /** * @param event */ protected void broadcastToActionListener(ScrollerActionEvent event) { FacesContext context = getFacesContext(); MethodBinding actionListenerBinding = getActionListener(); if (actionListenerBinding != null) { try { actionListenerBinding.invoke(context, new Object[] {event}); } catch (EvaluationException e) { Throwable cause = e.getCause(); if (cause != null && cause instanceof AbortProcessingException) { throw (AbortProcessingException)cause; } throw e; } } ActionListener defaultActionListener = context.getApplication().getActionListener(); if (defaultActionListener != null) { defaultActionListener.processAction((ActionEvent)event); } } /** * @return int */ public UIData getUIData() { if (_UIData == null) { _UIData = findUIData(); } return _UIData; } /** * @return the page index of the uidata */ public int getPageIndex() { UIData uiData = getUIData(); int rows = uiData.getRows(); if (0 == rows) { throw new FacesException("You need to set a value to the 'rows' attribute of component '" + uiData.getClientId(getFacesContext()) + "'" ); } int pageIndex; if (rows > 0) { pageIndex = uiData.getFirst() / rows + 1; } else { log.warn("DataTable " + uiData.getClientId(FacesContext.getCurrentInstance()) + " has invalid rows attribute."); pageIndex = 0; } if (uiData.getFirst() % rows > 0) { pageIndex++; } return pageIndex; } /** * @return the page count of the uidata */ public int getPageCount() { UIData uiData = getUIData(); int rows = uiData.getRows(); int pageCount; if (rows > 0) { pageCount = rows <= 0 ? 1 : uiData.getRowCount() / rows; if (uiData.getRowCount() % rows > 0) { pageCount++; } } else { rows = 1; pageCount = 1; } return pageCount; } /** * @return int */ public int getRowCount() { return getUIData().getRowCount(); } /** * @return int */ public int getRows() { return getUIData().getRows(); } /** * @return int */ public int getFirstRow() { return getUIData().getFirst(); } /** * Find the UIData component associated with this scroller. *

* If the "for" attribute is not null then that value is used to find the * specified component by id. Both "relative" and "absolute" ids are allowed; * see method UIComponent.findComponent for details. *

* If the "for" attribute is not defined, then this component is expected to * be a child of a UIData component. * * @throws IllegalArgumentException if an associated UIData component * cannot be found. */ protected UIData findUIData() { String forStr = getFor(); UIComponent forComp; if (forStr == null) { // DataScroller may be a child of uiData forComp = getParent(); } else { forComp = findComponent(forStr); } if (forComp == null) { throw new IllegalArgumentException( "could not find UIData referenced by attribute dataScroller@for = '" + forStr + "'"); } else if (!(forComp instanceof UIData)) { throw new IllegalArgumentException( "uiComponent referenced by attribute dataScroller@for = '" + forStr + "' must be of type " + UIData.class.getName() + ", not type " + forComp.getClass().getName()); } return (UIData) forComp; } public void setFirst(UIComponent first) { getFacets().put(FIRST_FACET_NAME, first); } /** * @JSFFacet */ public UIComponent getFirst() { return (UIComponent) getFacets().get(FIRST_FACET_NAME); } public void setLast(UIComponent last) { getFacets().put(LAST_FACET_NAME, last); } /** * @JSFFacet */ public UIComponent getLast() { return (UIComponent) getFacets().get(LAST_FACET_NAME); } public void setNext(UIComponent next) { getFacets().put(NEXT_FACET_NAME, next); } /** * @JSFFacet */ public UIComponent getNext() { return (UIComponent) getFacets().get(NEXT_FACET_NAME); } public void setFastForward(UIComponent previous) { getFacets().put(FAST_FORWARD_FACET_NAME, previous); } /** * @JSFFacet */ public UIComponent getFastForward() { return (UIComponent) getFacets().get(FAST_FORWARD_FACET_NAME); } public void setFastRewind(UIComponent previous) { getFacets().put(FAST_REWIND_FACET_NAME, previous); } /** * @JSFFacet */ public UIComponent getFastRewind() { return (UIComponent) getFacets().get(FAST_REWIND_FACET_NAME); } public void setPrevious(UIComponent previous) { getFacets().put(PREVIOUS_FACET_NAME, previous); } /** * @JSFFacet */ public UIComponent getPrevious() { return (UIComponent) getFacets().get(PREVIOUS_FACET_NAME); } public boolean getRendersChildren() { return true; } /** * @see javax.faces.component.ActionSource#getAction() */ public MethodBinding getAction() { // not used return null; } /** * @see javax.faces.component.ActionSource#setAction(javax.faces.el.MethodBinding) */ public void setAction(MethodBinding action) { throw new UnsupportedOperationException( "defining an action is not supported. use an actionlistener"); } /** * @see javax.faces.component.ActionSource#setActionListener(javax.faces.el.MethodBinding) */ public void setActionListener(MethodBinding actionListener) { _actionListener = actionListener; } /** * MethodBinding pointing at method acception an ActionEvent with return type void. * * @JSFProperty * returnSignature="void" * methodSignature="javax.faces.event.ActionEvent" * @see javax.faces.component.ActionSource#getActionListener() */ public MethodBinding getActionListener() { return _actionListener; } /** * @see javax.faces.component.ActionSource#addActionListener(javax.faces.event.ActionListener) */ public void addActionListener(ActionListener listener) { addFacesListener(listener); } /** * @see javax.faces.component.ActionSource#getActionListeners() */ public ActionListener[] getActionListeners() { return (ActionListener[]) getFacesListeners(ActionListener.class); } /** * @see javax.faces.component.ActionSource#removeActionListener(javax.faces.event.ActionListener) */ public void removeActionListener(ActionListener listener) { removeFacesListener(listener); } public Object saveState(FacesContext context) { Object values[] = new Object[2]; values[0] = super.saveState(context); values[1] = saveAttachedState(context, _actionListener); return values; } public void restoreState(FacesContext context, Object state) { Object values[] = (Object[]) state; super.restoreState(context, values[0]); _actionListener = (MethodBinding)restoreAttachedState(context, values[1]); } /** * The JSF id of a UIData component that this scroller will affect. * * If this attribute is not present then the datascroller must be * a child of a UIData component. * * @JSFProperty */ public abstract String getFor(); /** * step (pages) used for fastforward and fastrewind * * @JSFProperty * defaultValue="Integer.MIN_VALUE" */ public abstract int getFastStep(); /** * A parameter name, under which the actual page index is set * in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getPageIndexVar(); /** * A parameter name, under which the actual page count is set * in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getPageCountVar(); /** * A parameter name, under which the actual rows count is set * in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getRowsCountVar(); /** * A parameter name, under which the actual displayed rows count * is set in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getDisplayedRowsCountVar(); /** * A parameter name, under which the actual first displayed row * index is set in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getFirstRowIndexVar(); /** * A parameter name, under which the actual last displayed row * index is set in request scope similar to the var parameter. * * @JSFProperty */ public abstract String getLastRowIndexVar(); /** * If set true, then the paginator gets rendered * * @JSFProperty * defaultValue = "false" */ public abstract boolean isPaginator(); /** * The maximum amount of pages to be displayed in the paginator. * * @JSFProperty * defaultValue = "Integer.MIN_VALUE" */ public abstract int getPaginatorMaxPages(); /** * styleclass for pagingator * * @JSFProperty */ public abstract String getPaginatorTableClass(); /** * style for pagingator * * @JSFProperty */ public abstract String getPaginatorTableStyle(); /** * styleClass for paginator's column * * @JSFProperty */ public abstract String getPaginatorColumnClass(); /** * style for paginator's column * * @JSFProperty */ public abstract String getPaginatorColumnStyle(); /** * styleClass for paginator's column with pageIndex = currentPageIndex * * @JSFProperty */ public abstract String getPaginatorActiveColumnClass(); /** * 'true' - render a link for the paginator's column with * pageIndex = currentPageIndex. Default-value is 'true'. * * @JSFProperty * defaultValue = "true" */ public abstract boolean isPaginatorRenderLinkForActive(); /** * style-class for data-scroller first-element * * @JSFProperty */ public abstract String getFirstStyleClass(); /** * style-class for data-scroller last-element * * @JSFProperty */ public abstract String getLastStyleClass(); /** * style-class for data-scroller previous-element * * @JSFProperty */ public abstract String getPreviousStyleClass(); /** * style-class for dataScroller next-element * * @JSFProperty */ public abstract String getNextStyleClass(); /** * style-class for data-scroller fast-forward-element * * @JSFProperty */ public abstract String getFastfStyleClass(); /** * style-class for data-scroller fast-rewind-element * * @JSFProperty */ public abstract String getFastrStyleClass(); /** * style for paginator's column with pageIndex = currentPageIndex * * @JSFProperty */ public abstract String getPaginatorActiveColumnStyle(); /** * If set to false, the facets aren't renderd if all the * lines are contained on a single page. Default is true. * * @JSFProperty * defaultValue="true" */ public abstract boolean isRenderFacetsIfSinglePage(); /** * True means that the default ActionListener should be * executed immediately (i.e. during Apply Request * Values phase of the request processing lifecycle), * rather than waiting until the Invoke Application phase. * * @JSFProperty * defaultValue="false" */ public abstract boolean isImmediate(); /** * If the dataScroller is on the first page (index is at 1), links for * first, prev and fastprev are disabled. Default is false. * * @JSFProperty * defaultValue="false" */ public abstract boolean isDisableFacetLinksIfFirstPage(); /** * If the dataScroller is on the last page (index is at pagecount), links for * last, next and fastnext are disabled. Default is false. * * @JSFProperty * defaultValue="false" */ public abstract boolean isDisableFacetLinksIfLastPage(); /** * If the dataScroller is on the first page (index is at 1), links for * first, prev and fastprev are rendered. Default is true. * * @JSFProperty * defaultValue="true" */ public abstract boolean isRenderFacetLinksIfFirstPage(); /** * If the dataScroller is on the last page (index is at pagecount), links for * last, next and fastnext are rendered. Default is true. * * @JSFProperty * defaultValue="true" */ public abstract boolean isRenderFacetLinksIfLastPage(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy