1 13 package com.tonbeller.wcf.table; 14 15 import org.w3c.dom.Document ; 16 import org.w3c.dom.Element ; 17 import org.w3c.dom.Text ; 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 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 border = null; 47 private String width = null; 48 private String renderId = null; 49 private String error = null; 50 51 SelectionMgr selectionMgr; 52 RowComparator comparator = new RowComparator(); 53 Dispatcher dispatcher = new DispatcherSupport(); 54 55 57 SortedTableModel sorter = new SortedTableModel(); 58 PagedTableModel pager = new PagedTableModel(); 59 Document factory; 60 Element root; 61 62 String closeHandlerId; 63 64 class CloseHandler implements RequestListener { 65 public void request(RequestContext context) throws Exception { 66 setVisible(false); 67 } 68 } 69 70 String selectButtonId; 71 72 class SelectButtonHandler implements RequestListener { 73 public void request(RequestContext context) throws Exception { 74 Scroller.enableScroller(context); 75 76 validate(context); 78 79 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 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 gotoButtonId; 119 String gotoInputId; 120 121 class GotoButtonHandler implements RequestListener { 122 public GotoButtonHandler() { 123 } 124 125 public void request(RequestContext context) throws Exception { 126 Scroller.enableScroller(context); 127 validate(context); 129 try { 130 int page = Integer.parseInt(context.getParameter(gotoInputId)); 131 pager.setCurrentPage(page - 1); 132 } catch (NumberFormatException e) { 133 } 135 } 136 } 137 138 String pageSizeButtonId; 139 String pageSizeInputId; 140 141 class PageSizeButtonHandler implements RequestListener { 142 public PageSizeButtonHandler() { 143 } 144 145 public void request(RequestContext context) throws Exception { 146 Scroller.enableScroller(context); 147 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 e) { 155 } 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 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 sorter.setDecoree(model); 185 pager.setDecoree(sorter); 186 187 setModel(model); 188 } 189 190 196 public TableComponent(String 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 { 204 super.initialize(context); 205 this.resources = context.getResources(TableComponent.class); 206 } 207 208 209 public TableColumn getTableColumn(int columnIndex) { 210 return tableColumns[columnIndex]; 211 } 212 213 214 public void setTableColumn(int columnIndex, TableColumn tableColumn) { 215 tableColumns[columnIndex] = tableColumn; 216 } 217 218 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 236 public TableModel getModel() { 237 return tableModel; 238 } 239 240 241 public void setSelectionModel(SelectionModel selectionModel) { 242 selectionMgr.setSelectionModel(selectionModel); 243 } 244 245 246 public SelectionModel getSelectionModel() { 247 return selectionMgr.getSelectionModel(); 248 } 249 250 251 public void setSortable(boolean newSortable) { 252 sortable = newSortable; 253 } 254 255 256 public boolean isSortable() { 257 return sortable; 258 } 259 260 261 public void setPageable(boolean newPageable) { 262 pageable = newPageable; 263 } 264 265 266 public boolean isPageable() { 267 return pageable; 268 } 269 270 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 render(RequestContext context, Document factory) throws Exception { 300 startRendering(context); 301 302 dispatcher.clear(); 303 304 this.factory = factory; 305 this.root = factory.createElement("xtable-component"); 306 307 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 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 Element tr = tr(); 369 370 int selMode = getSelectionModel().getMode(); 372 if (selMode != SelectionModel.NO_SELECTION) { 373 Element th = th(tr); 374 visibleColumns += 1; 375 if (selMode == SelectionModel.MULTIPLE_SELECTION) 376 th.setAttribute("selectId", selectButtonId); 377 else 378 text(th, "\u00a0"); } 380 381 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 th = th(tr); 388 th.setAttribute("id", DomUtils.randomId()); 389 if (isSortable() && tc.isSortable()) { 390 StringBuffer img = new StringBuffer (); 391 392 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 tr = tr(); 418 TableRow row = model.getRow(rowIndex); 419 420 if (selectionMode != SelectionModel.NO_SELECTION) { 422 Element 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 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 tr = tr(); 445 Element td = td(tr); 446 447 int visibleColumns = countVisibleColumns(model); 449 td.setAttribute("colspan", Integer.toString(visibleColumns)); 450 451 int currentPage = pager.getCurrentPage(); 452 453 if (currentPage > 0) { 455 DomUtils.appendText(td, "\u00a0"); 456 addPageLink(td, 0, "first"); 457 addPageLink(td, currentPage - 1, "prev"); 458 } 459 460 DomUtils.appendText(td, "\u00a0"); 462 Object [] args = new Object [2]; 463 args[0] = new Integer (currentPage + 1); args[1] = new Integer (pageCount); 465 text(td, resources.getString("wcf.table.pages", args)); 466 467 if (currentPage < pageCount - 1) { 469 DomUtils.appendText(td, "\u00a0"); 470 addPageLink(td, currentPage + 1, "next"); 471 addPageLink(td, pageCount - 1, "last"); 472 } 473 474 if (pageCount > 1) { 476 DomUtils.appendText(td, "\u00a0"); 477 Element e = DomUtils.appendElement(td, "xgotopage"); 478 String 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 DomUtils.appendText(td, "\u00a0"); 487 Element e = DomUtils.appendElement(td, "xgotopage"); 488 String 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 td, int page, String direction) { 507 Element pg = factory.createElement("xpagenav"); 508 td.appendChild(pg); 509 String 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 { 525 Scroller.enableScroller(context); 526 527 validate(context); 529 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 { 542 Scroller.enableScroller(context); 544 validate(context); 546 if (tc.getColumnIndex() == comparator.getColumnIndex()) 548 tc.setDescending(!tc.isDescending()); 549 else 550 comparator.setColumn(tc); 551 sorter.sort(getRowComparator()); 552 } 553 } 554 555 558 public boolean isClosable() { 559 return closable; 560 } 561 562 565 public void setClosable(boolean b) { 566 closable = b; 567 } 568 569 574 public String getBorder() { 575 return border; 576 } 577 578 583 public void setBorder(String border) { 584 this.border = border; 585 } 586 587 590 public void setWidth(String width) { 591 this.width = width; 592 } 593 594 599 public void setRenderId(String renderId) { 600 this.renderId = renderId; 601 } 602 603 608 public String getRenderId() { 609 return renderId; 610 } 611 612 Element tr() { 613 Element xtr = factory.createElement(tr); 614 root.appendChild(xtr); 615 return xtr; 616 } 617 618 Element th(Element tr) { 619 Element xth = factory.createElement(th); 620 tr.appendChild(xth); 621 return xth; 622 } 623 624 Element td(Element tr) { 625 Element xtd = factory.createElement(td); 626 tr.appendChild(xtd); 627 return xtd; 628 } 629 630 void text(Element parent, String text) { 631 Text t = factory.createTextNode(text); 632 parent.appendChild(t); 633 } 634 635 private String tr = "xtr"; 636 private String td = "xtd"; 637 private String th = "xth"; 638 639 public void setTr(String newTr) { 640 tr = newTr; 641 } 642 643 public String getTr() { 644 return tr; 645 } 646 647 public void setTd(String newTd) { 648 td = newTd; 649 } 650 651 public String getTd() { 652 return td; 653 } 654 655 public void setTh(String newTh) { 656 th = newTh; 657 } 658 659 public String getTh() { 660 return th; 661 } 662 663 PagedTableModel getPager() { 664 return pager; 665 } 666 667 public TableColumn[] getTableColumns() { 668 return tableColumns; 669 } 670 671 675 public void setError(String 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 |