001 /* 002 Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.aspects.gui.web; 019 020 import java.io.IOException; 021 import java.io.PrintWriter; 022 import java.util.Collection; 023 import java.util.HashMap; 024 import java.util.Hashtable; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.Map; 028 import java.util.Vector; 029 import org.apache.log4j.Logger; 030 import org.objectweb.jac.aspects.gui.*; 031 import org.objectweb.jac.core.Naming; 032 import org.objectweb.jac.core.rtti.ClassItem; 033 import org.objectweb.jac.core.rtti.CollectionItem; 034 import org.objectweb.jac.core.rtti.FieldItem; 035 import org.objectweb.jac.core.rtti.MemberItem; 036 import org.objectweb.jac.core.rtti.MethodItem; 037 import org.objectweb.jac.util.ExtArrays; 038 039 public class Table extends AbstractCollection 040 implements HTMLViewer, TableListener 041 { 042 static Logger logger = Logger.getLogger("gui.table"); 043 static Logger loggerEvents = Logger.getLogger("gui.events"); 044 045 HTMLViewer[] cellViewers; 046 ExtendedTableModel tableModel; 047 048 public Table(ViewFactory factory, DisplayContext context, 049 CollectionItem collection, Object substance, 050 ExtendedTableModel model, 051 org.objectweb.jac.aspects.gui.CollectionItemView itemView) { 052 super(factory,context,collection,substance,model,itemView); 053 this.tableModel = model; 054 this.multiLineCollection = itemView.getMultiLineCollection(); 055 this.groupBy = itemView.getGroupBy(); 056 if (model!=null) { 057 this.cellViewers = new HTMLViewer[tableModel.getHeaders().length]; 058 setCellRenderers(); 059 } 060 } 061 062 CollectionItem multiLineCollection; 063 FieldItem groupBy; 064 065 public void setColumnsInfo(String[] headers, FieldItem[] fields, 066 ClassItem[] classes, ClassItem[] viewerClasses) { 067 if (!(headers.length==classes.length && 068 classes.length==viewerClasses.length && 069 viewerClasses.length==fields.length)) { 070 throw new RuntimeException("headers, fields, classes and "+ 071 "viewerClasses must be the same size"); 072 } 073 this.cellViewers = new HTMLViewer[headers.length]; 074 } 075 076 protected void setCellRenderers() { 077 MemberItem[] members = tableModel.getMembers(); 078 String[] headers = tableModel.getHeaders(); 079 080 for (int i=0; i<members.length; i++) { 081 if (members[i] instanceof FieldItem) { 082 cellViewers[i] = 083 (HTMLViewer)tableModel.getCellRenderer(this,i,factory,context); 084 } else if (members[i] instanceof MethodItem) { 085 MethodItem method = (MethodItem)members[i]; 086 try { 087 cellViewers[i] = (HTMLViewer)factory.createView( 088 method.getName(), 089 "Method", 090 new Object[] {substance,method},context); 091 } catch (Exception e) { 092 logger.error("Failed to instanciate TableCellRenderer "+ 093 method.getName()+" for column "+headers[i],e); 094 } 095 } 096 if (cellViewers[i] instanceof FieldView) 097 ((FieldView)cellViewers[i]).setAutoUpdate(false); 098 if (cellViewers[i] instanceof CollectionView) 099 ((CollectionView)cellViewers[i]).setEditor(false); 100 } 101 } 102 103 public void sort() { 104 if (sorter!=null) 105 sorter.sort(this); 106 } 107 108 protected boolean showRefreshButton() { 109 return super.showRefreshButton() 110 || (filterEditors!=null && !filterEditors.isEmpty()); 111 } 112 113 public void onRefreshCollection() { 114 if (filterEditors != null) { 115 JacRequest request = ((WebDisplay)context.getDisplay()).getRequest(); 116 Iterator it = filterEditors.values().iterator(); 117 while (it.hasNext()) { 118 ObjectChooser chooser = (ObjectChooser)it.next(); 119 chooser.readValue(request.getParameter(chooser.getLabel())); 120 } 121 } 122 checkRange(); 123 super.onRefreshCollection(); 124 } 125 126 protected void init() { 127 if (model!=null) { 128 sorter = ((ExtendedTableModel)model).getSorter(); 129 filter = ((ExtendedTableModel)model).getFilter(); 130 if (filter!=null) { 131 filterEditors = filter.buildFilterEditors(factory,context); 132 Iterator it = filterEditors.values().iterator(); 133 while (it.hasNext()) { 134 ObjectChooser chooser = (ObjectChooser)it.next(); 135 chooser.setParentView(this); 136 } 137 } 138 } 139 } 140 141 // FieldItem -> HTMLViewer 142 Map filterEditors; 143 144 /** 145 * Removes editors of embedded added object 146 */ 147 protected void clearFilterEditors() { 148 if (filterEditors!=null) { 149 Iterator it = filterEditors.values().iterator(); 150 while (it.hasNext()) { 151 FieldEditor editor = (FieldEditor)it.next(); 152 context.removeEditor(editor); 153 } 154 filterEditors.clear(); 155 } 156 } 157 158 /** 159 * Sorts the collection. 160 * 161 * @param column the index of the column used to sort 162 */ 163 public void sort(int column) { 164 sorter.sortByColumn(column, true); 165 } 166 167 // HTMLViewer interface 168 169 public void genHTML(PrintWriter out) throws IOException { 170 MethodItem adder = collection.getAdder(); 171 boolean embeddedAdder = 172 adder!=null && GuiAC.getView(adder,itemView.getName()).isEmbedded() && 173 GuiAC.isAutoCreate(collection); 174 if (model.getRowCount()==0 && !embeddedAdder) { 175 out.println("none"); 176 } 177 178 genHeader(out); 179 180 if (model.getRowCount()==0 && !embeddedAdder && filter==null) { 181 return; 182 } 183 184 logger.debug(itemView+".Embedded editors="+itemView.isEmbeddedEditors()); 185 186 String[] headers = tableModel.getHeaders(); 187 188 out.println("<table class=\"table\">"); 189 out.println(" <thead>"); 190 out.println(" <tr>"); 191 if (showRowNumbers) { 192 out.println(" <th style=\"width:"+ 193 ((""+model.getRowCount()).length())+"ex\" class=\"empty\"></th>"); 194 } 195 for (int i=0; i<headers.length; i++) { 196 if (headers[i]!=null) { 197 out.print(" <th>"); 198 out.print(sortLink(i,headers[i])); 199 out.println("</th>"); 200 } else { 201 out.print(" <th class=\"empty\"></th>"); 202 } 203 } 204 if (viewableItems) 205 out.println(" <th style=\"width:1px\" class=\"empty\"></th>"); // view button 206 if (GuiAC.isRemovable(collection)) 207 out.println(" <th style=\"width:1px\" class=\"empty\"></th>"); // remove button 208 out.println(" </tr>"); 209 out.println(" </thead>"); 210 211 boolean bodyOpened = false; 212 213 Object defaultsObject = null; 214 215 // Column filters 216 if (filter!=null) { 217 genColumnFilters(out); 218 } 219 220 bodyOpened = false; 221 // Default value editors in the table 222 if (GuiAC.hasEditableDefaultValues(collection) && embeddedAdder) { 223 try { 224 ClassItem componentType = collection.getComponentType(); 225 defaultsObject = Naming.getObject("defaults."+collection.getLongName()); 226 if (defaultsObject==null) { 227 Naming.setName("defaults."+collection.getLongName()); 228 defaultsObject = componentType.newInstance(); 229 clearDefaultEditors(); 230 } 231 out.println(" <tbody class=\"defaultObject\">"); 232 out.println(" <tr class=\"vspace\"></tr>"); 233 out.println(" <tr class=\"defaultObject\">"); 234 FieldItem[] defaultsFields = GuiAC.getDefaultsAttributesOrder(componentType); 235 if (showRowNumbers) { 236 out.println(" <td></td>"); 237 } 238 for (int col=0; col<tableModel.getColumnCount(); col++) { 239 out.print(" <td>"); 240 MemberItem member = tableModel.getMembers()[col]; 241 if (defaultsFields!=null && !ExtArrays.contains(defaultsFields,member)) { 242 out.println("</td>"); 243 continue; 244 } 245 GuiAC.pushGraphicContext(member); 246 try { 247 if (member instanceof FieldItem && 248 !(member instanceof CollectionItem)) 249 { 250 MethodItem setter = ((FieldItem)member).getSetter(); 251 if (GuiAC.isCreationAttribute((FieldItem)member) && 252 setter!=null) { 253 // <BAD>WE SHOULD ONLY BUILD THE EDITORS ONCE</BAD> 254 FieldEditor editor = GenericFactory.getEditorComponent( 255 factory, context, defaultsObject, setter, 0, true, null); 256 defaultsEditors.add(editor); 257 context.addEditor(editor); 258 ((HTMLViewer)editor).genHTML(out); 259 editor.setEmbedded(true); 260 //editorContainer.addEditor(editor); 261 //container.addView(editor); 262 } 263 } else if (member instanceof CollectionItem) { 264 if (GuiAC.isCreationAttribute((FieldItem)member)) { 265 CollectionItem collection = (CollectionItem)member; 266 HTMLViewer view = (HTMLViewer) 267 GenericFactory.getCollectionPane( 268 factory,context,defaultsObject,null,null,collection); 269 view.genHTML(out); 270 } 271 } 272 } finally { 273 GuiAC.popGraphicContext(); 274 } 275 out.println("</td>"); 276 } 277 out.println(" <td>"+eventURL("set","onSetDefaults","")+"</td>"); 278 out.println(" </tr>"); 279 out.println(" <tr class=\"vspace\"></tr>"); 280 out.println(" </tbody>"); 281 } catch (Exception e) { 282 e.printStackTrace(); 283 } 284 } 285 286 logger.debug("multiLineCollection="+ 287 (multiLineCollection!=null?multiLineCollection.getName():"none")); 288 289 // Actual rows 290 Object currentGroup = null; 291 int groupSpan = 1; 292 MemberItem[] members = tableModel.getMembers(); 293 boolean first = true; // First line of multi-line collection or groupBy? 294 int groupIndex = 0; 295 for (int index=startIndex; 296 (!split || index<startIndex+rowsPerPage) && index<model.getRowCount(); 297 index++) 298 { 299 Object substance = tableModel.getObject(index); 300 if (!bodyOpened) { 301 openTBody(out); 302 bodyOpened = true; 303 } 304 if (multiLineCollection!=null) { 305 first = true; // First line of multi-line collection ? 306 Collection multi = multiLineCollection.getActualCollectionThroughAccessor(substance); 307 String rowspan = " rowspan=\""+multi.size()+"\""; 308 Iterator it = multi.iterator(); 309 if (it.hasNext()) { 310 while (it.hasNext()) { 311 if (first) 312 groupIndex++; 313 openRow(out,index,groupIndex%2==0); 314 Object multiSubstance = it.next(); 315 if (first && showRowNumbers) { 316 out.println(" <td class=\"index\""+rowspan+">"+(index+1)+"</td>"); 317 } 318 for (int col=0; col<tableModel.getColumnCount(); col++) { 319 MemberItem member = members[col]; 320 if (member instanceof FieldItem 321 && ((FieldItem)member).startsWith(multiLineCollection)) { 322 FieldItem multiField = 323 ((FieldItem)member).getRelativeField(multiLineCollection); 324 genCell(out,index,col,multiSubstance, 325 multiField, 326 multiField.getThroughAccessor(multiSubstance), 327 ""); 328 } else if (first) { 329 genCell(out,index,col,substance,member, 330 tableModel.getValueAt(index,col),rowspan); 331 } 332 } 333 if (first) { 334 if (viewableItems) 335 genViewCell(out,index,rowspan); 336 genRemoveCell(out,index,rowspan); 337 } 338 out.println(" </tr>"); 339 first = false; 340 } 341 } else { 342 genRow(out,index,substance,members); 343 } 344 } else if (groupBy!=null) { 345 Object groupValue = groupBy.getThroughAccessor(substance); 346 if (currentGroup!=groupValue) { 347 logger.debug(index+": New group "+groupValue); 348 currentGroup = groupValue; 349 groupSpan = 1; 350 first = true; 351 for (int i=index+1; 352 (!split || i<startIndex+rowsPerPage) && i<model.getRowCount(); 353 i++) { 354 if (groupBy.getThroughAccessor(tableModel.getObject(i))!=currentGroup) 355 break; 356 groupSpan++; 357 } 358 } 359 if (first) 360 groupIndex++; 361 openRow(out,index,groupIndex%2==1); 362 if (showRowNumbers) { 363 out.println(" <td class=\"index\">"+(index+1)+"</td>"); 364 } 365 for (int col=0; col<tableModel.getColumnCount(); col++) { 366 MemberItem member = members[col]; 367 if (member instanceof FieldItem 368 && (((FieldItem)member).startsWith(groupBy) || member==groupBy)) { 369 if (first) { 370 String rowspan = groupSpan>1 ? (" rowspan=\""+groupSpan+"\"") : ""; 371 genCell(out,index,col,substance,member, 372 tableModel.getValueAt(index,col),rowspan); 373 } 374 } else { 375 genCell(out,index,col,substance,member, 376 tableModel.getValueAt(index,col),""); 377 } 378 } 379 if (viewableItems) 380 genViewCell(out,index,""); 381 genRemoveCell(out,index,""); 382 out.println(" </tr>"); 383 first = false; 384 } else { 385 genRow(out,index,substance,members); 386 } 387 388 } 389 if (bodyOpened) { 390 out.println(" </tbody>"); 391 bodyOpened = false; 392 } 393 394 // Embedded adder in the table 395 String focusId = null; // Id of HTML element to focus (if any) 396 if (GuiAC.isAddable(substance,collection)) { 397 try { 398 ClassItem componentType = collection.getComponentType(); 399 if (embeddedAdder) { 400 if (addedObject==null) { 401 addedObject = componentType.newInstance(); 402 EventHandler.initAutocreatedObject( 403 addedObject,substance,collection); 404 initAddedObject(addedObject,defaultsObject); 405 clearEmbeddedEditors(true); 406 } 407 out.println(" <tbody>"); 408 out.println(" <tr class=\"vspace\"></tr>"); 409 out.println(" <tr class=\"addedObject\">"); 410 if (showRowNumbers) { 411 out.println(" <td></td>"); 412 } 413 for (int col=0; col<tableModel.getColumnCount(); col++) { 414 out.print(" <td>"); 415 MemberItem member = tableModel.getMembers()[col]; 416 GuiAC.pushGraphicContext(member); 417 String keyPressEvent = 418 "return commitFormOnEnter(event,this,'event=onAddEmbedded&source="+getId()+"')\""; 419 try { 420 if (member instanceof FieldItem && 421 !(member instanceof CollectionItem)) 422 { 423 MethodItem setter = ((FieldItem)member).getSetter(); 424 if (GuiAC.isCreationAttribute((FieldItem)member) && 425 setter!=null) { 426 FieldEditor editor = GenericFactory.getEditorComponent( 427 factory, context, addedObject, setter, 0, true, null); 428 if (focusId==null) 429 focusId = editor.getLabel(); 430 embeddedEditors.add(editor); 431 ((HTMLEditor)editor).setAttribute("onkeypress",keyPressEvent); 432 ((HTMLViewer)editor).genHTML(out); 433 editor.setEmbedded(true); 434 context.addEditor(editor); 435 //editorContainer.addEditor(editor); 436 //container.addView(editor); 437 } 438 } else if (member instanceof CollectionItem) { 439 if (GuiAC.isCreationAttribute((FieldItem)member)) { 440 CollectionItem coll = (CollectionItem)member; 441 CollectionItem index = (CollectionItem) 442 coll.getComponentType().getAttribute(GuiAC.INDEXED_FIELD_SELECTOR); 443 if (index==null) { 444 HTMLViewer view = (HTMLViewer) 445 GenericFactory.getCollectionPane( 446 factory,context,addedObject,null,null,coll); 447 view.genHTML(out); 448 } else { 449 FieldEditor editor = factory.createEditor( 450 "editor "+Naming.getName(substance)+"."+coll.getName(), 451 "IndicesSelector", 452 new Object[] {coll,addedObject, 453 new ListModel(coll,addedObject), 454 GuiAC.getView(coll,itemView.getName())}, 455 context); 456 embeddedEditors.add(editor); 457 ((HTMLEditor)editor).setAttribute("onkeypress",keyPressEvent); 458 ((HTMLViewer)editor).genHTML(out); 459 editor.setEmbedded(true); 460 context.addEditor(editor); 461 } 462 } 463 } 464 } catch(Exception e) { 465 logger.error("Failed to gen HTML for embedded object to add, column "+ 466 tableModel.getHeaders()[col],e); 467 } finally { 468 GuiAC.popGraphicContext(); 469 } 470 out.println("</td>"); 471 } 472 out.println(" <td>"+eventURL(GuiAC.getLabelAdd(),"onAddEmbedded","")+"</td>"); 473 out.println(" </tr>"); 474 out.println(" </tbody>"); 475 } 476 } catch (Exception e) { 477 e.printStackTrace(); 478 } 479 } 480 481 FieldItem additionalRow = itemView.getAdditionalRow(); 482 if (additionalRow!=null) { 483 out.println(" <tbody class=\"additionalRow\">"); 484 out.println(" <tr>"); 485 if (showRowNumbers) { 486 out.println(" <td class=\"empty\"></td>"); 487 } 488 Object row = additionalRow.getThroughAccessor(substance); 489 for (int col=0; col<tableModel.getColumnCount(); col++) { 490 MemberItem member = members[col]; 491 if (member instanceof FieldItem && row!=null) { 492 genCell(out,-1,col,row,member,((FieldItem)member).getThroughAccessor(row),""); 493 } else { 494 genCell(out,-1,col,row,member,null,""); 495 } 496 } 497 if (viewableItems) { 498 out.println(" <td class=\"empty\"></td>"); 499 } 500 if (GuiAC.isRemovable(collection)) { 501 out.println(" <td class=\"empty\"></td>"); 502 } 503 out.println(" </tr>"); 504 out.println(" </tbody>"); 505 } 506 507 out.println("</table>"); 508 509 if (focusId!=null) { 510 out.println("<script type=\"text/javascript\">"+ 511 "element=getElementById('"+focusId+"');"+ 512 "element.focus();"+ 513 "window.scroll(0,10000);"+ 514 "</script>"); 515 } 516 } 517 518 protected void genRow(PrintWriter out, int index, Object substance, 519 MemberItem[] members) { 520 openRow(out,index,index%2==0); 521 if (showRowNumbers) { 522 out.println(" <td class=\"index\">"+(index+1)+"</td>"); 523 } 524 for (int col=0; col<tableModel.getColumnCount(); col++) { 525 MemberItem member = members[col]; 526 if (multiLineCollection!=null 527 && member instanceof FieldItem 528 && ((FieldItem)member).startsWith(multiLineCollection)) { 529 out.println(" <td></td>"); 530 } else { 531 genCell(out,index,col,substance,member, 532 tableModel.getValueAt(index,col),""); 533 } 534 } 535 if (viewableItems) 536 genViewCell(out,index,""); 537 genRemoveCell(out,index,""); 538 out.println(" </tr>"); 539 } 540 541 protected void genCell(PrintWriter out, int index, int col, 542 Object substance, MemberItem member, Object value, 543 String rowspan) 544 { 545 out.print(" <td"+rowspan+">"); 546 try { 547 HTMLViewer viewer = null; 548 if (member instanceof FieldItem) { 549 FieldItem field = (FieldItem)member; 550 if (itemView.isEmbeddedEditors(field)) 551 viewer = getFieldEditor(field,substance); 552 } 553 if (viewer!=null) { 554 viewer.genHTML(out); 555 } else { 556 if (cellViewers[col] instanceof Method) { 557 out.println(" <a href=\""+eventURL("onTableInvoke")+ 558 "&index="+index+"&method="+ 559 (member).getName()+"\">"+ 560 (GuiAC.getLabel(member))+"</a>"); 561 562 } else { 563 FieldView cellViewer = (FieldView)cellViewers[col]; 564 if (cellViewer!=null) { 565 if (cellViewer instanceof TableCellViewer) { 566 ((TableCellViewer)cellViewer).setRow(index); 567 ((TableCellViewer)cellViewer).setColumn(col); 568 } 569 if (cellViewer instanceof LinkGenerator) { 570 ((LinkGenerator)cellViewer).setEnableLinks(itemView.areLinksEnabled()); 571 } 572 if (cellViewer instanceof CollectionView) 573 ((CollectionView)cellViewer).updateModel(substance); 574 else { 575 cellViewer.setSubstance(substance); 576 cellViewer.setValue(value); 577 } 578 if (cellViewer instanceof ReferenceView) { 579 ((ReferenceView)cellViewer).setEventURL( 580 eventURL("onCellSelection")+"&row="+index+"&col="+col); 581 } 582 ((HTMLViewer)cellViewer).genHTML(out); 583 } else { 584 if (value!=null) { 585 out.print(GuiAC.toString(value)); 586 } 587 } 588 } 589 } 590 } catch (Exception e) { 591 logger.error( 592 "Failed to genHTML for cell["+ 593 tableModel.getHeaders()[col]+","+index+ 594 "] of "+collection.getName(),e); 595 } 596 out.println("</td>"); 597 } 598 599 protected void genColumnFilters(PrintWriter out) throws IOException { 600 out.println(" <tbody class=\"filters\">"); 601 out.println(" <tr class=\"filters\">"); 602 if (showRowNumbers) { 603 out.println(" <td></td>"); 604 } 605 for (int col=0; col<tableModel.getColumnCount(); col++) { 606 MemberItem member = tableModel.getMembers()[col]; 607 if (member instanceof FieldItem && 608 filter.isFiltered((FieldItem)member)) { 609 out.print(" <td>"); 610 ((HTMLViewer)filterEditors.get(member)).genHTML(out); 611 out.println(" </td>"); 612 } else { 613 out.println(" <td></td>"); 614 } 615 } 616 out.println(" </tr>"); 617 out.println(" </tbody>"); 618 } 619 620 protected void genViewCell(PrintWriter out, int index, String rowspan) { 621 out.print(" <td"+rowspan+">"); 622 if (collection.getAttribute(GuiAC.NEW_WINDOW)!=null) { 623 out.print("<a target=\""+collection.getName()+"\""+ 624 " href=\""+eventURL("onView")+ 625 "&index="+index+"&\">"+ 626 "details</a>"); 627 } else { 628 out.print(viewLink(index)); 629 } 630 out.println("</td>"); 631 } 632 633 protected void genRemoveCell(PrintWriter out, int index, String rowspan) { 634 if (GuiAC.isRemovable(collection)) { 635 out.print("<td"+rowspan+">"); 636 if (isEditor) 637 out.print(removeLink(index)); 638 out.println("</td>"); 639 } 640 } 641 642 protected boolean viewOnDoubleClick = true; 643 /** 644 * Print opening tag for a row 645 * 646 * @param out where to wrte the HTML code 647 * @param index index of the row to open 648 * @param even wether the <tr> should have the "even" or "odd" class 649 */ 650 protected void openRow(PrintWriter out, int index, boolean even) { 651 String event = ""; 652 String cls = ""; 653 if (viewOnDoubleClick && viewableItems) { 654 event = "ondblclick=\"openURL('"+eventURL("onView")+"&index="+index+"')\""; 655 cls = " highlight"; 656 } 657 if (selected==index) 658 out.println(" <tr class=\"selected"+cls+"\" "+event+">"); 659 else 660 out.println(" <tr class=\""+ 661 (even?"even":"odd")+cls+"\" "+event+">"); 662 } 663 664 /** 665 * Print opening TBODY tag containg rows 666 * @param out 667 */ 668 protected void openTBody(PrintWriter out) { 669 out.println(" <tbody"+((viewOnDoubleClick&&viewableItems)?" class=\"highlight\"":"")+">"); 670 } 671 672 /** 673 * Returns a cell editor for a field of an object. Editors are 674 * cached, so you'll always get the same object for the same field 675 * and substance, unless clearCellEditors() is called. 676 * @see #clearCellEditors() 677 */ 678 protected HTMLViewer getFieldEditor(FieldItem field, Object substance) { 679 HTMLViewer editor = null; 680 Map fieldEditors = (Map)cellEditors.get(field); 681 if (fieldEditors!=null) { 682 editor = (HTMLViewer)fieldEditors.get(substance); 683 } else { 684 fieldEditors = new HashMap(); 685 cellEditors.put(field,fieldEditors); 686 } 687 if (editor==null) { 688 if (!(field instanceof CollectionItem)) 689 { 690 MethodItem setter = field.getSetter(); 691 if (setter!=null) { 692 editor = (HTMLViewer)GenericFactory.getEditorComponent( 693 factory, context, field.getSubstance(substance), setter, 0, true, null); 694 } 695 } else { 696 CollectionItem coll = (CollectionItem)field; 697 CollectionItem index = (CollectionItem) 698 coll.getComponentType().getAttribute(GuiAC.INDEXED_FIELD_SELECTOR); 699 if (index==null) { 700 editor = (HTMLViewer)GenericFactory.getCollectionPane( 701 factory,context,substance,null,itemView,coll); 702 } else { 703 editor = (HTMLViewer)factory.createEditor( 704 "editor "+Naming.getName(substance)+"."+coll.getName(), 705 "IndicesSelector", 706 new Object[] {coll,substance, 707 new ListModel(coll,substance), 708 GuiAC.getView(coll,itemView.getName())}, 709 context); 710 } 711 } 712 ((View)editor).setParentView(this); 713 fieldEditors.put(substance,editor); 714 if (editor instanceof FieldEditor) { 715 ((FieldEditor)editor).setEmbedded(true); 716 context.addEditor((FieldEditor)editor); 717 } 718 if (editor instanceof ReferenceEditor) { 719 ((ReferenceEditor)editor).setEditable(false); 720 } 721 } 722 if (editor instanceof HTMLEditor) { 723 ((HTMLEditor)editor).setAttribute("ondblclick","event.stopPropagation();"); 724 } 725 logger.debug("editor["+field.getName()+","+substance+"] -> "+editor); 726 return editor; 727 } 728 729 /** 730 * Removes editors of embedded added object 731 */ 732 protected void clearEmbeddedEditors(boolean validate) { 733 Iterator it = embeddedEditors.iterator(); 734 while (it.hasNext()) { 735 FieldEditor editor = (FieldEditor)it.next(); 736 editor.close(validate); 737 context.removeEditor(editor); 738 } 739 embeddedEditors.clear(); 740 } 741 742 /** 743 * Removes editors of embedded added object 744 */ 745 protected void clearDefaultEditors() { 746 Iterator it = defaultsEditors.iterator(); 747 while (it.hasNext()) { 748 FieldEditor editor = (FieldEditor)it.next(); 749 context.removeEditor(editor); 750 } 751 defaultsEditors.clear(); 752 } 753 754 // FieldItem -> (Object -> FieldEditor) 755 Hashtable cellEditors = new Hashtable(); 756 757 /** 758 * Removes editors of embedded added object 759 */ 760 protected void clearCellEditors(boolean validate) { 761 Iterator it = cellEditors.values().iterator(); 762 while (it.hasNext()) { 763 Iterator editors = ((Map)it.next()).values().iterator(); 764 while (editors.hasNext()) { 765 View editor = (View)editors.next(); 766 if (editor!=null) 767 editor.close(validate); 768 context.removeEditor(editor); 769 } 770 } 771 cellEditors.clear(); 772 } 773 774 public void close(boolean validate) { 775 super.close(validate); 776 clearEmbeddedEditors(validate); 777 clearDefaultEditors(); 778 clearCellEditors(validate); 779 clearFilterEditors(); 780 } 781 782 /** 783 * Initialize fields of added object from one of defaultsObject 784 */ 785 protected void initAddedObject(Object addedObject, Object defaultsObject) { 786 if (defaultsObject==null || addedObject==null) { 787 return; 788 } 789 for (int col=0; col<tableModel.getColumnCount(); col++) { 790 MemberItem member = tableModel.getMembers()[col]; 791 if (member instanceof FieldItem && !(member instanceof CollectionItem)) { 792 FieldItem field = (FieldItem)member; 793 MethodItem setter = field.getSetter(); 794 if (GuiAC.isCreationAttribute(field) && setter!=null) { 795 Object value = field.getThroughAccessor(defaultsObject); 796 try { 797 field.set(addedObject,value); 798 } catch (Exception e) { 799 logger.error("Failed to set default value for field "+field,e); 800 } 801 } 802 } 803 } 804 } 805 806 public void onCellSelection(int row, int col) { 807 MemberItem[] members = tableModel.getMembers(); 808 EventHandler.get().onSelection(context,(FieldItem)members[col], 809 tableModel.getObject(row,col), 810 null,null,true); 811 } 812 813 List embeddedEditors = new Vector(); 814 Object addedObject = null; 815 816 public void onEmbeddedAddToCollection() { 817 JacRequest request = WebDisplay.getRequest(); 818 loggerEvents.debug("onEmbeddedAddToCollection "+collection.getName()+" "+request); 819 for (int i=0; i<embeddedEditors.size(); i++) { 820 FieldEditor editor = (FieldEditor)embeddedEditors.get(i); 821 editor.close(true); 822 } 823 EventHandler.get().onInvoke( 824 context, 825 new InvokeEvent( 826 this, 827 substance,collection.getAdder(), 828 new Object[] {addedObject}), 829 false, 830 null,null); 831 clearEmbeddedEditors(true); 832 /** 833 // onView(addedObject); 834 835 It does not work because 836 837 a) onInvoke() above is asynchronous and starts its own 838 thread, so we are not sure addedObject is added 839 "completely" (the table model may not be up to date for 840 instance) 841 842 b) InvokeThread already calls WebDisplay.refresh(), so 843 calling it again in onView() will fail 844 845 */ 846 addedObject = null; 847 } 848 849 List defaultsEditors = new Vector(); 850 851 public void onSetDefaults() { 852 loggerEvents.debug("onSetDefaults "+collection.getName()); 853 initAddedObject(addedObject, 854 Naming.getObject("defaults."+collection.getLongName())); 855 context.getDisplay().refresh(); 856 } 857 858 public void onHeaderClick(int column) { 859 SortCriteria criteria = sorter.getSortCriteria(column); 860 if (criteria!=null) { 861 if (criteria.isAscending()) { 862 criteria.toggleAscending(); 863 sorter.sortByColumn(column,criteria.isAscending()); 864 } else { 865 sorter.sortByColumn(-1,criteria.isAscending()); 866 } 867 } else { 868 sorter.sortByColumn(column,true); 869 } 870 context.getDisplay().refresh(); 871 } 872 873 public View onRowEvent(int row, int col) { 874 FieldView cellViewer = 875 (FieldView)tableModel.getCellRenderer(this,col,factory,context); 876 cellViewer.setValue(tableModel.getValueAt(row,col)); 877 return cellViewer; 878 } 879 880 }