KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > web > ui > common > component > data > UIRichList


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.web.ui.common.component.data;
18
19 import java.util.HashMap JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import javax.faces.component.UIComponent;
24 import javax.faces.component.UIComponentBase;
25 import javax.faces.context.FacesContext;
26 import javax.faces.el.ValueBinding;
27 import javax.transaction.UserTransaction JavaDoc;
28
29 import org.alfresco.web.app.Application;
30 import org.alfresco.web.bean.repository.Repository;
31 import org.alfresco.web.config.ViewsConfigElement;
32 import org.alfresco.web.data.IDataContainer;
33 import org.alfresco.web.ui.common.renderer.data.IRichListRenderer;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38  * @author Kevin Roast
39  */

40 public class UIRichList extends UIComponentBase implements IDataContainer
41 {
42    // ------------------------------------------------------------------------------
43
// Construction
44

45    /**
46     * Default constructor
47     */

48    public UIRichList()
49    {
50       setRendererType("org.alfresco.faces.RichListRenderer");
51       
52       // get the list of views from the client configuration
53
ViewsConfigElement viewsConfig = (ViewsConfigElement)Application.getConfigService(
54             FacesContext.getCurrentInstance()).getConfig("Views").
55             getConfigElement(ViewsConfigElement.CONFIG_ELEMENT_ID);
56       List JavaDoc<String JavaDoc> views = viewsConfig.getViews();
57       
58       // instantiate each renderer and add to the list
59
for (String JavaDoc view : views)
60       {
61          try
62          {
63             Class JavaDoc clazz = Class.forName(view);
64             IRichListRenderer renderer = (IRichListRenderer)clazz.newInstance();
65             UIRichList.viewRenderers.put(renderer.getViewModeID(), renderer);
66             
67             if (logger.isDebugEnabled())
68                logger.debug("Added view '" + renderer.getViewModeID() +
69                             "' to UIRichList");
70          }
71          catch (Exception JavaDoc e)
72          {
73             if (logger.isWarnEnabled())
74             {
75                logger.warn("Failed to create renderer: " + view, e);
76             }
77          }
78       }
79    }
80
81
82    // ------------------------------------------------------------------------------
83
// Component implementation
84

85    /**
86     * @see javax.faces.component.UIComponent#getFamily()
87     */

88    public String JavaDoc getFamily()
89    {
90       return "org.alfresco.faces.Data";
91    }
92    
93    /**
94     * @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object)
95     */

96    public void restoreState(FacesContext context, Object JavaDoc state)
97    {
98       Object JavaDoc values[] = (Object JavaDoc[])state;
99       // standard component attributes are restored by the super class
100
super.restoreState(context, values[0]);
101       this.currentPage = ((Integer JavaDoc)values[1]).intValue();
102       this.sortColumn = (String JavaDoc)values[2];
103       this.sortDescending = ((Boolean JavaDoc)values[3]).booleanValue();
104       this.value = values[4]; // not serializable!
105
this.dataModel = (IGridDataModel)values[5]; // not serializable!
106
this.viewMode = (String JavaDoc)values[6];
107       this.pageSize = ((Integer JavaDoc)values[7]).intValue();
108       this.initialSortColumn = (String JavaDoc)values[8];
109       this.initialSortDescending = ((Boolean JavaDoc)values[9]).booleanValue();
110    }
111    
112    /**
113     * @see javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext)
114     */

115    public Object JavaDoc saveState(FacesContext context)
116    {
117       Object JavaDoc values[] = new Object JavaDoc[10];
118       // standard component attributes are saved by the super class
119
values[0] = super.saveState(context);
120       values[1] = Integer.valueOf(this.currentPage);
121       values[2] = this.sortColumn;
122       values[3] = (this.sortDescending ? Boolean.TRUE : Boolean.FALSE);
123       values[4] = this.value;
124       values[5] = this.dataModel;
125       values[6] = this.viewMode;
126       values[7] = Integer.valueOf(this.pageSize);
127       values[8] = this.initialSortColumn;
128       values[9] = (this.initialSortDescending ? Boolean.TRUE : Boolean.FALSE);
129       
130       return (values);
131    }
132    
133    /**
134     * Get the value (for this component the value is an object used as the DataModel)
135     *
136     * @return the value
137     */

138    public Object JavaDoc getValue()
139    {
140       if (this.value == null)
141       {
142          ValueBinding vb = getValueBinding("value");
143          if (vb != null)
144          {
145             this.value = vb.getValue(getFacesContext());
146          }
147       }
148       return this.value;
149    }
150
151    /**
152     * Set the value (for this component the value is an object used as the DataModel)
153     *
154     * @param value the value
155     */

156    public void setValue(Object JavaDoc value)
157    {
158       this.dataModel = null;
159       this.value = value;
160    }
161    
162    /**
163     * Clear the current sorting settings back to the defaults
164     */

165    public void clearSort()
166    {
167       this.sortColumn = null;
168       this.sortDescending = true;
169       this.initialSortColumn = null;
170       this.initialSortDescending = false;
171    }
172    
173    /**
174     * Get the view mode for this Rich List
175     *
176     * @return view mode as a String
177     */

178    public String JavaDoc getViewMode()
179    {
180       ValueBinding vb = getValueBinding("viewMode");
181       if (vb != null)
182       {
183          this.viewMode = (String JavaDoc)vb.getValue(getFacesContext());
184       }
185       
186       return this.viewMode;
187    }
188    
189    /**
190     * Set the current view mode for this Rich List
191     *
192     * @param viewMode the view mode as a String
193     */

194    public void setViewMode(String JavaDoc viewMode)
195    {
196       this.viewMode = viewMode;
197    }
198    
199    /**
200     * Return the UI Component to be used as the "no items available" message
201     *
202     * @return UIComponent
203     */

204    public UIComponent getEmptyMessage()
205    {
206       return getFacet("empty");
207    }
208    
209    
210    // ------------------------------------------------------------------------------
211
// IDataContainer implementation
212

213    /**
214     * Return the currently sorted column if any
215     *
216     * @return current sorted column if any
217     */

218    public String JavaDoc getCurrentSortColumn()
219    {
220       return this.sortColumn;
221    }
222    
223    /**
224     * @see org.alfresco.web.data.IDataContainer#isCurrentSortDescending()
225     */

226    public boolean isCurrentSortDescending()
227    {
228       return this.sortDescending;
229    }
230    
231    /**
232     * @return Returns the initialSortColumn.
233     */

234    public String JavaDoc getInitialSortColumn()
235    {
236       return this.initialSortColumn;
237    }
238
239    /**
240     * @param initialSortColumn The initialSortColumn to set.
241     */

242    public void setInitialSortColumn(String JavaDoc initialSortColumn)
243    {
244       this.initialSortColumn = initialSortColumn;
245    }
246
247    /**
248     * @return Returns the initialSortDescending.
249     */

250    public boolean isInitialSortDescending()
251    {
252       return this.initialSortDescending;
253    }
254
255    /**
256     * @param initialSortDescending The initialSortDescending to set.
257     */

258    public void setInitialSortDescending(boolean initialSortDescending)
259    {
260       this.initialSortDescending = initialSortDescending;
261    }
262    
263    /**
264     * Returns the current page size used for this list, or -1 for no paging.
265     */

266    public int getPageSize()
267    {
268       ValueBinding vb = getValueBinding("pageSize");
269       if (vb != null)
270       {
271          int pageSize = ((Integer JavaDoc)vb.getValue(getFacesContext())).intValue();
272          if (pageSize != this.pageSize)
273          {
274             // force a reset of the current page - else the bind may show a page that isn't there
275
setPageSize(pageSize);
276          }
277       }
278       
279       return this.pageSize;
280    }
281    
282    /**
283     * Sets the current page size used for the list.
284     *
285     * @param val
286     */

287    public void setPageSize(int val)
288    {
289       if (val >= -1)
290       {
291          this.pageSize = val;
292          setCurrentPage(0);
293       }
294    }
295    
296    /**
297     * @see org.alfresco.web.data.IDataContainer#getPageCount()
298     */

299    public int getPageCount()
300    {
301       return this.pageCount;
302    }
303    
304    /**
305     * Return the current page the list is displaying
306     *
307     * @return current page zero based index
308     */

309    public int getCurrentPage()
310    {
311       return this.currentPage;
312    }
313    
314    /**
315     * @see org.alfresco.web.data.IDataContainer#setCurrentPage(int)
316     */

317    public void setCurrentPage(int index)
318    {
319       this.currentPage = index;
320    }
321
322    /**
323     * Returns true if a row of data is available
324     *
325     * @return true if data is available, false otherwise
326     */

327    public boolean isDataAvailable()
328    {
329       return this.rowIndex < this.maxRowIndex;
330    }
331    
332    /**
333     * Returns the next row of data from the data model
334     *
335     * @return next row of data as a Bean object
336     */

337    public Object JavaDoc nextRow()
338    {
339       // get next row and increment row count
340
Object JavaDoc rowData = getDataModel().getRow(this.rowIndex + 1);
341       
342       // Prepare the data-binding variable "var" ready for the next cycle of
343
// renderering for the child components.
344
String JavaDoc var = (String JavaDoc)getAttributes().get("var");
345       if (var != null)
346       {
347          Map JavaDoc requestMap = getFacesContext().getExternalContext().getRequestMap();
348          if (isDataAvailable() == true)
349          {
350             requestMap.put(var, rowData);
351          }
352          else
353          {
354             requestMap.remove(var);
355          }
356       }
357       
358       this.rowIndex++;
359       
360       return rowData;
361    }
362    
363    /**
364     * Sort the dataset using the specified sort parameters
365     *
366     * @param column Column to sort
367     * @param descending True for descending sort, false for ascending
368     * @param mode Sort mode to use (see IDataContainer constants)
369     */

370    public void sort(String JavaDoc column, boolean descending, String JavaDoc mode)
371    {
372       this.sortColumn = column;
373       this.sortDescending = descending;
374       
375       // delegate to the data model to sort its contents
376
// place in a UserTransaction as we may need to perform a LOT of node calls to complete
377
UserTransaction JavaDoc tx = null;
378       try
379       {
380          if (getDataModel().size() > 64)
381          {
382             FacesContext context = FacesContext.getCurrentInstance();
383             tx = Repository.getUserTransaction(context, true);
384             tx.begin();
385          }
386          
387          getDataModel().sort(column, descending, mode);
388          
389          // commit the transaction
390
if (tx != null)
391          {
392             tx.commit();
393          }
394       }
395       catch (Throwable JavaDoc err)
396       {
397          try { if (tx != null) {tx.rollback();} } catch (Exception JavaDoc tex) {}
398       }
399    }
400    
401    
402    // ------------------------------------------------------------------------------
403
// UIRichList implementation
404

405    /**
406     * Method called to bind the RichList component state to the data model value
407     */

408    public void bind()
409    {
410       int rowCount = getDataModel().size();
411       // if a page size is specified, then we use that
412
int pageSize = getPageSize();
413       if (pageSize != -1)
414       {
415          // calc start row index based on current page index
416
this.rowIndex = (this.currentPage * pageSize) - 1;
417          
418          // calc total number of pages available
419
this.pageCount = (rowCount / this.pageSize) + 1;
420          if (rowCount % pageSize == 0 && this.pageCount != 1)
421          {
422             this.pageCount--;
423          }
424          
425          // calc the maximum row index that can be returned
426
this.maxRowIndex = this.rowIndex + pageSize;
427          if (this.maxRowIndex >= rowCount)
428          {
429             this.maxRowIndex = rowCount - 1;
430          }
431       }
432       // else we are not paged so show all data from start
433
else
434       {
435          this.rowIndex = -1;
436          this.pageCount = 1;
437          this.maxRowIndex = (rowCount - 1);
438       }
439       if (logger.isDebugEnabled())
440          logger.debug("Bound datasource: PageSize: " + pageSize + "; CurrentPage: " + this.currentPage + "; RowIndex: " + this.rowIndex + "; MaxRowIndex: " + this.maxRowIndex + "; RowCount: " + rowCount);
441    }
442    
443    /**
444     * @return A new IRichListRenderer implementation for the current view mode
445     */

446    public IRichListRenderer getViewRenderer()
447    {
448       // get type from current view mode, then create an instance of the renderer
449
IRichListRenderer renderer = null;
450       if (getViewMode() != null)
451       {
452          renderer = (IRichListRenderer)UIRichList.viewRenderers.get(getViewMode());
453       }
454       return renderer;
455    }
456    
457    /**
458     * Return the data model wrapper
459     *
460     * @return IGridDataModel
461     */

462    private IGridDataModel getDataModel()
463    {
464       if (this.dataModel == null)
465       {
466          // build the appropriate data-model wrapper object
467
Object JavaDoc val = getValue();
468          if (val instanceof List JavaDoc)
469          {
470             this.dataModel = new GridListDataModel((List JavaDoc)val);
471          }
472          else if ( (java.lang.Object JavaDoc[].class).isAssignableFrom(val.getClass()) )
473          {
474             this.dataModel = new GridArrayDataModel((Object JavaDoc[])val);
475          }
476          else
477          {
478             throw new IllegalStateException JavaDoc("UIRichList 'value' attribute binding should specify data model of a supported type!");
479          }
480          
481          // sort first time on initially sorted column if set
482
if (this.sortColumn == null)
483          {
484             String JavaDoc initialSortColumn = getInitialSortColumn();
485             if (initialSortColumn != null && initialSortColumn.length() != 0)
486             {
487                boolean descending = isInitialSortDescending();
488                
489                // TODO: add support for retrieving correct column sort mode here
490
this.sortColumn = initialSortColumn;
491                this.sortDescending = descending;
492             }
493          }
494          if (this.sortColumn != null)
495          {
496             // delegate to the data model to sort its contents
497
this.dataModel.sort(this.sortColumn, this.sortDescending, IDataContainer.SORT_CASEINSENSITIVE);
498          }
499          
500          // reset current page
501
this.currentPage = 0;
502       }
503       
504       return this.dataModel;
505    }
506    
507    
508    // ------------------------------------------------------------------------------
509
// Private data
510

511    /** map of available IRichListRenderer instances */
512    private final static Map JavaDoc<String JavaDoc, IRichListRenderer> viewRenderers = new HashMap JavaDoc<String JavaDoc, IRichListRenderer>(5);
513    
514    // component state
515
private int currentPage = 0;
516    private String JavaDoc sortColumn = null;
517    private boolean sortDescending = true;
518    private Object JavaDoc value = null;
519    private IGridDataModel dataModel = null;
520    private String JavaDoc viewMode = null;
521    private int pageSize = -1;
522    private String JavaDoc initialSortColumn = null;
523    private boolean initialSortDescending = false;
524    
525    // transient component state that exists during a single page refresh only
526
private int rowIndex = -1;
527    private int maxRowIndex = -1;
528    private int pageCount = 1;
529    
530    private static Log logger = LogFactory.getLog(IDataContainer.class);
531 }
532
Popular Tags