1 30 package com.genimen.djeneric.tools.specifier.editor; 31 32 import java.awt.Component ; 33 import java.util.ArrayList ; 34 35 import javax.swing.DefaultComboBoxModel ; 36 import javax.swing.JCheckBox ; 37 import javax.swing.JComboBox ; 38 import javax.swing.JTable ; 39 import javax.swing.JTextField ; 40 import javax.swing.table.TableCellEditor ; 41 import javax.swing.table.TableCellRenderer ; 42 43 import com.genimen.djeneric.language.Messages; 44 import com.genimen.djeneric.repository.DjAssociation; 45 import com.genimen.djeneric.repository.DjDomain; 46 import com.genimen.djeneric.repository.DjDomainValue; 47 import com.genimen.djeneric.repository.DjExtent; 48 import com.genimen.djeneric.repository.DjList; 49 import com.genimen.djeneric.repository.DjObject; 50 import com.genimen.djeneric.repository.DjPersistenceManager; 51 import com.genimen.djeneric.repository.DjProperty; 52 import com.genimen.djeneric.repository.DjPropertyRestriction; 53 import com.genimen.djeneric.repository.DjRelation; 54 import com.genimen.djeneric.repository.DjSession; 55 import com.genimen.djeneric.repository.exceptions.DjenericException; 56 import com.genimen.djeneric.repository.exceptions.ObjectNotDefinedException; 57 import com.genimen.djeneric.repository.exceptions.PropertyFormatException; 58 import com.genimen.djeneric.structure.ExtentUsage; 59 import com.genimen.djeneric.structure.PropertyUsage; 60 import com.genimen.djeneric.tools.specifier.components.DjChooserField; 61 import com.genimen.djeneric.tools.specifier.components.DjDateChooser; 62 import com.genimen.djeneric.tools.specifier.interfaces.CustomCellEditor; 63 import com.genimen.djeneric.tools.specifier.interfaces.ObjectModelListener; 64 import com.genimen.djeneric.ui.DjCellEditor; 65 import com.genimen.djeneric.ui.DjCheckCellRenderer; 66 import com.genimen.djeneric.ui.DjModelColumn; 67 import com.genimen.djeneric.ui.DjTableModel; 68 import com.genimen.djeneric.util.DjLogger; 69 70 75 public class DjenericObjectModel extends DjTableModel 76 { 77 78 private static final long serialVersionUID = 1L; 79 private DjSession _session; 80 private DjList _objects = new DjList(); 81 private DjExtent _extent; 82 private ExtentUsage _usage; 83 private boolean _includeMemos = false; 84 private boolean[] _isCellUpdateable; 85 private ArrayList _allListeners = new ArrayList (); 86 87 private int[] _cellToUsageMapping; 88 private int _cellCount; 89 90 private String [] _propertyNames; 91 private DjDomain[] _domains; 92 DjenericContextManager _contextManager; 93 94 public static String OBJECT_PATH_ESCAPE_START = "{"; 95 public static String OBJECT_PATH_ESCAPE_END = "}"; 96 97 107 public DjenericObjectModel(DjSession session, ExtentUsage usage, DjenericContextManager contextManager) 108 throws DjenericException 109 { 110 _session = session; 111 _extent = usage.getExtent(); 112 _usage = usage; 113 setupColumns(usage); 114 setEditable(usage.isEditAllowed()); 115 setInsertable(usage.isInsertAllowed()); 116 setDeleteable(usage.isDeleteAllowed()); 117 118 _contextManager = contextManager; 119 } 120 121 public int cellIdx2UsageIdx(int ci) 122 { 123 return _cellToUsageMapping[ci]; 124 } 125 126 public String cellIdx2PropertyName(int ci) 127 { 128 return _propertyNames[ci]; 129 } 130 131 138 public void setupColumns(ExtentUsage usage) throws DjenericException 139 { 140 int propCount = usage.getPropertyUsageCount(); 141 _cellCount = 0; 142 143 for (int i = 0; i < propCount; i++) 146 { 147 PropertyUsage propUsage = usage.getPropertyUsage(i); 148 149 if (propUsage.isDisplayed() && (isIncludeMemos() || !DjDomain.isMemoComponent(propUsage.getComponentType()))) _cellCount++; 150 } 151 152 _isCellUpdateable = new boolean[propCount]; 153 _columns = new DjModelColumn[propCount]; 154 _propertyNames = new String [propCount]; 155 _cellToUsageMapping = new int[propCount]; 156 _propertyNames = new String [propCount]; 157 _domains = new DjDomain[propCount]; 158 159 int curCell = 0; 166 for (int i = 0; i < propCount; i++) 167 { 168 if (processCell(usage, curCell, i, true)) curCell++; 169 } 170 for (int i = 0; i < propCount; i++) 171 { 172 if (processCell(usage, curCell, i, false)) curCell++; 173 } 174 } 175 176 protected boolean processCell(ExtentUsage usage, int curCell, int i, boolean propDisplayed) 177 throws ObjectNotDefinedException 178 { 179 PropertyUsage propUsage = usage.getPropertyUsage(i); 180 181 185 if (!isIncludeMemos() && DjDomain.isMemoComponent(propUsage.getComponentType())) 186 { if (propDisplayed) return false; 188 } 189 else if (propUsage.isDisplayed() != propDisplayed) return false; 191 192 _isCellUpdateable[curCell] = propUsage.isUpdateable(); 193 194 String prompt = propUsage.getPrompt(); 195 if (propUsage.isRequired()) prompt += "*"; 196 197 _columns[curCell] = new DjModelColumn(prompt, propUsage.getDisplayWidth(), propUsage.getDescription()); 198 _propertyNames[curCell] = propUsage.getPropertyName(); 199 _cellToUsageMapping[curCell] = i; 200 201 if (propUsage.getProperty().getType() instanceof DjDomain) 202 { 203 _domains[curCell] = (DjDomain) propUsage.getProperty().getType(); 204 } 205 else 206 { 207 _domains[curCell] = null; 208 } 209 return true; 210 } 211 212 public int getCellIndex(String propertyName) throws ObjectNotDefinedException 213 { 214 for (int i = 0; i < _propertyNames.length; i++) 215 { 216 if (_propertyNames[i].equals(propertyName)) return i; 217 } 218 throw new ObjectNotDefinedException(Messages.getString("DjenericObjectModel.PropertyUsageFor", propertyName)); 219 } 220 221 227 public TableCellRenderer getColumnRenderer(int cellIdx) 228 { 229 PropertyUsage pu = _usage.getPropertyUsage(_cellToUsageMapping[cellIdx]); 230 int compType = pu.getComponentType(); 231 if (compType == DjDomain.COMP_CHECKBOX) 232 { 233 try 234 { 235 DjCheckCellRenderer result = new DjCheckCellRenderer(_domains[cellIdx]); 236 result.setToolTipText(pu.getDescription()); 237 return result; 238 } 239 catch (Exception x) 240 { 241 DjLogger.log(x); 242 } 243 } 244 return _columns[cellIdx].getCellRenderer(); 245 } 246 247 257 public DjDomainValue[] getValidValues(int rowIdx, int cellIdx) throws DjenericException 258 { 259 DjObject obj = get(rowIdx); 260 return obj.getValidValues(_propertyNames[cellIdx]); 261 } 262 263 269 public TableCellEditor getColumnEditor(int cellIdx) 270 { 271 PropertyUsage pu = _usage.getPropertyUsage(_cellToUsageMapping[cellIdx]); 272 273 if (!pu.hasValidRelativePath()) setStatusMessage(Messages.getString("PropertyUsageTableModel.InvalidPath", pu 274 .getRelativePath()), false); 275 276 int compType = pu.getComponentType(); 277 278 if (compType == DjDomain.COMP_COMBOBOX) 279 { 280 JComboBox cbb = new JComboBox (); 281 282 cbb.setEditable(true); 284 285 DjCellEditor ce = new DjCellEditor(cbb) 286 { 287 private static final long serialVersionUID = 1L; 288 289 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 290 { 291 JComboBox combo = (JComboBox ) editorComponent; 292 try 293 { 294 DjDomainValue[] validVals = getValidValues(row, column); 295 combo.setModel(new DefaultComboBoxModel (validVals)); 296 combo.setSelectedIndex(-1); 297 } 298 catch (Exception x) 299 { 300 setStatusMessage(x); 301 } 302 delegate.setValue(value); 303 return editorComponent; 304 } 305 }; 306 return ce; 307 } 308 else if (compType == DjDomain.COMP_CHECKBOX) 309 { 310 if (pu.getProperty().getType() instanceof DjDomain) 311 { 312 DjDomain dom = (DjDomain) pu.getProperty().getType(); 313 if (dom.getValidValues().length == 2) 314 { 315 return new DjCellEditor(new JCheckBox (), dom); 316 } 317 else 318 { 319 System.err.println(Messages.getString("DjenericObjectModel.CheckboxInvalid", pu.getPropertyName())); 320 } 321 } 322 } 323 else if (compType == DjDomain.COMP_CHOOSER && pu.getProperty().getType() instanceof DjExtent) 324 { 325 DjExtent lookup = (DjExtent) pu.getProperty().getType(); 326 DjChooserField chooser; 327 try 328 { 329 chooser = new DjChooserField(_session, lookup); 330 chooser.setDialogTitle(Messages.getString("DjenericObjectModel.Choose", pu.getPrompt())); 331 chooser.setRequired(pu.isRequired()); 332 333 return new DjCellEditor(chooser); 334 } 335 catch (DjenericException e) 336 { 337 setStatusMessage(e); 338 } 339 } 340 else if (compType == DjDomain.COMP_DATECHOOSER) 341 { 342 DjDateChooser datechooser; 343 datechooser = new DjDateChooser(pu.getProperty()); 344 datechooser.setRequired(pu.isRequired()); 345 return new DjCellEditor(datechooser); 346 } 347 else if (pu.isCustomComponent()) 348 { 349 try 350 { 351 String className = pu.getCustomEditorClass(); 352 Class clz = _contextManager.getResourceManager().loadClass(className); 353 354 CustomCellEditor cce = (CustomCellEditor) clz.newInstance(); 355 cce.setContextManager(_contextManager); 356 cce.setModel(this); 357 358 return cce; 359 360 } 361 catch (Exception x) 362 { 363 setStatusMessage(x); 364 } 365 366 } 367 368 return new DjCellEditor(new JTextField ()); 369 } 370 371 377 public void setData(DjList data) 378 { 379 _objects = data; 380 } 381 382 387 public DjExtent getExtent() 388 { 389 return _extent; 390 } 391 392 397 public int getRowCount() 398 { 399 return _objects.size(); 400 } 401 402 409 public void addStatusListener(ObjectModelListener lsnr) 410 { 411 _allListeners.add(lsnr); 412 } 413 414 420 public void removeStatusListener(ObjectModelListener lsnr) 421 { 422 _allListeners.remove(lsnr); 423 } 424 425 433 public void setStatusMessage(String msg, boolean isInformative) 434 { 435 for (int i = 0; i < _allListeners.size(); i++) 436 { 437 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 438 lsnr.setStatusMessage(msg, isInformative); 439 } 440 } 441 442 448 public void setStatusMessage(String msg) 449 { 450 setStatusMessage(msg, true); 451 } 452 453 458 public boolean isNoObjectsPresent() 459 { 460 return _objects.size() == 0; 461 } 462 463 468 public String getNameSingular() 469 { 470 return _extent.getNameSingular(); 471 } 472 473 478 public String getNamePlural() 479 { 480 return _extent.getNamePlural(); 481 } 482 483 490 public DjObject get(int idx) 491 { 492 return _objects.getDjenericObjectAt(idx); 493 } 494 495 500 public int getColumnCount() 501 { 502 return _cellCount; 503 } 504 505 515 public boolean isRestricted(int rowIdx, int cellIdx) throws DjenericException 516 { 517 DjObject obj = get(rowIdx); 518 519 if (obj.isNull(_propertyNames[cellIdx])) return false; 520 DjProperty prop = obj.getProperty(_propertyNames[cellIdx]); 521 522 for (int i = 0; i < prop.getPropertyRestrictionCount(); i++) 523 { 524 DjPropertyRestriction restr = prop.getPropertyRestriction(i); 525 DjAssociation assoc = obj.getDetailAssociationByName(restr.getRestrictedRelation().getName()); 526 if (assoc.objectsExist()) return true; 527 } 528 529 return false; 530 } 531 532 541 public boolean isCellEditable(int rowIdx, int cellIdx) 542 { 543 return isEditable() && _isCellUpdateable[cellIdx]; 544 } 545 546 554 public int insertRow(int atIdx) throws DjenericException 555 { 556 DjRelation rel = null; 557 if (_usage.getVia() != null) rel = _usage.getVia().getRelation(); 558 559 if (rel != null && rel.isOneToOne() && _objects.size() > 0) 560 { 561 throw new DjenericException(Messages.getString("DjenericObjectModel.One2OneViolated", rel.getDetailExtent() 562 .getNameSingular(), rel.getMasterExtent().getNameSingular())); 563 } 564 565 DjObject obj = _session.createObject(_extent); 566 try 567 { 568 for (int i = 0; i < _allListeners.size(); i++) 569 { 570 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 571 lsnr.beforeObjectCreated(_usage, obj); 572 } 573 } 574 catch (DjenericException x) 575 { 576 _session.unregisterDjenericObject(obj); 577 throw x; 578 } 579 try 582 { 583 setDefaults(obj); 584 } 585 catch (Exception x) 586 { 587 DjLogger.log(x); 588 } 591 _objects.add(atIdx, obj); 592 593 for (int i = 0; i < _allListeners.size(); i++) 594 { 595 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 596 lsnr.afterObjectCreated(_usage, obj); 597 } 598 599 return atIdx; 600 } 601 602 public void setDefaults() throws ObjectNotDefinedException, PropertyFormatException, DjenericException 603 { 604 for (int i = 0; i < _objects.size(); i++) 605 { 606 DjObject obj = _objects.getDjenericObjectAt(i); 607 if (obj.isNew()) setDefaults(obj); 608 } 609 } 610 611 public void setDefaults(DjObject obj) throws ObjectNotDefinedException, PropertyFormatException, DjenericException 612 { 613 for (int i = 0; i < _usage.getPropertyUsageCount(); i++) 614 { 615 PropertyUsage pu = _usage.getPropertyUsage(i); 616 String dflt = pu.getDefaultValue(); 617 if (dflt != null) 618 { 619 if (dflt.startsWith(OBJECT_PATH_ESCAPE_START) && dflt.endsWith(OBJECT_PATH_ESCAPE_END)) 620 { 621 dflt = dflt.substring(OBJECT_PATH_ESCAPE_START.length(), dflt.length() - OBJECT_PATH_ESCAPE_END.length()); 622 Object evaluated = _contextManager.evaluatePath(dflt, _objects, obj, pu); 623 obj.set(pu.getPropertyName(), evaluated); 624 } 625 else obj.setString(pu.getPropertyName(), dflt); 626 } 627 else if ((pu.getComponentType() == DjDomain.COMP_CHECKBOX) && (obj.isNull(pu.getPropertyName()))) 628 { 629 DjDomain dom = null; 630 631 if (pu.getProperty().getType() instanceof DjDomain) dom = (DjDomain) pu.getProperty().getType(); 632 633 if ((dom != null) && (dom.getValidValues().length > 0)) 634 { 635 obj.setString(pu.getPropertyName(), dom.getValidValues()[0].getValue().toString()); 636 } 637 } 638 } 639 } 640 641 649 public boolean deleteRow(int atIdx) throws DjenericException 650 { 651 DjObject obj = get(atIdx); 652 for (int i = 0; i < _allListeners.size(); i++) 653 { 654 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 655 lsnr.beforeObjectDeleted(_usage, obj); 656 } 657 obj.markForDelete(); 658 _objects.remove(obj); 659 660 for (int i = 0; i < _allListeners.size(); i++) 661 { 662 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 663 lsnr.afterObjectDeleted(_usage, obj); 664 lsnr.notifyViewersDelete(obj.getExtent()); 665 666 } 667 return true; 668 } 669 670 679 public void setValueAt(Object value, int rowIdx, int cellIdx) 680 { 681 try 682 { 683 setValueAtX(value, rowIdx, cellIdx); 684 } 685 catch (Exception x) 686 { 687 setStatusMessage(x); 688 } 689 } 690 691 701 public void setValueAtX(Object value, int rowIdx, int cellIdx) throws DjenericException 702 { 703 PropertyUsage pu = _usage.getPropertyUsage(_cellToUsageMapping[cellIdx]); 704 DjObject obj = _objects.getDjenericObjectAt(rowIdx); 705 706 if (value instanceof Boolean ) 707 { 708 boolean val = ((Boolean ) value).booleanValue(); 709 if (_domains[cellIdx] != null) 710 { 711 DjDomainValue valids[] = _domains[cellIdx].getValidValues(); 712 if (val) 713 { 714 value = valids[0].getValue(); 715 } 716 else 717 { 718 value = valids[1].getValue(); 719 } 720 } 721 } 722 723 if (value instanceof String ) 725 { 726 value = trimSpaces(value); 727 } 728 729 if ((value instanceof String ) && (_domains[cellIdx] != null)) 731 { 732 DjDomain dom = _domains[cellIdx]; 733 if (dom.isEnforced() && dom.hasValidValues()) 734 { 735 DjDomainValue dv = dom.looselyMatchDescription((String ) value); 736 if (dv != null) value = dv.getValue(); 737 } 738 } 739 740 if (value instanceof DjDomainValue) 741 { 742 value = ((DjDomainValue) value).getValue(); 743 } 744 745 String strVal = null; 746 747 if (value instanceof DjObject) 749 { 750 strVal = String.valueOf(((DjObject) value).getObjectId()); 751 } 752 else if (value != null) 753 { 754 strVal = value.toString(); 755 if (strVal.trim().length() == 0) 756 { 757 strVal = null; 758 } 759 760 if (strVal != null && pu.getComponentType() == DjDomain.COMP_COMBOBOX 761 || pu.getComponentType() == DjDomain.COMP_TEXTFIELD || pu.getComponentType() == DjDomain.COMP_MEMO 762 || pu.getComponentType() == DjDomain.COMP_HTML_MEMO || pu.getComponentType() == DjDomain.COMP_PASSWORD) 763 { 764 if (_domains[cellIdx] != null && strVal != null && (_domains[cellIdx].getDomainValueCount() > 0) 765 && _domains[cellIdx].isEnforced()) 766 { 767 DjDomainValue dv = _domains[cellIdx].looselyMatchValue(strVal); 768 if (dv != null) 769 { 770 strVal = dv.getValue().toString(); 771 } 772 else 773 { 774 throw new DjenericException(Messages 775 .getString("DjenericObjectModel.NotAValidValue", strVal, pu.getPrompt())); 776 } 777 } 778 else if (pu.getProperty().getType() instanceof DjExtent) 779 { 780 DjDomainValue[] valids = obj.getValidValues(_propertyNames[cellIdx]); 781 DjDomainValue dv = DjDomain.looselyMatchValue(valids, strVal); 782 if (dv != null) 783 { 784 strVal = String.valueOf(((DjObject) dv.getValue()).getObjectId()); 785 } 786 else 787 { 788 throw new DjenericException(Messages 789 .getString("DjenericObjectModel.NotAValidValue", strVal, pu.getPrompt())); 790 } 791 } 792 } 793 } 794 795 for (int i = 0; i < _allListeners.size(); i++) 796 { 797 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 798 lsnr.beforePropertyChanged(_usage, obj, cellIdx, strVal); 799 } 800 801 String oldVal = obj.getString(_propertyNames[cellIdx]); 802 803 try 804 { 805 obj.setString(_propertyNames[cellIdx], strVal); 806 } 807 catch (NumberFormatException ne) 808 { 809 throw new DjenericException(Messages.getString("DjenericObjectModel.InvalidNumber", strVal)); 810 } 811 812 for (int i = 0; i < _allListeners.size(); i++) 813 { 814 ObjectModelListener lsnr = (ObjectModelListener) _allListeners.get(i); 815 lsnr.afterPropertyChanged(_usage, obj, cellIdx, oldVal); 816 } 817 } 818 819 protected Object trimSpaces(Object value) 820 { 821 if ("true".equalsIgnoreCase(System.getProperty("djeneric.stripspaces"))) value = ((String ) value).trim(); 822 return value; 823 } 824 825 833 public Object getValueAt(int rowIdx, int cellIdx) 834 { 835 try 836 { 837 DjObject obj = _objects.getDjenericObjectAt(rowIdx); 838 if (obj.getType(_propertyNames[cellIdx]) instanceof DjExtent) 839 { 840 return obj.get(_propertyNames[cellIdx]); 841 } 842 else 843 { 844 DjProperty prop = obj.getProperty(_propertyNames[cellIdx]); 845 if (prop.getType() instanceof DjDomain) 846 { 847 DjDomain dom = (DjDomain) prop.getType(); 848 if (dom.isEnforced() && dom.hasValidValues()) 849 { 850 String val = obj.getString(_propertyNames[cellIdx]); 851 String result = dom.translateCode(val); 852 if (result == null) return val; 853 return result; 854 } 855 } 856 857 return obj.getString(_propertyNames[cellIdx]); 858 } 859 } 860 catch (Exception x) 861 { 862 setStatusMessage(x); 863 } 864 return ""; 865 } 866 867 872 public boolean isIncludeMemos() 873 { 874 return _includeMemos; 875 } 876 877 881 public void setIncludeMemos(boolean includeMemos) 882 { 883 _includeMemos = includeMemos; 884 } 885 886 public DjSession getSession() 887 { 888 return _session; 889 } 890 891 public DjPersistenceManager getPersistenceManager() 892 { 893 if (_session == null) return null; 894 return _session.getPersistenceManager(); 895 } 896 897 } | Popular Tags |