KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tonbeller > wcf > table > TableComponent


1 /*
2  * ====================================================================
3  * This software is subject to the terms of the Common Public License
4  * Agreement, available at the following URL:
5  * http://www.opensource.org/licenses/cpl.html .
6  * Copyright (C) 2003-2004 TONBELLER AG.
7  * All Rights Reserved.
8  * You must accept the terms of that agreement to use this software.
9  * ====================================================================
10  *
11  *
12  */

13 package com.tonbeller.wcf.table;
14
15 import org.w3c.dom.Document JavaDoc;
16 import org.w3c.dom.Element JavaDoc;
17 import org.w3c.dom.Text JavaDoc;
18
19 import com.tonbeller.tbutils.res.Resources;
20 import com.tonbeller.wcf.component.Component;
21 import com.tonbeller.wcf.component.NestableComponentSupport;
22 import com.tonbeller.wcf.component.RenderListener;
23 import com.tonbeller.wcf.controller.Dispatcher;
24 import com.tonbeller.wcf.controller.DispatcherSupport;
25 import com.tonbeller.wcf.controller.RequestContext;
26 import com.tonbeller.wcf.controller.RequestListener;
27 import com.tonbeller.wcf.format.FormatException;
28 import com.tonbeller.wcf.scroller.Scroller;
29 import com.tonbeller.wcf.selection.SelectionMgr;
30 import com.tonbeller.wcf.selection.SelectionModel;
31 import com.tonbeller.wcf.utils.DomUtils;
32
33 /**
34  * The main class for the table.
35  */

36 public class TableComponent extends NestableComponentSupport implements ITableComponent {
37
38   private TableColumn[] tableColumns;
39   private TableModel tableModel;
40   private boolean sortable = true;
41   private boolean pageable = true;
42   private boolean closable = true;
43   private boolean colHeaders = true;
44   private Resources resources;
45
46   private String JavaDoc border = null;
47   private String JavaDoc width = null;
48   private String JavaDoc renderId = null;
49   private String JavaDoc error = null;
50
51   SelectionMgr selectionMgr;
52   RowComparator comparator = new RowComparator();
53   Dispatcher dispatcher = new DispatcherSupport();
54
55   // initialized by initialize()
56

57   SortedTableModel sorter = new SortedTableModel();
58   PagedTableModel pager = new PagedTableModel();
59   Document JavaDoc factory;
60   Element JavaDoc root;
61
62   String JavaDoc closeHandlerId;
63
64   class CloseHandler implements RequestListener {
65     public void request(RequestContext context) throws Exception JavaDoc {
66       setVisible(false);
67     }
68   }
69
70   String JavaDoc selectButtonId;
71
72   class SelectButtonHandler implements RequestListener {
73     public void request(RequestContext context) throws Exception JavaDoc {
74       Scroller.enableScroller(context);
75
76       // validate other forms
77
validate(context);
78       
79       // in read-only mode dont change selection
80
if (isReadOnly())
81         return;
82
83       SelectionModel sm = getSelectionModel();
84       if (isFirstSelectableRowSelected()) {
85         sm.clear();
86         sm.fireSelectionChanged(context);
87       }
88       else {
89         sm.clear();
90         TableModel tm = getModel();
91         final int N = tm.getRowCount();
92         for (int i = 0; i< N; i++) {
93           TableRow row = tm.getRow(i);
94           if (sm.isSelectable(row))
95             sm.add(row);
96         }
97         sm.fireSelectionChanged(context);
98       }
99     }
100
101     /**
102      * returns the state of the first row that is selectable
103      */

104     boolean isFirstSelectableRowSelected() {
105       SelectionModel sm = getSelectionModel();
106       TableModel tm = getModel();
107       final int N = tm.getRowCount();
108       for (int i = 0; i < N; i++) {
109         TableRow row = tm.getRow(i);
110         if (sm.isSelectable(row)) {
111           return sm.contains(row);
112         }
113       }
114       return false;
115     }
116   }
117
118   String JavaDoc gotoButtonId;
119   String JavaDoc gotoInputId;
120
121   class GotoButtonHandler implements RequestListener {
122     public GotoButtonHandler() {
123     }
124
125     public void request(RequestContext context) throws Exception JavaDoc {
126       Scroller.enableScroller(context);
127       // validate other forms
128
validate(context);
129       try {
130         int page = Integer.parseInt(context.getParameter(gotoInputId));
131         pager.setCurrentPage(page - 1);
132       } catch (NumberFormatException JavaDoc e) {
133         // ignore
134
}
135     }
136   }
137
138   String JavaDoc pageSizeButtonId;
139   String JavaDoc pageSizeInputId;
140
141   class PageSizeButtonHandler implements RequestListener {
142     public PageSizeButtonHandler() {
143     }
144
145     public void request(RequestContext context) throws Exception JavaDoc {
146       Scroller.enableScroller(context);
147       // validate other forms
148
validate(context);
149       try {
150         int ps = Integer.parseInt(context.getParameter(pageSizeInputId));
151         if (ps < 1)
152           ps = 1;
153         pager.setPageSize(ps);
154       } catch (NumberFormatException JavaDoc e) {
155         // ignore
156
}
157     }
158   }
159   
160   TableModelChangeListener changeListener = new TableModelChangeListener() {
161     public void tableModelChanged(TableModelChangeEvent event) {
162       if (event.isIdentityChanged()) {
163         setModel(getModel());
164       }
165     }
166   };
167
168   public TableComponent(String JavaDoc id, Component parent, TableModel model) {
169     super(id, parent);
170     selectionMgr = new SelectionMgr(getDispatcher(), this);
171     closeHandlerId = getId() + ".close";
172     selectButtonId = getId() + ".select";
173     gotoButtonId = getId() + ".goto.button";
174     gotoInputId = getId() + ".goto.input";
175     pageSizeButtonId = getId() + ".pageSize.button";
176     pageSizeInputId = getId() + ".pageSize.input";
177     getDispatcher().addRequestListener(closeHandlerId, null, new CloseHandler());
178     getDispatcher().addRequestListener(selectButtonId, null, new SelectButtonHandler());
179     getDispatcher().addRequestListener(gotoButtonId, null, new GotoButtonHandler());
180     getDispatcher().addRequestListener(pageSizeButtonId, null, new PageSizeButtonHandler());
181     getDispatcher().addRequestListener(null, null, dispatcher);
182
183     // default chain for JSP scripting
184
sorter.setDecoree(model);
185     pager.setDecoree(sorter);
186
187     setModel(model);
188   }
189
190   /**
191    * creates a Table component that is initially hidden. It must be assigned a TableModel
192    * before it may set visible or used in another way
193    * @param id - id of session attribute
194    * @see #setModel
195    */

196   public TableComponent(String JavaDoc id, Component parent) {
197     super(id, parent);
198     this.tableModel = null;
199     super.setVisible(false);
200     selectionMgr = new SelectionMgr(getDispatcher(), this);
201   }
202
203   public void initialize(RequestContext context) throws Exception JavaDoc {
204     super.initialize(context);
205     this.resources = context.getResources(TableComponent.class);
206   }
207
208   /** column metadata */
209   public TableColumn getTableColumn(int columnIndex) {
210     return tableColumns[columnIndex];
211   }
212
213   /** column metadata */
214   public void setTableColumn(int columnIndex, TableColumn tableColumn) {
215     tableColumns[columnIndex] = tableColumn;
216   }
217
218   /** set the data model and initializes everything */
219   public void setModel(TableModel newModel) {
220     if (tableModel != null)
221       tableModel.removeTableModelChangeListener(changeListener);
222
223     tableModel = newModel;
224     tableColumns = new TableColumn[tableModel.getColumnCount()];
225     for (int i = 0; i < tableColumns.length; i++)
226       tableColumns[i] = new TableColumn(i);
227     if (tableColumns.length > 0)
228       comparator.setColumn(tableColumns[0]);
229     else
230       comparator.setColumn(new TableColumn(0));
231     tableModel.addTableModelChangeListener(changeListener);
232     getSelectionModel().clear();
233   }
234
235   /** the underlying data model w/o sort/paging decorators */
236   public TableModel getModel() {
237     return tableModel;
238   }
239
240   /** the current selection */
241   public void setSelectionModel(SelectionModel selectionModel) {
242     selectionMgr.setSelectionModel(selectionModel);
243   }
244
245   /** the current selection */
246   public SelectionModel getSelectionModel() {
247     return selectionMgr.getSelectionModel();
248   }
249
250   /** allows to enable/disable sorting of columns */
251   public void setSortable(boolean newSortable) {
252     sortable = newSortable;
253   }
254
255   /** allows to enable/disable sorting of columns */
256   public boolean isSortable() {
257     return sortable;
258   }
259
260   /** allows to enable/disable paging of rows */
261   public void setPageable(boolean newPageable) {
262     pageable = newPageable;
263   }
264
265   /** allows to enable/disable paging of rows */
266   public boolean isPageable() {
267     return pageable;
268   }
269
270   /** set the current sort column */
271   public void setSortColumnIndex(int index) {
272     comparator.setColumn(tableColumns[index]);
273   }
274
275   public RowComparator getRowComparator() {
276     return comparator;
277   }
278
279   public int getPageSize() {
280     return pager.getPageSize();
281   }
282
283   public void setPageSize(int newPageSize) {
284     pager.setPageSize(newPageSize);
285   }
286
287   public int getCurrentPage() {
288     return pager.getCurrentPage();
289   }
290
291   public void setCurrentPage(int newCurrentPage) {
292     pager.setCurrentPage(newCurrentPage);
293   }
294
295   public int getPageCount() {
296     return pager.getPageCount();
297   }
298
299   public Element JavaDoc render(RequestContext context, Document JavaDoc factory) throws Exception JavaDoc {
300     startRendering(context);
301
302     dispatcher.clear();
303
304     this.factory = factory;
305     this.root = factory.createElement("xtable-component");
306
307     // build decorator chain
308
TableModel model = this.getModel();
309     if (isSortable()) {
310       sorter.setDecoree(model);
311       model = sorter;
312     }
313     if (isPageable()) {
314       pager.setDecoree(model);
315       model = pager;
316     }
317
318     if (isSortable())
319       sorter.sort(getRowComparator());
320     renderHeading(model, context);
321     renderBody(model, context);
322     if (isPageable())
323       renderPager(model, context);
324
325     // add title
326
if (model.getTitle() != null && model.getTitle().length()>0)
327       root.setAttribute("title", model.getTitle());
328     if (isClosable())
329       root.setAttribute("closeId", closeHandlerId);
330     if (error != null)
331       root.setAttribute("error", error);
332
333     if (border != null)
334       root.setAttribute("border", border);
335     if (width != null)
336       root.setAttribute("width", width);
337     if (renderId != null)
338       root.setAttribute("renderId", renderId);
339
340     stopRendering();
341
342     return root;
343   }
344
345
346   private void startRendering(RequestContext context) {
347     selectionMgr.startRendering(context);
348     for (int i = 0; i < tableColumns.length; i++) {
349       CellRenderer r = tableColumns[i].getCellRenderer();
350       if (r instanceof RenderListener)
351         ((RenderListener) r).startRendering(context);
352     }
353   }
354
355   private void stopRendering() {
356     selectionMgr.stopRendering();
357     for (int i = 0; i < tableColumns.length; i++) {
358       CellRenderer r = tableColumns[i].getCellRenderer();
359       if (r instanceof RenderListener)
360         ((RenderListener) r).stopRendering();
361     }
362   }
363
364   void renderHeading(TableModel model, RequestContext context) throws FormatException {
365     int visibleColumns = 0;
366
367     // heading
368
Element JavaDoc tr = tr();
369
370     // extra column for selection
371
int selMode = getSelectionModel().getMode();
372     if (selMode != SelectionModel.NO_SELECTION) {
373       Element JavaDoc th = th(tr);
374       visibleColumns += 1;
375       if (selMode == SelectionModel.MULTIPLE_SELECTION)
376         th.setAttribute("selectId", selectButtonId);
377       else
378         text(th, "\u00a0"); // &nbsp;
379
}
380
381     // data columns
382
int N = model.getColumnCount();
383     for (int i = 0; i < N; i++) {
384       TableColumn tc = getTableColumn(i);
385       int columnIndex = tc.getColumnIndex();
386       if (!tc.isHidden()) {
387         Element JavaDoc th = th(tr);
388         th.setAttribute("id", DomUtils.randomId());
389         if (isSortable() && tc.isSortable()) {
390           StringBuffer JavaDoc img = new StringBuffer JavaDoc();
391
392           // here the letters "d" (descending) and "a" (ascending) are swapped
393
// this corresponds to the images
394
img.append(tc.isDescending() ? "a" : "d");
395
396           img.append(getRowComparator().getColumnIndex() == columnIndex ? "c" : "n");
397           th.setAttribute("sort", img.toString());
398           RequestListener h = new SortButtonHandler(tc);
399           dispatcher.addRequestListener(th.getAttribute("id"), null, h);
400         }
401         text(th, model.getColumnTitle(columnIndex));
402         visibleColumns += 1;
403       }
404     }
405     root.setAttribute("visibleColumns", "" + visibleColumns);
406
407     if(!colHeaders)
408       root.removeChild(tr);
409   }
410
411   void renderBody(TableModel model, RequestContext context) throws FormatException {
412     int rowCount = model.getRowCount();
413     int colCount = model.getColumnCount();
414     int selectionMode = getSelectionModel().getMode();
415
416     for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
417       Element JavaDoc tr = tr();
418       TableRow row = model.getRow(rowIndex);
419
420       // extra column if selectable
421
if (selectionMode != SelectionModel.NO_SELECTION) {
422         Element JavaDoc td = td(tr);
423         selectionMgr.renderButton(td, row);
424       }
425
426       for (int i = 0; i < colCount; i++) {
427         TableColumn tc = getTableColumn(i);
428         if (!tc.isHidden()) {
429           int columnIndex = tc.getColumnIndex();
430           Element JavaDoc td = td(tr);
431           CellRenderer renderer = tc.getCellRenderer();
432           renderer.render(context, td, row.getValue(columnIndex));
433         }
434       }
435     }
436   }
437
438   void renderPager(TableModel model, RequestContext context) {
439     int pageCount = pager.getPageCount();
440     
441     if (model.getRowCount() < 2)
442       return;
443
444     Element JavaDoc tr = tr();
445     Element JavaDoc td = td(tr);
446
447     // comupte colspan
448
int visibleColumns = countVisibleColumns(model);
449     td.setAttribute("colspan", Integer.toString(visibleColumns));
450
451     int currentPage = pager.getCurrentPage();
452
453     // add back buttons
454
if (currentPage > 0) {
455       DomUtils.appendText(td, "\u00a0");
456       addPageLink(td, 0, "first");
457       addPageLink(td, currentPage - 1, "prev");
458     }
459
460     // add "Page 1/5"
461
DomUtils.appendText(td, "\u00a0");
462     Object JavaDoc[] args = new Object JavaDoc[2];
463     args[0] = new Integer JavaDoc(currentPage + 1); // zero based
464
args[1] = new Integer JavaDoc(pageCount);
465     text(td, resources.getString("wcf.table.pages", args));
466
467     // add forward buttons
468
if (currentPage < pageCount - 1) {
469       DomUtils.appendText(td, "\u00a0");
470       addPageLink(td, currentPage + 1, "next");
471       addPageLink(td, pageCount - 1, "last");
472     }
473
474     // add "Goto Page"
475
if (pageCount > 1) {
476       DomUtils.appendText(td, "\u00a0");
477       Element JavaDoc e = DomUtils.appendElement(td, "xgotopage");
478       String JavaDoc label = resources.getString("wcf.table.goto.label");
479       e.setAttribute("label", label);
480       e.setAttribute("buttonId", gotoButtonId);
481       e.setAttribute("inputId", gotoInputId);
482       e.setAttribute("value", "" + (currentPage + 1));
483     }
484
485     // add "Rows / Page"
486
DomUtils.appendText(td, "\u00a0");
487     Element JavaDoc e = DomUtils.appendElement(td, "xgotopage");
488     String JavaDoc label = resources.getString("wcf.table.rowcnt.label");
489     e.setAttribute("label", label);
490     e.setAttribute("buttonId", pageSizeButtonId);
491     e.setAttribute("inputId", pageSizeInputId);
492     e.setAttribute("value", "" + pager.getPageSize());
493   }
494
495   private int countVisibleColumns(TableModel model) {
496     int visibleColumns = 0;
497     if (getSelectionModel().getMode() != SelectionModel.NO_SELECTION)
498       visibleColumns = 1;
499     int N = model.getColumnCount();
500     for (int i = 0; i < N; i++)
501       if (!getTableColumn(i).isHidden())
502         visibleColumns += 1;
503     return visibleColumns;
504   }
505
506   void addPageLink(Element JavaDoc td, int page, String JavaDoc direction) {
507     Element JavaDoc pg = factory.createElement("xpagenav");
508     td.appendChild(pg);
509     String JavaDoc id = DomUtils.randomId();
510     pg.setAttribute("id", id);
511     pg.setAttribute("page", Integer.toString(page + 1));
512     pg.setAttribute("direction", direction);
513     RequestListener h = new PageHandler(page);
514     dispatcher.addRequestListener(id, null, h);
515   }
516
517   class PageHandler implements RequestListener {
518     int page;
519
520     public PageHandler(int page) {
521       this.page = page;
522     }
523
524     public void request(RequestContext context) throws Exception JavaDoc {
525       Scroller.enableScroller(context);
526
527       // validate other forms
528
validate(context);
529       // update pageno
530
pager.setCurrentPage(page);
531     }
532   }
533
534   private class SortButtonHandler implements RequestListener {
535     TableColumn tc;
536
537     SortButtonHandler(TableColumn tc) {
538       this.tc = tc;
539     }
540
541     public void request(RequestContext context) throws Exception JavaDoc {
542       // Keep scroll position
543
Scroller.enableScroller(context);
544       // validate other forms
545
validate(context);
546       // change sort direction
547
if (tc.getColumnIndex() == comparator.getColumnIndex())
548         tc.setDescending(!tc.isDescending());
549       else
550         comparator.setColumn(tc);
551       sorter.sort(getRowComparator());
552     }
553   }
554
555   /**
556    * shall this table have a close button?
557    */

558   public boolean isClosable() {
559     return closable;
560   }
561
562   /**
563    * shall this table have a close button?
564    */

565   public void setClosable(boolean b) {
566     closable = b;
567   }
568
569   /**
570    * gets the border attribute of the generated table.
571    * Overrides the global stylesheet parameter "border".
572    * @return the border attribute or null
573    */

574   public String JavaDoc getBorder() {
575     return border;
576   }
577
578   /**
579    * sets the border attribute of the generated table.
580    * Overrides the global stylesheet parameter "border".
581    * @param border the border attribute or null to use the stylesheet parameter
582    */

583   public void setBorder(String JavaDoc border) {
584     this.border = border;
585   }
586
587   /**
588    * sets the width attribute of the generated table.
589    */

590   public void setWidth(String JavaDoc width) {
591     this.width = width;
592   }
593
594   /**
595    * sets the renderId attribute of the generated table.
596    * Overrides the global stylesheet parameter "renderId".
597    * @param renderId the renderId attribute or null to use the stylesheet parameter
598    */

599   public void setRenderId(String JavaDoc renderId) {
600     this.renderId = renderId;
601   }
602
603   /**
604    * gets the renderId attribute of the generated table.
605    * Overrides the global stylesheet parameter "renderId".
606    * @return the renderId attribute or null
607    */

608   public String JavaDoc getRenderId() {
609     return renderId;
610   }
611
612   Element JavaDoc tr() {
613     Element JavaDoc xtr = factory.createElement(tr);
614     root.appendChild(xtr);
615     return xtr;
616   }
617
618   Element JavaDoc th(Element JavaDoc tr) {
619     Element JavaDoc xth = factory.createElement(th);
620     tr.appendChild(xth);
621     return xth;
622   }
623
624   Element JavaDoc td(Element JavaDoc tr) {
625     Element JavaDoc xtd = factory.createElement(td);
626     tr.appendChild(xtd);
627     return xtd;
628   }
629
630   void text(Element JavaDoc parent, String JavaDoc text) {
631     Text JavaDoc t = factory.createTextNode(text);
632     parent.appendChild(t);
633   }
634
635   private String JavaDoc tr = "xtr";
636   private String JavaDoc td = "xtd";
637   private String JavaDoc th = "xth";
638
639   public void setTr(String JavaDoc newTr) {
640     tr = newTr;
641   }
642
643   public String JavaDoc getTr() {
644     return tr;
645   }
646
647   public void setTd(String JavaDoc newTd) {
648     td = newTd;
649   }
650
651   public String JavaDoc getTd() {
652     return td;
653   }
654
655   public void setTh(String JavaDoc newTh) {
656     th = newTh;
657   }
658
659   public String JavaDoc getTh() {
660     return th;
661   }
662
663   PagedTableModel getPager() {
664     return pager;
665   }
666
667   public TableColumn[] getTableColumns() {
668     return tableColumns;
669   }
670
671   /**
672    * sets the error message to display
673    * @param message the message to display or null to remove a previous error message
674    */

675   public void setError(String JavaDoc message) {
676     this.error = message;
677   }
678
679   public boolean isColHeaders() {
680     return colHeaders;
681   }
682
683   public void setColHeaders(boolean title) {
684     this.colHeaders = title;
685   }
686
687   public boolean isReadOnly() {
688     return selectionMgr.isReadOnly();
689   }
690
691   public void setReadOnly(boolean readOnly) {
692     selectionMgr.setReadOnly(readOnly);
693   }
694 }
Popular Tags