summaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
Diffstat (limited to 'projects')
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java150
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java188
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java397
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java103
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java106
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java195
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java348
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java846
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java27
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java711
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java129
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java20
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java134
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java1122
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java101
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java94
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java78
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java101
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java336
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java319
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java509
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java14
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java172
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java672
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java321
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java328
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java123
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java41
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java845
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java228
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java601
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java208
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java229
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java148
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java233
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java1086
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java553
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java128
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java41
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java514
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java581
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java212
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java864
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java538
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java319
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java272
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java299
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java51
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java439
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java1544
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java17
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java17
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java574
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java17
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java91
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java926
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java996
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java267
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java1215
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java135
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java61
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java50
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/AllTests.java4
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/TestBundle.java10
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java4
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java569
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSBundleTest.java219
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java56
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java28
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCChannel.java230
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java56
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpression.java38
-rw-r--r--projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpressionFactory.java29
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessArrayFaultHandler.java40
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessFaultHandler.java39
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessGenericFaultHandler.java33
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessLock.java19
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptor.java81
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorChannel.java110
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorContext.java39
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorOperation.java37
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAttribute.java114
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabase.java60
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseChannel.java37
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseContext.java338
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseOperation.java19
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java202
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntityClassDescription.java55
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOGeneralAdaptorException.java25
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOJoin.java22
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModel.java131
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModelGroup.java79
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOProperty.java21
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOPropertyListEncoding.java34
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOQualifierSQLGeneration.java77
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EORelationship.java113
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpression.java170
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpressionFactory.java44
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOStoredProcedure.java61
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/AbstractObjectStore.java1350
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ArrayFault.java322
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ChildDataSource.java282
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOAndQualifier.java180
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOClassDescription.java990
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCooperatingObjectStore.java63
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCustomObject.java1158
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODataSource.java230
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODatabaseDataSource.java551
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODeferredFaulting.java36
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserver.java209
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java446
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEditingContext.java5547
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEnterpriseObject.java352
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaultHandler.java40
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaulting.java97
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFetchSpecification.java847
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGenericRecord.java214
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGlobalID.java88
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOIntegralKeyGlobalID.java38
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyComparisonQualifier.java59
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyGlobalID.java160
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiver.java32
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiving.java21
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCoding.java166
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingAdditions.java245
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingSupport.java338
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueQualifier.java224
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueUnarchiver.java46
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONotQualifier.java124
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONullValue.java143
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStore.java465
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStoreCoordinator.java238
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java727
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverProxy.java125
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserving.java36
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOOrQualifier.java183
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java1089
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifierEvaluation.java24
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EORelationshipManipulation.java80
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOSortOrdering.java562
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOTemporaryGlobalID.java350
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOValidation.java82
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOVectorKeyGlobalID.java34
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EditingContext.java441
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/KeyValueCodingUtilities.java1140
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ObservableArray.java485
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/OrderedDataSource.java48
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java863
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/internal/Surrogate.java279
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingController.java30
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingPanel.java239
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataKeyID.java126
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataObjectStore.java774
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditController.java248
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditPanel.java59
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/InspectorController.java142
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/Test.java150
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestController.java490
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestDataSource.java158
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestMap.java238
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObject.java643
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectClassDesc.java38
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectStore.java409
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestPanel.java119
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeController.java372
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeInspectorController.java214
-rw-r--r--projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreePanel.java42
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ActionAssociation.java463
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/AdjustableAssociation.java443
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ButtonAssociation.java684
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ComboBoxAssociation.java1137
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DateAssociation.java856
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupActionAssociation.java148
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupInspector.java135
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupNode.java2452
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ListAssociation.java491
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/MutableDisplayGroupNode.java296
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/NotificationInspector.java497
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/RadioPanelAssociation.java593
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ReferenceInspector.java417
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/SliderAssociation.java587
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java1370
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableColumnAssociation.java1085
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TextAssociation.java1980
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java1430
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeAssociation.java876
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeColumnAssociation.java488
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeModelAssociation.java2930
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AbsoluteLayout.java61
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlphaTextField.java593
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlternatingRowCellRenderer.java157
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterFlowLayout.java952
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterRootLayout.java268
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterTableUI.java176
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ButtonPanel.java1066
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/CheckButtonPanel.java455
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellEditor.java88
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellRenderer.java79
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ComboBoxCellRenderer.java44
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/DateTextField.java1098
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/FormattedCellRenderer.java460
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/IconCellRenderer.java1272
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ImagePanel.java91
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/InfoPanel.java2908
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyDelayTimer.java301
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyableCellEditor.java566
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/LineWrappingRenderer.java225
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/MultiLineLabel.java163
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/NumericTextField.java754
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTable.java927
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTableModel.java538
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/RadioButtonPanel.java278
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartPasswordField.java456
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartTextField.java398
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/StatusButtonPanel.java435
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TintedImageFilter.java122
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeChooser.java1134
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeTableCellRenderer.java305
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ClassGrabber.java108
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ComponentHighlighter.java212
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/GIFEncoder.java890
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ObjectInspector.java300
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/PositionComparator.java84
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/StackTraceInspector.java686
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/TextInputRangeChecker.java609
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowGrabber.java229
-rw-r--r--projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowUtilities.java890
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java488
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java380
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java490
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java880
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java4040
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java586
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java605
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java134
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java486
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java488
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java6836
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java38
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java39
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java115
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java2021
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java236
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java150
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java124
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java2118
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java27
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java340
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java131
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java929
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java314
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java440
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java322
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java4219
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java339
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java115
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java181
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java99
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java61
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java114
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java19
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java408
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java277
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java78
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java135
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java52
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java354
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java258
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java18
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java251
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java18
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java295
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java1003
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java59
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java33
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java776
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java150
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java38
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java235
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java262
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java918
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java118
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java68
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java173
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java77
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java160
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java52
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java63
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java1242
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java146
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java663
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java840
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java77
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java320
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java423
-rw-r--r--projects/net.wotonomy.web/src/test/java/net/wotonomy/web/xml/XMLRPCSelectorTest.java71
296 files changed, 59328 insertions, 69990 deletions
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java
index 89fa1eb..8fc681e 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java
@@ -22,90 +22,88 @@ import java.io.Serializable;
import java.util.List;
/**
-* A DataIndex maintains a list of objects associated with values.
-* The objects can then be retrieved based on the values. This class
-* should not be much more complex than a simple map or list because
-* the DataSoup is responsible for populating it.
-*/
-public interface DataIndex extends Serializable
-{
- /**
- * Gets the name of this index. The DataSoup uses this to
- * uniquely refer to this index.
- * @return The name of this index.
- */
- public String getName();
+ * A DataIndex maintains a list of objects associated with values. The objects
+ * can then be retrieved based on the values. This class should not be much more
+ * complex than a simple map or list because the DataSoup is responsible for
+ * populating it.
+ */
+public interface DataIndex extends Serializable {
+ /**
+ * Gets the name of this index. The DataSoup uses this to uniquely refer to this
+ * index.
+ *
+ * @return The name of this index.
+ */
+ public String getName();
+
+ /**
+ * The property managed by this index. This is the property used when the
+ * DataSoup builds and rebuilds this index.
+ *
+ * @return The property managed by this index.
+ */
+ public String getProperty();
+
+ /**
+ * Adds an object to be associated with the specified value.
+ *
+ * @param anObject A data object, usually but not always a DataKey.
+ * @param newValue The property value to be associated with the data object.
+ * @return The data object that was inserted, or null if an error occurred.
+ */
+ public Object addObject(Object anObject, Object newValue);
- /**
- * The property managed by this index. This is the property
- * used when the DataSoup builds and rebuilds this index.
- * @return The property managed by this index.
- */
- public String getProperty();
-
- /**
- * Adds an object to be associated with the specified value.
- * @param anObject A data object, usually but not always a DataKey.
- * @param newValue The property value to be associated with the data object.
- * @return The data object that was inserted, or null if an error occurred.
- */
- public Object addObject( Object anObject, Object newValue );
-
- /**
- * Updates an object previously associated with the specified
- * value to be associated with the specified new value.
- * @param anObject A data object, usually but not always a DataKey.
- * @param oldValue The value currently associated with the data object.
- * @param newValue The value to be associated with the data object.
- * @return The data object that was updated, or null if an error occurred.
- */
- public Object updateObject( Object anObject,
- Object oldValue, Object newValue );
-
- /**
- * Removes an object from the index.
- * @param anObject A data object, usually but not always a DataKey.
- * @param oldValue The value currently associated with the data object.
- * @return The data object that was removed, or null if not found or error.
- */
- public Object removeObject( Object anObject, Object oldValue );
+ /**
+ * Updates an object previously associated with the specified value to be
+ * associated with the specified new value.
+ *
+ * @param anObject A data object, usually but not always a DataKey.
+ * @param oldValue The value currently associated with the data object.
+ * @param newValue The value to be associated with the data object.
+ * @return The data object that was updated, or null if an error occurred.
+ */
+ public Object updateObject(Object anObject, Object oldValue, Object newValue);
+
+ /**
+ * Removes an object from the index.
+ *
+ * @param anObject A data object, usually but not always a DataKey.
+ * @param oldValue The value currently associated with the data object.
+ * @return The data object that was removed, or null if not found or error.
+ */
+ public Object removeObject(Object anObject, Object oldValue);
+
+ /**
+ * Removes all objects from the index. Usually called before rebuilding the
+ * index.
+ */
+ public void clear();
+
+ /**
+ * Returns all objects in the index whose associated values fall between the two
+ * specified values, inclusive.
+ *
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A List of the matching objects, ordered in increasing value, or null
+ * for invalid query parameters or other error.
+ */
+ public List query(Object beginValue, Object endValue);
- /**
- * Removes all objects from the index. Usually called before
- * rebuilding the index.
- */
- public void clear();
-
- /**
- * Returns all objects in the index whose associated values fall
- * between the two specified values, inclusive.
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A List of the matching objects, ordered in increasing
- * value, or null for invalid query parameters or other error.
- */
- public List query( Object beginValue, Object endValue );
-
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
index 6fe574f..4ac8b50 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
@@ -22,121 +22,101 @@ import java.io.Serializable;
import net.wotonomy.foundation.internal.ValueConverter;
-public class DataKey implements Comparable, Serializable, Cloneable
-{
+public class DataKey implements Comparable, Serializable, Cloneable {
static final long serialVersionUID = 8421127539579065705L;
- Long key;
-
- public DataKey()
- {
- key = new Long( 0 );
- }
-
- /**
- * Converts string representation to new object.
- */
- public DataKey( String aString )
- {
- this();
- setKeyString( aString );
- }
-
- public int hashCode()
- {
- return key.intValue();
- }
-
- public void increment()
- {
- key = new Long( key.longValue() + 1 );
- }
-
- public Object clone()
- {
- return new DataKey( this.toString() );
- }
-
- public String toString()
- {
- return key.toString();
- }
-
- public String getKeyString()
- {
- return key.toString();
- }
-
- public void setKeyString( String aString )
- {
- Long parsed = ValueConverter.getLong( aString );
- if ( parsed != null ) key = parsed;
- }
-
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof String )
- {
- if ( toString().equals( anObject ) )
- {
- return true;
- }
- }
- if ( ! ( anObject instanceof DataKey ) ) return false;
- return key.equals( ((DataKey)anObject).key );
- }
-
- public int compareTo( Object anObject )
- {
- if ( anObject instanceof String )
- {
- if ( toString().equals( anObject ) )
- {
- return 0;
- }
- }
- if ( ! ( anObject instanceof DataKey ) )
- {
- Long converted = (Long) ValueConverter.getLong( anObject );
- if ( converted != null )
- {
- return (int) ( key.longValue() - converted.longValue() );
- }
- return 0;
- };
- return (int) ( key.longValue() - ((DataKey)anObject).key.longValue() );
- }
+ Long key;
+
+ public DataKey() {
+ key = new Long(0);
+ }
+
+ /**
+ * Converts string representation to new object.
+ */
+ public DataKey(String aString) {
+ this();
+ setKeyString(aString);
+ }
+
+ public int hashCode() {
+ return key.intValue();
+ }
+
+ public void increment() {
+ key = new Long(key.longValue() + 1);
+ }
+
+ public Object clone() {
+ return new DataKey(this.toString());
+ }
+
+ public String toString() {
+ return key.toString();
+ }
+
+ public String getKeyString() {
+ return key.toString();
+ }
+
+ public void setKeyString(String aString) {
+ Long parsed = ValueConverter.getLong(aString);
+ if (parsed != null)
+ key = parsed;
+ }
+
+ public boolean equals(Object anObject) {
+ if (anObject instanceof String) {
+ if (toString().equals(anObject)) {
+ return true;
+ }
+ }
+ if (!(anObject instanceof DataKey))
+ return false;
+ return key.equals(((DataKey) anObject).key);
+ }
+
+ public int compareTo(Object anObject) {
+ if (anObject instanceof String) {
+ if (toString().equals(anObject)) {
+ return 0;
+ }
+ }
+ if (!(anObject instanceof DataKey)) {
+ Long converted = (Long) ValueConverter.getLong(anObject);
+ if (converted != null) {
+ return (int) (key.longValue() - converted.longValue());
+ }
+ return 0;
+ }
+ ;
+ return (int) (key.longValue() - ((DataKey) anObject).key.longValue());
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/14 19:29:38 chochos
- * minor cleanup (imports, static method calls, etc)
+ * Revision 1.4 2003/08/14 19:29:38 chochos minor cleanup (imports, static
+ * method calls, etc)
*
- * Revision 1.3 2001/02/23 23:44:44 mpowers
- * Fixes for hashcode to ensure proper key comparison.
+ * Revision 1.3 2001/02/23 23:44:44 mpowers Fixes for hashcode to ensure proper
+ * key comparison.
*
- * Revision 1.2 2001/02/15 21:12:41 mpowers
- * Added accessors for key throughout the api. This breaks compatibility.
- * insertObject now returns the permanent key for the newly created object.
- * The old way returned a copy of the object which was an additional read
- * that was often ignored. Now you can read it only if you need it.
- * Furthermore, there was not other way of getting the permanent key.
+ * Revision 1.2 2001/02/15 21:12:41 mpowers Added accessors for key throughout
+ * the api. This breaks compatibility. insertObject now returns the permanent
+ * key for the newly created object. The old way returned a copy of the object
+ * which was an additional read that was often ignored. Now you can read it only
+ * if you need it. Furthermore, there was not other way of getting the permanent
+ * key.
*
- * Revision 1.1.1.1 2000/12/21 15:47:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:04 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java
index 3c37d43..c7523b3 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java
@@ -20,197 +20,207 @@ package net.wotonomy.datastore;
import java.util.Collection;
-public interface DataSoup
-{
- /**
- * Adds the specified object to the soup and returns the key
- * for the new object by which it may be subsequently retrieved.
- * Null indicates an error, probably due to serialization.
- * @param anObject Object to be added to soup.
- * @return The unique identifier used for the new object.
- */
- public DataKey addObject( Object anObject );
-
- /**
- * Removes the specified object from the soup and returns
- * the removed object as read from the soup (which is the
- * original copy of the object). Null indicates object not found.
- * @param aKey A key for an object to be removed.
- * @return The object that was removed, or null if not found or error.
- */
- public Object removeObject( DataKey aKey );
-
- /**
- * Updates the specified object and returns the object
- * as updated. Null indicates an error writing the object.
- * @param aKey A key for an object to be updated.
- * @param aKey The new object for that key.
- * @return A copy of the updated object, possibly updated,
- * or null if not found or error.
- */
- public Object updateObject( DataKey aKey, Object updatedObject );
-
- /**
- * Gets object from data store whose identifier is equal
- * to the specified object.
- * @param aKey A key for an object to be retrieved.
- * @return The corresponding object from the soup.
- */
- public Object getObjectByKey( DataKey aKey );
-
+public interface DataSoup {
/**
- * Registers an object that may or may not be created
- * later, returning a temporary but uniquely identifiable
- * key. The key will be replaced with a permanent key when
- * the object is created with addObject().
- * @param anObject An object to be registered.
- * @return A temporary key for this object.
- */
- public DataKey registerTemporaryObject( Object anObject );
+ * Adds the specified object to the soup and returns the key for the new object
+ * by which it may be subsequently retrieved. Null indicates an error, probably
+ * due to serialization.
+ *
+ * @param anObject Object to be added to soup.
+ * @return The unique identifier used for the new object.
+ */
+ public DataKey addObject(Object anObject);
- // index management
-
/**
- * Adds an index to the soup.
- * @param aName The string identifier for this index.
- * @param aProperty The property on which this index will be based.
- */
- public void addIndex( String aName, String aProperty );
-
+ * Removes the specified object from the soup and returns the removed object as
+ * read from the soup (which is the original copy of the object). Null indicates
+ * object not found.
+ *
+ * @param aKey A key for an object to be removed.
+ * @return The object that was removed, or null if not found or error.
+ */
+ public Object removeObject(DataKey aKey);
+
+ /**
+ * Updates the specified object and returns the object as updated. Null
+ * indicates an error writing the object.
+ *
+ * @param aKey A key for an object to be updated.
+ * @param aKey The new object for that key.
+ * @return A copy of the updated object, possibly updated, or null if not found
+ * or error.
+ */
+ public Object updateObject(DataKey aKey, Object updatedObject);
+
+ /**
+ * Gets object from data store whose identifier is equal to the specified
+ * object.
+ *
+ * @param aKey A key for an object to be retrieved.
+ * @return The corresponding object from the soup.
+ */
+ public Object getObjectByKey(DataKey aKey);
+
/**
- * Deletes the specified index from the soup.
- * @param aName The string identifier for the index to be removed.
- */
- public void removeIndex( String aName );
-
+ * Registers an object that may or may not be created later, returning a
+ * temporary but uniquely identifiable key. The key will be replaced with a
+ * permanent key when the object is created with addObject().
+ *
+ * @param anObject An object to be registered.
+ * @return A temporary key for this object.
+ */
+ public DataKey registerTemporaryObject(Object anObject);
+
+ // index management
+
/**
- * Gets a collection of all indices in this soup.
- * @return A collection of all indices in this soup.
- */
+ * Adds an index to the soup.
+ *
+ * @param aName The string identifier for this index.
+ * @param aProperty The property on which this index will be based.
+ */
+ public void addIndex(String aName, String aProperty);
+
+ /**
+ * Deletes the specified index from the soup.
+ *
+ * @param aName The string identifier for the index to be removed.
+ */
+ public void removeIndex(String aName);
+
+ /**
+ * Gets a collection of all indices in this soup.
+ *
+ * @return A collection of all indices in this soup.
+ */
public Collection getAllIndices();
-
- // relationship management
-
+
+ // relationship management
+
/**
- * Adds a relation to entries in another soup.
- * @param aProperty The property on which this relation will be based.
- * @param aSoup The name of the soup to be related in this store.
- */
+ * Adds a relation to entries in another soup.
+ *
+ * @param aProperty The property on which this relation will be based.
+ * @param aSoup The name of the soup to be related in this store.
+ */
// public void addRelation( String aProperty, String aSoup );
-
+
/**
- * Deletes the specified relation to entries in another soup.
- * @param aProperty The property on which this relation will be based.
- * @param aSoup The name of the soup to be related in this store.
- */
+ * Deletes the specified relation to entries in another soup.
+ *
+ * @param aProperty The property on which this relation will be based.
+ * @param aSoup The name of the soup to be related in this store.
+ */
// public void removeRelation( String aProperty, String aSoup );
-
+
/**
- * Gets a collection of all relations in this soup.
- * @return A collection of all relation in this soup.
- */
+ * Gets a collection of all relations in this soup.
+ *
+ * @return A collection of all relation in this soup.
+ */
// public Collection getAllRelations();
-
- // queries
+
+ // queries
/**
- * Returns an empty data view, suitable for creating
- * new entries in the soup.
- * @return A DataView containing no entries.
- */
+ * Returns an empty data view, suitable for creating new entries in the soup.
+ *
+ * @return A DataView containing no entries.
+ */
public DataView createView();
-
- /**
- * Queries by the specified pre-generated index, if it exists.
- * Will return objects whose values for the indexed property
- * fall between the two values inclusive.
- * Otherwise, falls through to queryByProperty.
- * @param anIndexName The index to be queried.
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView queryByIndex(
- String anIndexName, Object beginKey, Object endKey );
-
- /**
- * Generates an index based on the specified property
- * and then executes the query.
- * Will return objects whose values for the specified property
- * fall between the two values inclusive.
- * @param aPropertyName The property to be queried. If null,
- * will query the objects directly with queryObjects().
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView queryByProperty(
- String aPropertyName, Object beginKey, Object endKey );
- /**
- * Generates an index based on the values of the objects themselves
- * and then executes the query.
- * Will return objects whose values fall between the two values inclusive.
- * @param beginValue The beginning value, or null for all values
- * up to and including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView queryObjects( Object beginKey, Object endKey );
+ /**
+ * Queries by the specified pre-generated index, if it exists. Will return
+ * objects whose values for the indexed property fall between the two values
+ * inclusive. Otherwise, falls through to queryByProperty.
+ *
+ * @param anIndexName The index to be queried.
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView queryByIndex(String anIndexName, Object beginKey, Object endKey);
+
+ /**
+ * Generates an index based on the specified property and then executes the
+ * query. Will return objects whose values for the specified property fall
+ * between the two values inclusive.
+ *
+ * @param aPropertyName The property to be queried. If null, will query the
+ * objects directly with queryObjects().
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView queryByProperty(String aPropertyName, Object beginKey, Object endKey);
+
+ /**
+ * Generates an index based on the values of the objects themselves and then
+ * executes the query. Will return objects whose values fall between the two
+ * values inclusive.
+ *
+ * @param beginValue The beginning value, or null for all values up to and
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView queryObjects(Object beginKey, Object endKey);
+
+ /**
+ * Returns a view containing the objects for the specified keys.
+ *
+ * @param aKeyList A collection of keys to be placed in the view.
+ * @return A DataView containing the objects for the corresponding keys, in the
+ * order in which the keys are returned from the collection.
+ */
+ public DataView queryByKeys(Collection aKeyList);
- /**
- * Returns a view containing the objects for the specified keys.
- * @param aKeyList A collection of keys to be placed in the view.
- * @return A DataView containing the objects for the corresponding
- * keys, in the order in which the keys are returned from the collection.
- */
- public DataView queryByKeys( Collection aKeyList );
-
- /**
- * As queryByIndex, but with objects returned in reverse order.
- * @param anIndexName The index to be queried.
- * @param beginValue The beginning value, or null for all values
- * up to and including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryByIndex(
- String anIndexName, Object beginKey, Object endKey );
-
- /**
- * As queryByProperty, but with objects returned in reverse order.
- * @param aPropertyName The property to be queried. If null,
- * will query the objects directly with queryObjects().
- * @param beginValue The beginning value, or null for all values
- * up to and including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryByProperty(
- String aPropertyName, Object beginKey, Object endKey );
+ /**
+ * As queryByIndex, but with objects returned in reverse order.
+ *
+ * @param anIndexName The index to be queried.
+ * @param beginValue The beginning value, or null for all values up to and
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryByIndex(String anIndexName, Object beginKey, Object endKey);
- /**
- * As queryObjects, but with objects returned in reverse order.
- * @param beginValue The beginning value, or null for all values
- * up to and including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryObjects( Object beginKey, Object endKey );
+ /**
+ * As queryByProperty, but with objects returned in reverse order.
+ *
+ * @param aPropertyName The property to be queried. If null, will query the
+ * objects directly with queryObjects().
+ * @param beginValue The beginning value, or null for all values up to and
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryByProperty(String aPropertyName, Object beginKey, Object endKey);
+
+ /**
+ * As queryObjects, but with objects returned in reverse order.
+ *
+ * @param beginValue The beginning value, or null for all values up to and
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryObjects(Object beginKey, Object endKey);
// public void addIndex( String aName, DataIndex anIndex ) {}
// public void removeIndex( String aName ) {}
@@ -219,39 +229,32 @@ public interface DataSoup
// public void removeTaggedObject( String aKey );
// public void setMetaData(
// String aMetaProperty, Serializable aValue, Serializable anObject );
-
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/14 19:29:38 chochos
- * minor cleanup (imports, static method calls, etc)
+ * Revision 1.4 2003/08/14 19:29:38 chochos minor cleanup (imports, static
+ * method calls, etc)
*
- * Revision 1.3 2001/03/05 22:12:11 mpowers
- * Created the control package for a datastore-specific implementation
- * of EOObjectStore.
+ * Revision 1.3 2001/03/05 22:12:11 mpowers Created the control package for a
+ * datastore-specific implementation of EOObjectStore.
*
- * Revision 1.2 2001/02/15 21:12:41 mpowers
- * Added accessors for key throughout the api. This breaks compatibility.
- * insertObject now returns the permanent key for the newly created object.
- * The old way returned a copy of the object which was an additional read
- * that was often ignored. Now you can read it only if you need it.
- * Furthermore, there was not other way of getting the permanent key.
+ * Revision 1.2 2001/02/15 21:12:41 mpowers Added accessors for key throughout
+ * the api. This breaks compatibility. insertObject now returns the permanent
+ * key for the newly created object. The old way returned a copy of the object
+ * which was an additional read that was often ignored. Now you can read it only
+ * if you need it. Furthermore, there was not other way of getting the permanent
+ * key.
*
- * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java
index 28fbc90..2924ca3 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java
@@ -22,73 +22,58 @@ import java.io.File;
import java.io.Serializable;
import java.util.Iterator;
-public class DataStore implements Serializable
-{
- protected File homeDirectory;
-
- public DataStore( String aPath )
- {
- homeDirectory = new File( aPath );
-
- // if specified directory does not exist
- if ( ! homeDirectory.exists() )
- {
- homeDirectory.mkdirs();
- }
-
- // if existing path is a file, exit with error
- if ( homeDirectory.isDirectory() )
- {
- new RuntimeException( "DataStore: Specified directory is a file." );
+public class DataStore implements Serializable {
+ protected File homeDirectory;
+
+ public DataStore(String aPath) {
+ homeDirectory = new File(aPath);
+
+ // if specified directory does not exist
+ if (!homeDirectory.exists()) {
+ homeDirectory.mkdirs();
+ }
+
+ // if existing path is a file, exit with error
+ if (homeDirectory.isDirectory()) {
+ new RuntimeException("DataStore: Specified directory is a file.");
+ }
+ }
+
+ public File getHomeDirectory() {
+ return homeDirectory;
+ }
+
+ public DataSoup getSoupForName(String aName) {
+ return null;
}
- }
-
- public File getHomeDirectory()
- {
- return homeDirectory;
- }
-
-
- public DataSoup getSoupForName( String aName )
- {
- return null;
- }
- public void removeSoup( DataSoup aSoup )
- {
- // FIXME
- }
- public Iterator getAllSoups()
- {
- return null;
- }
-
- public static void main( String[] argv )
- {
- new DataStore( "/Local/Users/michael/Projects/test/data" );
- }
-
+
+ public void removeSoup(DataSoup aSoup) {
+ // FIXME
+ }
+
+ public Iterator getAllSoups() {
+ return null;
+ }
+
+ public static void main(String[] argv) {
+ new DataStore("/Local/Users/michael/Projects/test/data");
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/03/05 22:12:11 mpowers
- * Created the control package for a datastore-specific implementation
- * of EOObjectStore.
+ * Revision 1.2 2001/03/05 22:12:11 mpowers Created the control package for a
+ * datastore-specific implementation of EOObjectStore.
*
- * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java
index fec9cfc..a0e7819 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java
@@ -21,91 +21,81 @@ package net.wotonomy.datastore;
import java.util.List;
import java.util.Observer;
-public interface DataView extends List
-{
+public interface DataView extends List {
// public void newQuery( String aProperty, Object beginKey, Object endKey );
// public void addQuery( String aProperty, Object beginKey, Object endKey );
// public void removeQuery( String aProperty, Object beginKey, Object endKey );
// public void retainQuery( String aProperty, Object beginKey, Object endKey );
/**
- * This method is called to notify the DataView
- * that one of its objects has been modified and
- * should be updated when the view is committed.
- */
+ * This method is called to notify the DataView that one of its objects has been
+ * modified and should be updated when the view is committed.
+ */
public void update(Object o);
/**
- * This method is called commit all changes to
- * the DataView to its data store. The list
- * elements may be refreshed from the datastore,
- * although the list itself should remain unchanged.
- * @return True if the commit was successful,
- * otherwise false.
- */
+ * This method is called commit all changes to the DataView to its data store.
+ * The list elements may be refreshed from the datastore, although the list
+ * itself should remain unchanged.
+ *
+ * @return True if the commit was successful, otherwise false.
+ */
public boolean commit();
/**
- * Called to add the specified observer to the
- * list of observers that should receive notifications
- * when the view if modified. DataViews notify
- * when objects are added, updated, or deleted,
- * passing the affected object as the parameter
- * to the Observer's notify method.
- * @param o The observer to add.
- */
- public void addObserver(Observer o);
+ * Called to add the specified observer to the list of observers that should
+ * receive notifications when the view if modified. DataViews notify when
+ * objects are added, updated, or deleted, passing the affected object as the
+ * parameter to the Observer's notify method.
+ *
+ * @param o The observer to add.
+ */
+ public void addObserver(Observer o);
/**
- * Called to remove the specified observer from the
- * list of observers that should receive notifications
- * when the view if modified.
- * @param o The observer to delete.
- */
- public void deleteObserver(Observer o);
+ * Called to remove the specified observer from the list of observers that
+ * should receive notifications when the view if modified.
+ *
+ * @param o The observer to delete.
+ */
+ public void deleteObserver(Observer o);
/**
- * Called to clear the list of observers that should
- * receive notifications when the view if modified.
- */
- public void deleteObservers();
+ * Called to clear the list of observers that should receive notifications when
+ * the view if modified.
+ */
+ public void deleteObservers();
/**
- * Returns the key for the specified object.
- * If the object is not in the view, returns null.
- */
- public DataKey getKeyForObject( Object anObject );
+ * Returns the key for the specified object. If the object is not in the view,
+ * returns null.
+ */
+ public DataKey getKeyForObject(Object anObject);
/**
- * Returns the object for the specified key.
- * If the key is not in the view, returns null.
- */
- public Object getObjectForKey( DataKey aKey );
+ * Returns the object for the specified key. If the key is not in the view,
+ * returns null.
+ */
+ public Object getObjectForKey(DataKey aKey);
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/15 21:12:41 mpowers
- * Added accessors for key throughout the api. This breaks compatibility.
- * insertObject now returns the permanent key for the newly created object.
- * The old way returned a copy of the object which was an additional read
- * that was often ignored. Now you can read it only if you need it.
- * Furthermore, there was not other way of getting the permanent key.
+ * Revision 1.2 2001/02/15 21:12:41 mpowers Added accessors for key throughout
+ * the api. This breaks compatibility. insertObject now returns the permanent
+ * key for the newly created object. The old way returned a copy of the object
+ * which was an additional read that was often ignored. Now you can read it only
+ * if you need it. Furthermore, there was not other way of getting the permanent
+ * key.
*
- * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java
index b97b8a1..dc49737 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java
@@ -24,122 +24,99 @@ import java.util.Comparator;
import net.wotonomy.foundation.internal.ValueConverter;
/**
-* DefaultComparator exists to compare basic java
-* primitive wrappers, since these classes don't
-* implement Comparable in jdk 1.1.x. Also uses
-* ValueConverter to try to match types for comparison.
-*/
-public class DefaultComparator implements Comparator, Serializable
-{
- public int compare(Object o1, Object o2)
- {
+ * DefaultComparator exists to compare basic java primitive wrappers, since
+ * these classes don't implement Comparable in jdk 1.1.x. Also uses
+ * ValueConverter to try to match types for comparison.
+ */
+public class DefaultComparator implements Comparator, Serializable {
+ public int compare(Object o1, Object o2) {
// System.out.println( "compare: " + o1 + " : " + o1.getClass() + " : " + o2 + " : " + o2.getClass() );
-/*
- if ( ( o1 instanceof Comparable ) && ( o2 instanceof Comparable ) )
- {
- return ((Comparable)o1).compareTo( o2 );
- }
-*/
- if ( ( o1 instanceof Number ) && ( o2 instanceof Number ) )
- {
- // TODO: special case for each type would be faster
- return (int)
- ( ((Number)o1).doubleValue() - ((Number)o2).doubleValue() );
- }
-
- if ( o1 instanceof StringBuffer )
- {
- o1 = o1.toString();
- }
- if ( o2 instanceof StringBuffer )
- {
- o2 = o2.toString();
- }
-
- if ( ( o1 instanceof String ) && ( o2 instanceof String ) )
- {
- return ((String)o1).compareTo( ((String)o2) );
- }
-
- if ( ( o1 instanceof Character ) && ( o2 instanceof Character ) )
- {
- return (int)
- ((Character)o1).charValue() - ((Character)o2).charValue();
- }
-
- if ( ( o1 instanceof Byte ) && ( o2 instanceof Byte ) )
- {
- return (int)
- ((Byte)o1).byteValue() - ((Byte)o2).byteValue();
- }
-
- if ( ( o1 instanceof Boolean ) && ( o2 instanceof Boolean ) )
- {
- if ( o1.equals( o2 ) ) return 0;
-
- // presumably TRUE is greater than FALSE
- if ( o1.equals( Boolean.TRUE ) ) return 1;
- return -1;
- }
-
- // handle all NULL cases: NULL is less than anything else.
- if ( ( o1 == null ) && ( o2 == null ) ) return 0;
- if ( ( o1 == null ) && ( o2 != null ) ) return -1;
- if ( ( o2 == null ) && ( o1 != null ) ) return 1;
-
- if ( o1.getClass() != o2.getClass() )
- {
- Object convertedValue;
-
- if ( ! ( o2 instanceof String ) )
- // (string should be lowest common demoninator, if possible)
- {
- // convert first to second's type
- convertedValue =
- ValueConverter.convertObjectToClass( o1, o2.getClass() );
- if ( convertedValue != null )
- {
- return compare( convertedValue, o2 );
- }
- }
-
- // convert second to first's type
- convertedValue =
- ValueConverter.convertObjectToClass( o2, o1.getClass() );
- if ( convertedValue != null )
- {
- return -1 * compare( convertedValue, o1 ); // reverse result
- }
- }
-
- // we tried really hard, but these values are incomparable:
- // we'll consider them equal.
- return 0;
- }
-
- public boolean equals(Object obj)
- {
- return (obj == this);
- }
+ /*
+ * if ( ( o1 instanceof Comparable ) && ( o2 instanceof Comparable ) ) { return
+ * ((Comparable)o1).compareTo( o2 ); }
+ */
+ if ((o1 instanceof Number) && (o2 instanceof Number)) {
+ // TODO: special case for each type would be faster
+ return (int) (((Number) o1).doubleValue() - ((Number) o2).doubleValue());
+ }
+
+ if (o1 instanceof StringBuffer) {
+ o1 = o1.toString();
+ }
+ if (o2 instanceof StringBuffer) {
+ o2 = o2.toString();
+ }
+
+ if ((o1 instanceof String) && (o2 instanceof String)) {
+ return ((String) o1).compareTo(((String) o2));
+ }
+
+ if ((o1 instanceof Character) && (o2 instanceof Character)) {
+ return (int) ((Character) o1).charValue() - ((Character) o2).charValue();
+ }
+
+ if ((o1 instanceof Byte) && (o2 instanceof Byte)) {
+ return (int) ((Byte) o1).byteValue() - ((Byte) o2).byteValue();
+ }
+
+ if ((o1 instanceof Boolean) && (o2 instanceof Boolean)) {
+ if (o1.equals(o2))
+ return 0;
+
+ // presumably TRUE is greater than FALSE
+ if (o1.equals(Boolean.TRUE))
+ return 1;
+ return -1;
+ }
+
+ // handle all NULL cases: NULL is less than anything else.
+ if ((o1 == null) && (o2 == null))
+ return 0;
+ if ((o1 == null) && (o2 != null))
+ return -1;
+ if ((o2 == null) && (o1 != null))
+ return 1;
+
+ if (o1.getClass() != o2.getClass()) {
+ Object convertedValue;
+
+ if (!(o2 instanceof String))
+ // (string should be lowest common demoninator, if possible)
+ {
+ // convert first to second's type
+ convertedValue = ValueConverter.convertObjectToClass(o1, o2.getClass());
+ if (convertedValue != null) {
+ return compare(convertedValue, o2);
+ }
+ }
+
+ // convert second to first's type
+ convertedValue = ValueConverter.convertObjectToClass(o2, o1.getClass());
+ if (convertedValue != null) {
+ return -1 * compare(convertedValue, o1); // reverse result
+ }
+ }
+
+ // we tried really hard, but these values are incomparable:
+ // we'll consider them equal.
+ return 0;
+ }
+
+ public boolean equals(Object obj) {
+ return (obj == this);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:08 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:08 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java
index a8ede78..218c1d4 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java
@@ -25,215 +25,193 @@ import java.util.List;
import java.util.TreeMap;
/**
-* This implementation of DataIndex wraps a TreeMap and
-* adds the ability to contain objects with duplicate keys.
-*/
-public class DefaultDataIndex implements DataIndex
-{
+ * This implementation of DataIndex wraps a TreeMap and adds the ability to
+ * contain objects with duplicate keys.
+ */
+public class DefaultDataIndex implements DataIndex {
static final long serialVersionUID = -3759982714240822885L;
- protected String name;
- protected String property;
- private TreeMap treeMap;
- private Comparator comparator;
-
- public DefaultDataIndex()
- {
- comparator = new DefaultComparator();
- setTreeMap( new TreeMap( new DefaultComparator() ) );
- }
-
- public DefaultDataIndex( String aName, String aProperty )
- {
- this();
- setName( aName );
- setProperty( aProperty );
- }
-
- // included for xml serialization
- public Comparator getComparator() { return comparator; }
- public void setComparator( Comparator aComparator )
- {
- comparator = aComparator;
- // set comparator and copy contents
- TreeMap map = getTreeMap();
- setTreeMap( new TreeMap( comparator ) );
- getTreeMap().putAll( map );
-
- }
-
- public String getName() { return name; };
- public void setName( String aName ) { name = aName; }
- public String getProperty() { return property; };
- public void setProperty( String aProperty ) { property = aProperty; }
- public TreeMap getTreeMap() { return treeMap; }
- public void setTreeMap( TreeMap aMap ) { treeMap = aMap; }
-
- public List query( Object beginValue, Object endValue )
- {
+ protected String name;
+ protected String property;
+ private TreeMap treeMap;
+ private Comparator comparator;
+
+ public DefaultDataIndex() {
+ comparator = new DefaultComparator();
+ setTreeMap(new TreeMap(new DefaultComparator()));
+ }
+
+ public DefaultDataIndex(String aName, String aProperty) {
+ this();
+ setName(aName);
+ setProperty(aProperty);
+ }
+
+ // included for xml serialization
+ public Comparator getComparator() {
+ return comparator;
+ }
+
+ public void setComparator(Comparator aComparator) {
+ comparator = aComparator;
+ // set comparator and copy contents
+ TreeMap map = getTreeMap();
+ setTreeMap(new TreeMap(comparator));
+ getTreeMap().putAll(map);
+
+ }
+
+ public String getName() {
+ return name;
+ };
+
+ public void setName(String aName) {
+ name = aName;
+ }
+
+ public String getProperty() {
+ return property;
+ };
+
+ public void setProperty(String aProperty) {
+ property = aProperty;
+ }
+
+ public TreeMap getTreeMap() {
+ return treeMap;
+ }
+
+ public void setTreeMap(TreeMap aMap) {
+ treeMap = aMap;
+ }
+
+ public List query(Object beginValue, Object endValue) {
//System.out.println( "DefaultDataIndex.query: " + beginValue + " : " + endValue );
List result = new LinkedList();
- if ( endValue == null )
- {
- if ( beginValue == null )
- {
- // begin and end are null, return entire set
- populateListFromIterator( result, treeMap.values().iterator() );
- return result;
- }
-
- // only end is null, return all starting from beginValue
- populateListFromIterator( result,
- treeMap.tailMap( beginValue ).values().iterator() );
+ if (endValue == null) {
+ if (beginValue == null) {
+ // begin and end are null, return entire set
+ populateListFromIterator(result, treeMap.values().iterator());
+ return result;
+ }
+
+ // only end is null, return all starting from beginValue
+ populateListFromIterator(result, treeMap.tailMap(beginValue).values().iterator());
return result;
- }
- else
- if ( beginValue == null )
- {
- // only begin is null, return all ending with endValue
- populateListFromIterator( result,
- treeMap.headMap( endValue ).values().iterator() );
- }
- else
- {
- // begin and end are specified, return all inclusive
- populateListFromIterator( result,
- treeMap.subMap( beginValue, endValue ).values().iterator() );
+ } else if (beginValue == null) {
+ // only begin is null, return all ending with endValue
+ populateListFromIterator(result, treeMap.headMap(endValue).values().iterator());
+ } else {
+ // begin and end are specified, return all inclusive
+ populateListFromIterator(result, treeMap.subMap(beginValue, endValue).values().iterator());
}
-
+
// append endValue results, so it's inclusive
- Object o = treeMap.get( endValue );
- if ( o != null )
- {
- if ( o instanceof DuplicateList )
- {
- populateListFromIterator( result,
- ((DuplicateList)o).iterator() );
- }
- else
- {
- result.add( o );
- }
+ Object o = treeMap.get(endValue);
+ if (o != null) {
+ if (o instanceof DuplicateList) {
+ populateListFromIterator(result, ((DuplicateList) o).iterator());
+ } else {
+ result.add(o);
+ }
}
-
+
// return complete result
return result;
}
-
- protected void populateListFromIterator( List aList, Iterator it )
- {
- Object o;
- while ( it.hasNext() )
- {
- o = it.next();
- if ( o instanceof DuplicateList )
- {
- populateListFromIterator(
- aList, ((DuplicateList)o).iterator() );
- }
- else
- {
- aList.add( o );
- }
- }
- }
-
- public Object addObject( Object anObject, Object newValue )
- {
- Object o = treeMap.get( newValue );
- if ( o != null )
- {
- if ( o instanceof DuplicateList )
- {
- ((DuplicateList)o).add( anObject );
- return anObject;
- }
-
- DuplicateList list = new DuplicateList();
- list.add( o );
- list.add( anObject );
- anObject = list;
-
- }
-if ( anObject == null ) new RuntimeException().printStackTrace();
-
- treeMap.put( newValue, anObject );
- return anObject;
- }
-
- public Object updateObject( Object anObject,
- Object oldValue, Object newValue )
- {
- removeObject( anObject, oldValue );
- return addObject( anObject, newValue );
- }
-
- public Object removeObject( Object anObject, Object oldValue )
- {
- Object o = treeMap.get( oldValue );
- if ( o != null )
- {
- if ( o instanceof DuplicateList )
- {
- // remove this item from the list
- DuplicateList list = (DuplicateList) o;
- list.remove( anObject );
-
+
+ protected void populateListFromIterator(List aList, Iterator it) {
+ Object o;
+ while (it.hasNext()) {
+ o = it.next();
+ if (o instanceof DuplicateList) {
+ populateListFromIterator(aList, ((DuplicateList) o).iterator());
+ } else {
+ aList.add(o);
+ }
+ }
+ }
+
+ public Object addObject(Object anObject, Object newValue) {
+ Object o = treeMap.get(newValue);
+ if (o != null) {
+ if (o instanceof DuplicateList) {
+ ((DuplicateList) o).add(anObject);
+ return anObject;
+ }
+
+ DuplicateList list = new DuplicateList();
+ list.add(o);
+ list.add(anObject);
+ anObject = list;
+
+ }
+ if (anObject == null)
+ new RuntimeException().printStackTrace();
+
+ treeMap.put(newValue, anObject);
+ return anObject;
+ }
+
+ public Object updateObject(Object anObject, Object oldValue, Object newValue) {
+ removeObject(anObject, oldValue);
+ return addObject(anObject, newValue);
+ }
+
+ public Object removeObject(Object anObject, Object oldValue) {
+ Object o = treeMap.get(oldValue);
+ if (o != null) {
+ if (o instanceof DuplicateList) {
+ // remove this item from the list
+ DuplicateList list = (DuplicateList) o;
+ list.remove(anObject);
+
// if there are still duplicates, return
- if ( list.size() > 1 )
- return anObject;
-
- // else, list size must be one
- if ( list.size() == 0 )
- {
- System.out.println( "DefaultDataIndex.deleteObject: " + oldValue
- + " : list size is 1 : this should never happen." );
+ if (list.size() > 1)
+ return anObject;
+
+ // else, list size must be one
+ if (list.size() == 0) {
+ System.out.println("DefaultDataIndex.deleteObject: " + oldValue
+ + " : list size is 1 : this should never happen.");
return null;
- }
+ }
- // replace existing list with remaining item from list
- treeMap.remove( oldValue );
- treeMap.put( oldValue, list.getFirst() );
- return anObject;
- }
+ // replace existing list with remaining item from list
+ treeMap.remove(oldValue);
+ treeMap.put(oldValue, list.getFirst());
+ return anObject;
+ }
// otherwise, proceed normally
- treeMap.remove( oldValue );
- }
+ treeMap.remove(oldValue);
+ }
return anObject;
- }
-
- public void clear()
- {
- treeMap.clear();
- }
-
- public String toString()
- {
- return "DefaultDataIndex: " + name + " : " + property + " : " + treeMap.toString();
- }
-
+ }
+
+ public void clear() {
+ treeMap.clear();
+ }
+
+ public String toString() {
+ return "DefaultDataIndex: " + name + " : " + property + " : " + treeMap.toString();
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/14 19:29:38 chochos
- * minor cleanup (imports, static method calls, etc)
+ * Revision 1.2 2003/08/14 19:29:38 chochos minor cleanup (imports, static
+ * method calls, etc)
*
- * Revision 1.1.1.1 2000/12/21 15:47:11 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:11 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java
index ca76252..1864cac 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java
@@ -26,21 +26,18 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Observable;
-public class DefaultDataView extends Observable
- implements DataView
-{
- protected DataSoup backingSoup;
- protected List objectList;
- protected List keyList;
- protected List addedObjectList;
- protected List removedObjectList;
- protected List addedKeyList;
- protected List removedKeyList;
- protected Collection updatedObjects;
- protected boolean fullyLoaded;
-
- DefaultDataView( DataSoup aSoup, Collection aKeyList )
- {
+public class DefaultDataView extends Observable implements DataView {
+ protected DataSoup backingSoup;
+ protected List objectList;
+ protected List keyList;
+ protected List addedObjectList;
+ protected List removedObjectList;
+ protected List addedKeyList;
+ protected List removedKeyList;
+ protected Collection updatedObjects;
+ protected boolean fullyLoaded;
+
+ DefaultDataView(DataSoup aSoup, Collection aKeyList) {
backingSoup = aSoup;
objectList = new ArrayList();
keyList = new ArrayList();
@@ -51,11 +48,10 @@ public class DefaultDataView extends Observable
updatedObjects = new LinkedList();
fullyLoaded = false;
- setKeyList( aKeyList );
+ setKeyList(aKeyList);
}
-
- void setKeyList( Collection aCollection )
- {
+
+ void setKeyList(Collection aCollection) {
fullyLoaded = false;
addedObjectList.clear();
removedObjectList.clear();
@@ -64,494 +60,434 @@ public class DefaultDataView extends Observable
updatedObjects.clear();
keyList.clear();
objectList.clear();
- if ( ( aCollection == null ) || ( aCollection.size() == 0 ) )
- {
+ if ((aCollection == null) || (aCollection.size() == 0)) {
return;
}
- keyList.addAll( aCollection );
- for ( int i = 0; i < keyList.size(); i++ )
- {
- objectList.add( null );
+ keyList.addAll(aCollection);
+ for (int i = 0; i < keyList.size(); i++) {
+ objectList.add(null);
}
}
- public Object get( int i )
- {
- if ( i > keyList.size() ) return null;
+ public Object get(int i) {
+ if (i > keyList.size())
+ return null;
- Object o = objectList.get( i );
- if ( o == null )
- {
- Object key = keyList.get( i );
- if ( key == null ) return null; // FIXME!!
+ Object o = objectList.get(i);
+ if (o == null) {
+ Object key = keyList.get(i);
+ if (key == null)
+ return null; // FIXME!!
- //NOTE: this is the gateway for getting object from the soup
- o = backingSoup.getObjectByKey( (DataKey) key );
+ // NOTE: this is the gateway for getting object from the soup
+ o = backingSoup.getObjectByKey((DataKey) key);
- objectList.set( i, o );
+ objectList.set(i, o);
}
return o;
}
- public int indexOf( Object o )
- {
- if ( o == null ) return -1;
- for ( int i = 0; i < size(); i++ )
- {
- if ( o.equals( get( i ) ) )
- {
- return i;
- }
- }
- return -1;
- }
-
- private int indexOfIdenticalObject( Object o )
- {
- if ( o == null ) return -1;
- for ( int i = 0; i < size(); i++ )
- {
- if ( o == get( i ) )
- {
- return i;
- }
- }
- return -1;
- }
-
- public int lastIndexOf( Object o )
- {
- if ( o == null ) return -1;
- int lastIndex = -1;
- for ( int i = 0; i < size(); i++ )
- {
- if ( o.equals( get( i ) ) )
- {
- lastIndex = i;
- }
- }
- return lastIndex;
- }
-
- protected void loadAllObjects()
- {
- if ( fullyLoaded ) return;
- for ( int i = 0; i < keyList.size(); i++ )
- {
- get( i );
+ public int indexOf(Object o) {
+ if (o == null)
+ return -1;
+ for (int i = 0; i < size(); i++) {
+ if (o.equals(get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private int indexOfIdenticalObject(Object o) {
+ if (o == null)
+ return -1;
+ for (int i = 0; i < size(); i++) {
+ if (o == get(i)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int lastIndexOf(Object o) {
+ if (o == null)
+ return -1;
+ int lastIndex = -1;
+ for (int i = 0; i < size(); i++) {
+ if (o.equals(get(i))) {
+ lastIndex = i;
+ }
+ }
+ return lastIndex;
+ }
+
+ protected void loadAllObjects() {
+ if (fullyLoaded)
+ return;
+ for (int i = 0; i < keyList.size(); i++) {
+ get(i);
}
fullyLoaded = true;
}
-
- // convenience to return the first object, or null.
- public Object getObject()
- {
- return get( 0 );
- }
-
+
+ // convenience to return the first object, or null.
+ public Object getObject() {
+ return get(0);
+ }
+
// marked object as updated
- public void update( Object anObject )
- {
- if ( contains( anObject ) )
- {
- if ( ! addedObjectList.contains( anObject ) )
- {
- updatedObjects.add( anObject );
- }
+ public void update(Object anObject) {
+ if (contains(anObject)) {
+ if (!addedObjectList.contains(anObject)) {
+ updatedObjects.add(anObject);
+ }
}
- // notification
- setChanged();
- notifyObservers( anObject );
- }
-
- // DefaultDataViews know their parent soup to perform the query
- // and take the subset
- public DataView query(
- String aProperty, Object beginKey, Object endKey ) { return this; }
-
- public boolean commit()
- {
- int index;
- Object o;
- DataKey key;
- for ( int i = 0; i < addedObjectList.size(); i++ )
- {
- o = addedObjectList.get(i);
- key = backingSoup.addObject( o );
- index = indexOfIdenticalObject( o );
- keyList.set( index, key );
+ // notification
+ setChanged();
+ notifyObservers(anObject);
+ }
+
+ // DefaultDataViews know their parent soup to perform the query
+ // and take the subset
+ public DataView query(String aProperty, Object beginKey, Object endKey) {
+ return this;
+ }
+
+ public boolean commit() {
+ int index;
+ Object o;
+ DataKey key;
+ for (int i = 0; i < addedObjectList.size(); i++) {
+ o = addedObjectList.get(i);
+ key = backingSoup.addObject(o);
+ index = indexOfIdenticalObject(o);
+ keyList.set(index, key);
}
addedObjectList.clear();
addedKeyList.clear();
- for ( int i = 0; i < removedObjectList.size(); i++ )
- {
- backingSoup.removeObject( (DataKey) removedKeyList.get(i) );
+ for (int i = 0; i < removedObjectList.size(); i++) {
+ backingSoup.removeObject((DataKey) removedKeyList.get(i));
}
removedObjectList.clear();
removedKeyList.clear();
int i;
Iterator it = updatedObjects.iterator();
- while ( it.hasNext() )
- {
- i = objectList.indexOf( it.next() );
- backingSoup.updateObject(
- (DataKey) keyList.get(i), objectList.get(i) );
+ while (it.hasNext()) {
+ i = objectList.indexOf(it.next());
+ backingSoup.updateObject((DataKey) keyList.get(i), objectList.get(i));
}
updatedObjects.clear();
- // notification
- setChanged();
- notifyObservers( this );
+ // notification
+ setChanged();
+ notifyObservers(this);
return true;
}
- public DataKey getKeyForObject( Object anObject )
- {
- int index = indexOfIdenticalObject( anObject );
- if ( index == -1 ) return null;
- return (DataKey) keyList.get( index );
- }
+ public DataKey getKeyForObject(Object anObject) {
+ int index = indexOfIdenticalObject(anObject);
+ if (index == -1)
+ return null;
+ return (DataKey) keyList.get(index);
+ }
- public Object getObjectForKey( DataKey aKey )
- {
- int index = keyList.indexOf( aKey );
- if ( index == -1 ) return null;
- return get( index );
- }
+ public Object getObjectForKey(DataKey aKey) {
+ int index = keyList.indexOf(aKey);
+ if (index == -1)
+ return null;
+ return get(index);
+ }
// interface Collection
- public int size () { return keyList.size(); }
- public boolean isEmpty () { return keyList.isEmpty(); }
- public void clear () { setKeyList( null ); };
- public int hashCode() { return keyList.hashCode(); };
+ public int size() {
+ return keyList.size();
+ }
+
+ public boolean isEmpty() {
+ return keyList.isEmpty();
+ }
+
+ public void clear() {
+ setKeyList(null);
+ };
+
+ public int hashCode() {
+ return keyList.hashCode();
+ };
- public boolean equals (Object o)
- {
- if ( ! ( o instanceof DefaultDataView ) ) return false;
- return keyList.equals( ((DefaultDataView)o).keyList );
+ public boolean equals(Object o) {
+ if (!(o instanceof DefaultDataView))
+ return false;
+ return keyList.equals(((DefaultDataView) o).keyList);
}
- public boolean contains (Object o)
- {
+ public boolean contains(Object o) {
loadAllObjects();
return objectList.contains(o);
}
- public boolean containsAll (Collection c)
- {
- loadAllObjects();
- return objectList.containsAll( c );
- }
-
- public boolean add (Object o)
- {
- // if previously removed, restore to list
- if ( removedObjectList.contains( o ) )
- {
- int index = removedObjectList.indexOf( o );
- removedObjectList.remove( index );
- Object key = removedKeyList.remove( index );
- objectList.add( o );
- keyList.add( key );
-
- // notification
- setChanged();
- notifyObservers( o );
- return true;
- }
-
- // register and add to lists
- Object key = backingSoup.registerTemporaryObject( o );
- addedObjectList.add( o );
- addedKeyList.add( key );
- objectList.add( o );
- keyList.add( key );
-
- // notification
- setChanged();
- notifyObservers( o );
- return true;
- }
-
- public Object remove( int index )
- {
- Object result = get( index );
- if ( remove( result ) )
- {
- return result;
- }
- return null;
- }
-
- public boolean remove (Object o)
- {
- loadAllObjects();
-
- int index = objectList.indexOf( o );
- if ( index == -1 ) return false;
-
- objectList.remove( index );
- Object key = keyList.remove( index );
-
- if ( updatedObjects.contains( o ) )
- {
- updatedObjects.remove( o );
- }
-
- // if not previously added, track removal
- if ( ! ( removedObjectList.contains( o ) ) )
- {
- removedObjectList.add( o );
- removedKeyList.add( key );
- }
-
- // notification
- setChanged();
- notifyObservers( o );
-
- return true;
- }
-
- /**
- * Set completely replaces the object at the specified
- * index with the specified object. The new object is not
- * marked as inserted, and the old object is not marked
- * as deleted: the new object will be stored in the soup
- * with the same key. The old object is returned.
- */
- public Object set( int index, Object element )
- {
- Object result = objectList.set( index, element );
- update( element );
- return result;
- }
-
- public void add( int index, Object o )
- {
- // if previously removed, restore to list
- if ( removedObjectList.contains( o ) )
- {
- int i = removedObjectList.indexOf( o );
- removedObjectList.remove( i );
- Object key = removedKeyList.remove( i );
- objectList.add( index, o );
- keyList.add( index, key );
-
- // notification
- setChanged();
- notifyObservers( o );
- return;
- }
-
- // register and add to lists
- Object key = backingSoup.registerTemporaryObject( o );
- addedObjectList.add( o );
- addedKeyList.add( key );
- objectList.add( index, o );
- keyList.add( index, key );
-
- // notification
- setChanged();
- notifyObservers( o );
- }
-
- public boolean addAll (Collection c)
- {
- boolean result = true;
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- result = result && add( it.next() );
- }
- return result;
- }
-
- public boolean addAll (int index, Collection c)
- {
- int originalSize = size();
- boolean result = true;
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- add( index, it.next() );
- }
- return ( originalSize + c.size() == size() );
- }
-
- public boolean removeAll (Collection c)
- {
- boolean result = true;
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- result = result && remove( it.next() );
- }
- return result;
- }
-
- public boolean retainAll (Collection c)
- {
- removeAll( new ArrayList( objectList ) );
- return addAll( c );
- }
-
- public List subList( int fromIndex, int toIndex )
- {
- List result = new LinkedList();
- for ( int i = fromIndex; i < toIndex; i++ )
- {
- result.add( get( i ) );
- }
- return result;
- }
-
- public Iterator iterator()
- {
- loadAllObjects();
- return objectList.iterator();
-
-/* // uncomment to enable on-demand loading
- return new Iterator()
- {
- int index = 0;
- public boolean hasNext() { return ( index + 1 < keyList.size() ); }
- public Object next() {
- return get( index++ ); }
- public void remove()
- {
- Object o = get( index );
- if ( o != null ) DefaultDataView.this.remove( o );
- }
- };
-*/
- }
-
- public ListIterator listIterator()
- {
- return new DataViewIterator( this );
- }
-
- public ListIterator listIterator( int index )
- {
- return new DataViewIterator( this, index );
- }
-
- public Object[] toArray ()
- {
- loadAllObjects();
- return objectList.toArray();
- }
- public java.lang.Object[] toArray (Object[] array)
- {
- loadAllObjects();
- return objectList.toArray( array );
- }
-
- protected class DataViewIterator implements ListIterator
- {
- DataView theView;
- int currentIndex;
-
- //TODO: should track current object in addition to index
- // to track external changes to the view. (or should be listener)
- Object currentObject;
-
- public DataViewIterator( DataView aView )
- {
- this( aView, 0 );
- }
-
- public DataViewIterator( DataView aView, int index )
- {
- theView = aView;
- if ( theView.size() > index )
- {
- currentIndex = index;
- currentObject = theView.get( currentIndex );
- }
- else
- {
- index = -1;
- currentObject = null;
- }
- }
-
- public void add( Object o )
- {
- currentIndex++;
- theView.add( currentIndex, o );
- }
-
- public boolean hasNext()
- {
- return ( theView.size() > currentIndex + 1 );
- }
-
- public boolean hasPrevious()
- {
- return ( currentIndex > -1 );
- }
-
- public Object next()
- {
- return theView.get( ++currentIndex );
- }
-
- public int nextIndex()
- {
- return currentIndex + 1;
- }
-
- public Object previous()
- {
- return theView.get( currentIndex-- );
- }
-
- public int previousIndex()
- {
- return currentIndex;
- }
-
- public void remove()
- {
- theView.remove( currentIndex-- );
- }
-
- public void set( Object o )
- {
- theView.set( currentIndex, o );
- }
-
- }
+ public boolean containsAll(Collection c) {
+ loadAllObjects();
+ return objectList.containsAll(c);
+ }
+
+ public boolean add(Object o) {
+ // if previously removed, restore to list
+ if (removedObjectList.contains(o)) {
+ int index = removedObjectList.indexOf(o);
+ removedObjectList.remove(index);
+ Object key = removedKeyList.remove(index);
+ objectList.add(o);
+ keyList.add(key);
+
+ // notification
+ setChanged();
+ notifyObservers(o);
+ return true;
+ }
+
+ // register and add to lists
+ Object key = backingSoup.registerTemporaryObject(o);
+ addedObjectList.add(o);
+ addedKeyList.add(key);
+ objectList.add(o);
+ keyList.add(key);
+
+ // notification
+ setChanged();
+ notifyObservers(o);
+ return true;
+ }
+
+ public Object remove(int index) {
+ Object result = get(index);
+ if (remove(result)) {
+ return result;
+ }
+ return null;
+ }
+
+ public boolean remove(Object o) {
+ loadAllObjects();
+
+ int index = objectList.indexOf(o);
+ if (index == -1)
+ return false;
+
+ objectList.remove(index);
+ Object key = keyList.remove(index);
+
+ if (updatedObjects.contains(o)) {
+ updatedObjects.remove(o);
+ }
+
+ // if not previously added, track removal
+ if (!(removedObjectList.contains(o))) {
+ removedObjectList.add(o);
+ removedKeyList.add(key);
+ }
+
+ // notification
+ setChanged();
+ notifyObservers(o);
+
+ return true;
+ }
+
+ /**
+ * Set completely replaces the object at the specified index with the specified
+ * object. The new object is not marked as inserted, and the old object is not
+ * marked as deleted: the new object will be stored in the soup with the same
+ * key. The old object is returned.
+ */
+ public Object set(int index, Object element) {
+ Object result = objectList.set(index, element);
+ update(element);
+ return result;
+ }
+
+ public void add(int index, Object o) {
+ // if previously removed, restore to list
+ if (removedObjectList.contains(o)) {
+ int i = removedObjectList.indexOf(o);
+ removedObjectList.remove(i);
+ Object key = removedKeyList.remove(i);
+ objectList.add(index, o);
+ keyList.add(index, key);
+
+ // notification
+ setChanged();
+ notifyObservers(o);
+ return;
+ }
+
+ // register and add to lists
+ Object key = backingSoup.registerTemporaryObject(o);
+ addedObjectList.add(o);
+ addedKeyList.add(key);
+ objectList.add(index, o);
+ keyList.add(index, key);
+
+ // notification
+ setChanged();
+ notifyObservers(o);
+ }
+
+ public boolean addAll(Collection c) {
+ boolean result = true;
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ result = result && add(it.next());
+ }
+ return result;
+ }
+
+ public boolean addAll(int index, Collection c) {
+ int originalSize = size();
+ boolean result = true;
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ add(index, it.next());
+ }
+ return (originalSize + c.size() == size());
+ }
+
+ public boolean removeAll(Collection c) {
+ boolean result = true;
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ result = result && remove(it.next());
+ }
+ return result;
+ }
+
+ public boolean retainAll(Collection c) {
+ removeAll(new ArrayList(objectList));
+ return addAll(c);
+ }
+
+ public List subList(int fromIndex, int toIndex) {
+ List result = new LinkedList();
+ for (int i = fromIndex; i < toIndex; i++) {
+ result.add(get(i));
+ }
+ return result;
+ }
+
+ public Iterator iterator() {
+ loadAllObjects();
+ return objectList.iterator();
+
+ /*
+ * // uncomment to enable on-demand loading return new Iterator() { int index =
+ * 0; public boolean hasNext() { return ( index + 1 < keyList.size() ); } public
+ * Object next() { return get( index++ ); } public void remove() { Object o =
+ * get( index ); if ( o != null ) DefaultDataView.this.remove( o ); } };
+ */
+ }
+
+ public ListIterator listIterator() {
+ return new DataViewIterator(this);
+ }
+
+ public ListIterator listIterator(int index) {
+ return new DataViewIterator(this, index);
+ }
+
+ public Object[] toArray() {
+ loadAllObjects();
+ return objectList.toArray();
+ }
+
+ public java.lang.Object[] toArray(Object[] array) {
+ loadAllObjects();
+ return objectList.toArray(array);
+ }
+
+ protected class DataViewIterator implements ListIterator {
+ DataView theView;
+ int currentIndex;
+
+ // TODO: should track current object in addition to index
+ // to track external changes to the view. (or should be listener)
+ Object currentObject;
+
+ public DataViewIterator(DataView aView) {
+ this(aView, 0);
+ }
+
+ public DataViewIterator(DataView aView, int index) {
+ theView = aView;
+ if (theView.size() > index) {
+ currentIndex = index;
+ currentObject = theView.get(currentIndex);
+ } else {
+ index = -1;
+ currentObject = null;
+ }
+ }
+
+ public void add(Object o) {
+ currentIndex++;
+ theView.add(currentIndex, o);
+ }
+
+ public boolean hasNext() {
+ return (theView.size() > currentIndex + 1);
+ }
+
+ public boolean hasPrevious() {
+ return (currentIndex > -1);
+ }
+
+ public Object next() {
+ return theView.get(++currentIndex);
+ }
+
+ public int nextIndex() {
+ return currentIndex + 1;
+ }
+
+ public Object previous() {
+ return theView.get(currentIndex--);
+ }
+
+ public int previousIndex() {
+ return currentIndex;
+ }
+
+ public void remove() {
+ theView.remove(currentIndex--);
+ }
+
+ public void set(Object o) {
+ theView.set(currentIndex, o);
+ }
+
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/15 21:12:41 mpowers
- * Added accessors for key throughout the api. This breaks compatibility.
- * insertObject now returns the permanent key for the newly created object.
- * The old way returned a copy of the object which was an additional read
- * that was often ignored. Now you can read it only if you need it.
- * Furthermore, there was not other way of getting the permanent key.
+ * Revision 1.2 2001/02/15 21:12:41 mpowers Added accessors for key throughout
+ * the api. This breaks compatibility. insertObject now returns the permanent
+ * key for the newly created object. The old way returned a copy of the object
+ * which was an additional read that was often ignored. Now you can read it only
+ * if you need it. Furthermore, there was not other way of getting the permanent
+ * key.
*
- * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java
index ed47b24..9a5458f 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java
@@ -21,29 +21,22 @@ package net.wotonomy.datastore;
import java.util.LinkedList;
/**
-* DuplicateList is a marker class used to store values
-* with duplicate keys in the DataIndex TreeMap.
-*/
-public class DuplicateList extends LinkedList
-{
+ * DuplicateList is a marker class used to store values with duplicate keys in
+ * the DataIndex TreeMap.
+ */
+public class DuplicateList extends LinkedList {
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java
index 45cc9d8..d8b8df0 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java
@@ -29,82 +29,71 @@ import java.util.Map;
import net.wotonomy.foundation.internal.Introspector;
-abstract public class FileSoup implements DataSoup
-{
- public static final String INDEX_SUFFIX = ".idx";
- public static final String MAP_SUFFIX = ".map";
- private static final String ID_ID = "id";
- private static final String IDENTITY_PROPERTY = "__SELF__";
-
- protected DataKey nextUniqueIdentifier;
- protected File homeDirectory;
- protected Map indices;
-
- public FileSoup( String aPath )
- {
- homeDirectory = new File( aPath );
-
- // if specified directory does not exist
- if ( ! homeDirectory.exists() )
- {
- homeDirectory.mkdirs();
- }
-
- // if existing path is a file, exit with error
- if ( homeDirectory.isDirectory() )
- {
- new RuntimeException( "DataStore: Specified directory is a file." );
- }
-
- // read indices
- DataIndex index;
- indices = new HashMap();
- String[] files = getHomeDirectory().list();
- for ( int i = 0; i < files.length; i++ )
- {
- if ( files[i].endsWith( INDEX_SUFFIX ) )
- {
- index = (DataIndex) readFile( files[i] );
- if ( index != null )
- {
- indices.put( index.getName(), index );
- }
- }
- }
-
- // read unique identifier
- nextUniqueIdentifier = (DataKey) readFile( ID_ID );
- if ( nextUniqueIdentifier == null )
- nextUniqueIdentifier = new DataKey( "1" );
-
- }
-
- public File getHomeDirectory()
- {
- return homeDirectory;
- }
-
- // index management
-
- public void addIndex( String aName, String aProperty )
- {
- DataIndex index = new DefaultDataIndex( aName, aProperty );
- indices.put( index.getName(), index );
- buildIndex( index );
+abstract public class FileSoup implements DataSoup {
+ public static final String INDEX_SUFFIX = ".idx";
+ public static final String MAP_SUFFIX = ".map";
+ private static final String ID_ID = "id";
+ private static final String IDENTITY_PROPERTY = "__SELF__";
+
+ protected DataKey nextUniqueIdentifier;
+ protected File homeDirectory;
+ protected Map indices;
+
+ public FileSoup(String aPath) {
+ homeDirectory = new File(aPath);
+
+ // if specified directory does not exist
+ if (!homeDirectory.exists()) {
+ homeDirectory.mkdirs();
+ }
+
+ // if existing path is a file, exit with error
+ if (homeDirectory.isDirectory()) {
+ new RuntimeException("DataStore: Specified directory is a file.");
+ }
+
+ // read indices
+ DataIndex index;
+ indices = new HashMap();
+ String[] files = getHomeDirectory().list();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].endsWith(INDEX_SUFFIX)) {
+ index = (DataIndex) readFile(files[i]);
+ if (index != null) {
+ indices.put(index.getName(), index);
+ }
+ }
+ }
+
+ // read unique identifier
+ nextUniqueIdentifier = (DataKey) readFile(ID_ID);
+ if (nextUniqueIdentifier == null)
+ nextUniqueIdentifier = new DataKey("1");
+
+ }
+
+ public File getHomeDirectory() {
+ return homeDirectory;
+ }
+
+ // index management
+
+ public void addIndex(String aName, String aProperty) {
+ DataIndex index = new DefaultDataIndex(aName, aProperty);
+ indices.put(index.getName(), index);
+ buildIndex(index);
writeIndices();
- }
-
- public void removeIndex( String aName )
- {
- indices.remove( aName );
+ }
+
+ public void removeIndex(String aName) {
+ indices.remove(aName);
writeIndices();
- }
+ }
+
+ public Collection getAllIndices() {
+ return indices.values();
+ }
- public Collection getAllIndices()
- {
- return indices.values();
- }
-
// public void addIndex( String aName, Index anIndex ) {}
// public void removeIndex( String aName ) {}
// public void addTaggedObject( String aKey, Serializable anObject )
@@ -112,357 +101,315 @@ abstract public class FileSoup implements DataSoup
// public void removeTaggedObject( String aKey );
// public void setMetaData(
// String aMetaProperty, Serializable aValue, Serializable anObject );
-
- protected void buildIndex( DataIndex anIndex )
- {
+
+ protected void buildIndex(DataIndex anIndex) {
//System.out.print( "FileSoup.buildIndex: " + anIndex.getName() + " : " );
-long millis = System.currentTimeMillis();
+ long millis = System.currentTimeMillis();
- anIndex.clear();
+ anIndex.clear();
- int count = 0;
+ int count = 0;
DataKey key;
- Object o;
- Object value;
+ Object o;
+ Object value;
String property = anIndex.getProperty();
-
- String[] files = getHomeDirectory().list();
- for ( int i = 0; i < files.length; i++ )
- {
- if ( ( ! files[i].equals( ID_ID.toString() )
- && ( ! files[i].endsWith( INDEX_SUFFIX ) ) ) )
- {
- key = new DataKey( files[i] );
- o = getObjectByKey( key );
- value = getValueFromObject( o, property );
- anIndex.addObject( key, value );
- count++;
- }
- }
-
+
+ String[] files = getHomeDirectory().list();
+ for (int i = 0; i < files.length; i++) {
+ if ((!files[i].equals(ID_ID.toString()) && (!files[i].endsWith(INDEX_SUFFIX)))) {
+ key = new DataKey(files[i]);
+ o = getObjectByKey(key);
+ value = getValueFromObject(o, property);
+ anIndex.addObject(key, value);
+ count++;
+ }
+ }
+
//System.out.print( count + " objects: " );
//System.out.println( System.currentTimeMillis() - millis + " milliseconds" );
- }
- protected void writeIndices()
- {
- DataIndex index;
- Iterator it = getAllIndices().iterator();
- while ( it.hasNext() )
- {
- index = (DataIndex) it.next();
- writeFile( index.getName() + INDEX_SUFFIX, index );
- }
- }
+ }
+
+ protected void writeIndices() {
+ DataIndex index;
+ Iterator it = getAllIndices().iterator();
+ while (it.hasNext()) {
+ index = (DataIndex) it.next();
+ writeFile(index.getName() + INDEX_SUFFIX, index);
+ }
+ }
// object management
// this implementation currently uses up a valid key increment
- public DataKey registerTemporaryObject( Object anObject )
- {
+ public DataKey registerTemporaryObject(Object anObject) {
DataKey id = getNextKey();
-
- if ( anObject instanceof UniquelyIdentifiable )
- {
- ((UniquelyIdentifiable)anObject).setUniqueIdentifier( id );
+
+ if (anObject instanceof UniquelyIdentifiable) {
+ ((UniquelyIdentifiable) anObject).setUniqueIdentifier(id);
}
-
+
return id;
}
-
- /**
- * Adds the specified object to the soup and returns the key
- * for the new object by which it may be subsequently retrieved.
- * Null indicates an error, probably due to serialization.
- */
- public DataKey addObject( Object anObject )
- {
- DataKey id = getNextKey();
-
- if ( anObject instanceof UniquelyIdentifiable )
- { // set id if necessary
- ((UniquelyIdentifiable)anObject).setUniqueIdentifier( id );
- }
-
- writeFile( id.toString(), anObject );
-
- // update indices
+
+ /**
+ * Adds the specified object to the soup and returns the key for the new object
+ * by which it may be subsequently retrieved. Null indicates an error, probably
+ * due to serialization.
+ */
+ public DataKey addObject(Object anObject) {
+ DataKey id = getNextKey();
+
+ if (anObject instanceof UniquelyIdentifiable) { // set id if necessary
+ ((UniquelyIdentifiable) anObject).setUniqueIdentifier(id);
+ }
+
+ writeFile(id.toString(), anObject);
+
+ // update indices
DataIndex index;
Iterator it = indices.values().iterator();
- while ( it.hasNext() )
- {
- index = (DataIndex)it.next();
- index.addObject( id,
- getValueFromObject( anObject, index.getProperty() ) );
+ while (it.hasNext()) {
+ index = (DataIndex) it.next();
+ index.addObject(id, getValueFromObject(anObject, index.getProperty()));
}
-
+
writeIndices();
return id;
- }
-
- /**
- * Removes the specified object from the soup and returns
- * the removed object as read from the soup (which is the
- * original copy of the object). Null indicates object not found.
- */
- public Object removeObject( DataKey aKey )
- {
- Object existing = getObjectByKey( aKey );
- if ( existing != null )
- {
- if ( ! deleteFile( aKey.toString() ) )
- {
- existing = null; // return error
- }
- else
- {
- // update indices
- DataIndex index;
- Iterator it = indices.values().iterator();
- while ( it.hasNext() )
- {
- index = (DataIndex)it.next();
- index.removeObject( aKey,
- getValueFromObject( existing, index.getProperty() ) );
- }
-
- writeIndices();
+ }
+
+ /**
+ * Removes the specified object from the soup and returns the removed object as
+ * read from the soup (which is the original copy of the object). Null indicates
+ * object not found.
+ */
+ public Object removeObject(DataKey aKey) {
+ Object existing = getObjectByKey(aKey);
+ if (existing != null) {
+ if (!deleteFile(aKey.toString())) {
+ existing = null; // return error
+ } else {
+ // update indices
+ DataIndex index;
+ Iterator it = indices.values().iterator();
+ while (it.hasNext()) {
+ index = (DataIndex) it.next();
+ index.removeObject(aKey, getValueFromObject(existing, index.getProperty()));
+ }
+
+ writeIndices();
}
- }
-
- return existing;
- }
-
- /**
- * Updates the specified object and returns the object
- * as updated. Null indicates an error writing the object.
- */
- public Object updateObject( DataKey aKey, Object updatedObject )
- {
- Object existing = getObjectByKey( aKey );
- if ( existing == null )
- {
- System.err.println( "FileSoup.updateObject: " +
- "existing object could not be found with id: " + aKey );
- return null;
- }
-
- Object result = null;
- if ( updatedObject instanceof UniquelyIdentifiable )
- {
+ }
+
+ return existing;
+ }
+
+ /**
+ * Updates the specified object and returns the object as updated. Null
+ * indicates an error writing the object.
+ */
+ public Object updateObject(DataKey aKey, Object updatedObject) {
+ Object existing = getObjectByKey(aKey);
+ if (existing == null) {
+ System.err.println("FileSoup.updateObject: " + "existing object could not be found with id: " + aKey);
+ return null;
+ }
+
+ Object result = null;
+ if (updatedObject instanceof UniquelyIdentifiable) {
// update key if changed
- ((UniquelyIdentifiable)updatedObject).setUniqueIdentifier( aKey );
- }
-
- if ( writeFile( aKey.toString(), updatedObject ) )
- {
- result = updatedObject;
-
- // update indices
- DataIndex index;
- Iterator it = indices.values().iterator();
- while ( it.hasNext() )
- {
- index = (DataIndex)it.next();
- index.updateObject( aKey,
- getValueFromObject( existing, index.getProperty() ),
- getValueFromObject( updatedObject, index.getProperty() ) );
- }
-
- writeIndices();
- }
-
+ ((UniquelyIdentifiable) updatedObject).setUniqueIdentifier(aKey);
+ }
+
+ if (writeFile(aKey.toString(), updatedObject)) {
+ result = updatedObject;
+
+ // update indices
+ DataIndex index;
+ Iterator it = indices.values().iterator();
+ while (it.hasNext()) {
+ index = (DataIndex) it.next();
+ index.updateObject(aKey, getValueFromObject(existing, index.getProperty()),
+ getValueFromObject(updatedObject, index.getProperty()));
+ }
+
+ writeIndices();
+ }
+
//System.out.println( "FileSoup.updateObject: " + updatedObject + " -> " + result );
- return getObjectByKey( aKey );
- }
-
- protected DataKey getNextKey()
- {
+ return getObjectByKey(aKey);
+ }
+
+ protected DataKey getNextKey() {
DataKey id = (DataKey) nextUniqueIdentifier.clone();
- // while ( id isn't yet in use by the soup ) increment();
+ // while ( id isn't yet in use by the soup ) increment();
nextUniqueIdentifier.increment();
- writeFile( ID_ID.toString(), nextUniqueIdentifier );
- return id;
- }
-
- protected DataKey getNextTempKey()
- {
- return getNextKey();
- }
-
- /**
- * Gets object from data store whose identifier is equal
- * to the specified object.
- */
- public Object getObjectByKey( DataKey aKey )
- {
- return readFile( aKey.toString() );
- }
-
- // queries
-
+ writeFile(ID_ID.toString(), nextUniqueIdentifier);
+ return id;
+ }
+
+ protected DataKey getNextTempKey() {
+ return getNextKey();
+ }
+
/**
- * Returns an empty data view, suitable for creating
- * new entries in the soup.
- * @return A DataView containing no entries.
- */
- public DataView createView()
- {
- return new DefaultDataView( this, new LinkedList() );
+ * Gets object from data store whose identifier is equal to the specified
+ * object.
+ */
+ public Object getObjectByKey(DataKey aKey) {
+ return readFile(aKey.toString());
}
-
- /**
- * Queries by the specified pre-generated index, if it exists.
- * Otherwise, falls through to queryByProperty.
- */
- public DataView queryByIndex(
- String anIndexName, Object beginKey, Object endKey )
- {
- DataIndex index = (DataIndex) indices.get( anIndexName );
-
- if ( index == null )
- {
- return queryByProperty( anIndexName, beginKey, endKey );
- }
-
- return queryByKeys( index.query( beginKey, endKey ) );
- }
-
- /**
- * Generates an index based on the specified property
- * and then executes the query.
- */
- public DataView queryByProperty(
- String aPropertyName, Object beginKey, Object endKey )
- {
- if ( aPropertyName == null ) aPropertyName = IDENTITY_PROPERTY;
- DataIndex index = new DefaultDataIndex( "temporary", aPropertyName );
- buildIndex( index );
- return queryByKeys( index.query( beginKey, endKey ) );
- }
-
- /**
- * Generates an index based on the specified property
- * and then executes the query.
- */
- public DataView queryObjects( Object beginKey, Object endKey )
- {
- return queryByProperty( IDENTITY_PROPERTY, beginKey, endKey );
- }
-
- /**
- * Returns a view containing the objects for the specified keys.
- */
- public DataView queryByKeys( Collection aKeyList )
- {
- return new DefaultDataView( this, aKeyList );
- }
-
- /**
- * As queryByIndex, but with objects returned in reverse order.
- * @param anIndexName The index to be queried.
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryByIndex(
- String anIndexName, Object beginKey, Object endKey )
- {
- DataIndex index = (DataIndex) indices.get( anIndexName );
-
- if ( index == null )
- {
- return reverseQueryByProperty( anIndexName, beginKey, endKey );
- }
-
- List items = index.query( endKey, beginKey );
- Collections.reverse( items );
- return queryByKeys( items );
+
+ // queries
+
+ /**
+ * Returns an empty data view, suitable for creating new entries in the soup.
+ *
+ * @return A DataView containing no entries.
+ */
+ public DataView createView() {
+ return new DefaultDataView(this, new LinkedList());
}
-
- /**
- * As queryByProperty, but with objects returned in reverse order.
- * @param aPropertyName The property to be queried. If null,
- * will query the objects directly with queryObjects().
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryByProperty(
- String aPropertyName, Object beginKey, Object endKey )
- {
- if ( aPropertyName == null ) aPropertyName = IDENTITY_PROPERTY;
- DataIndex index = new DefaultDataIndex( "temporary", aPropertyName );
- buildIndex( index );
- List items = index.query( endKey, beginKey );
- Collections.reverse( items );
- return queryByKeys( items );
+
+ /**
+ * Queries by the specified pre-generated index, if it exists. Otherwise, falls
+ * through to queryByProperty.
+ */
+ public DataView queryByIndex(String anIndexName, Object beginKey, Object endKey) {
+ DataIndex index = (DataIndex) indices.get(anIndexName);
+
+ if (index == null) {
+ return queryByProperty(anIndexName, beginKey, endKey);
+ }
+
+ return queryByKeys(index.query(beginKey, endKey));
}
- /**
- * As queryObjects, but with objects returned in reverse order.
- * @param beginValue The beginning value, or null for all values
- * up to an including the end key.
- * @param endValue The ending value, or null for all values
- * since and including the begin key.
- * @return A DataView containing the query results, or null
- * for invalid query parameters.
- */
- public DataView reverseQueryObjects( Object beginKey, Object endKey )
- {
- return queryByProperty( IDENTITY_PROPERTY, beginKey, endKey );
- }
-
- public Object getValueFromObject( Object anObject, String aProperty )
- {
- if ( IDENTITY_PROPERTY.equals( aProperty ) ) return anObject;
- return Introspector.getValueForObject( anObject, aProperty );
+ /**
+ * Generates an index based on the specified property and then executes the
+ * query.
+ */
+ public DataView queryByProperty(String aPropertyName, Object beginKey, Object endKey) {
+ if (aPropertyName == null)
+ aPropertyName = IDENTITY_PROPERTY;
+ DataIndex index = new DefaultDataIndex("temporary", aPropertyName);
+ buildIndex(index);
+ return queryByKeys(index.query(beginKey, endKey));
}
-
- // file access methods
-
- abstract protected boolean writeFile( String name, Object anObject );
- abstract protected Object readFile( String name );
- abstract protected boolean deleteFile( String name );
+
+ /**
+ * Generates an index based on the specified property and then executes the
+ * query.
+ */
+ public DataView queryObjects(Object beginKey, Object endKey) {
+ return queryByProperty(IDENTITY_PROPERTY, beginKey, endKey);
+ }
+
+ /**
+ * Returns a view containing the objects for the specified keys.
+ */
+ public DataView queryByKeys(Collection aKeyList) {
+ return new DefaultDataView(this, aKeyList);
+ }
+
+ /**
+ * As queryByIndex, but with objects returned in reverse order.
+ *
+ * @param anIndexName The index to be queried.
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryByIndex(String anIndexName, Object beginKey, Object endKey) {
+ DataIndex index = (DataIndex) indices.get(anIndexName);
+
+ if (index == null) {
+ return reverseQueryByProperty(anIndexName, beginKey, endKey);
+ }
+
+ List items = index.query(endKey, beginKey);
+ Collections.reverse(items);
+ return queryByKeys(items);
+ }
+
+ /**
+ * As queryByProperty, but with objects returned in reverse order.
+ *
+ * @param aPropertyName The property to be queried. If null, will query the
+ * objects directly with queryObjects().
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryByProperty(String aPropertyName, Object beginKey, Object endKey) {
+ if (aPropertyName == null)
+ aPropertyName = IDENTITY_PROPERTY;
+ DataIndex index = new DefaultDataIndex("temporary", aPropertyName);
+ buildIndex(index);
+ List items = index.query(endKey, beginKey);
+ Collections.reverse(items);
+ return queryByKeys(items);
+ }
+
+ /**
+ * As queryObjects, but with objects returned in reverse order.
+ *
+ * @param beginValue The beginning value, or null for all values up to an
+ * including the end key.
+ * @param endValue The ending value, or null for all values since and
+ * including the begin key.
+ * @return A DataView containing the query results, or null for invalid query
+ * parameters.
+ */
+ public DataView reverseQueryObjects(Object beginKey, Object endKey) {
+ return queryByProperty(IDENTITY_PROPERTY, beginKey, endKey);
+ }
+
+ public Object getValueFromObject(Object anObject, String aProperty) {
+ if (IDENTITY_PROPERTY.equals(aProperty))
+ return anObject;
+ return Introspector.getValueForObject(anObject, aProperty);
+ }
+
+ // file access methods
+
+ abstract protected boolean writeFile(String name, Object anObject);
+
+ abstract protected Object readFile(String name);
+
+ abstract protected boolean deleteFile(String name);
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/14 19:29:38 chochos
- * minor cleanup (imports, static method calls, etc)
+ * Revision 1.4 2003/08/14 19:29:38 chochos minor cleanup (imports, static
+ * method calls, etc)
*
- * Revision 1.3 2001/03/05 22:12:11 mpowers
- * Created the control package for a datastore-specific implementation
- * of EOObjectStore.
+ * Revision 1.3 2001/03/05 22:12:11 mpowers Created the control package for a
+ * datastore-specific implementation of EOObjectStore.
*
- * Revision 1.2 2001/02/15 21:12:41 mpowers
- * Added accessors for key throughout the api. This breaks compatibility.
- * insertObject now returns the permanent key for the newly created object.
- * The old way returned a copy of the object which was an additional read
- * that was often ignored. Now you can read it only if you need it.
- * Furthermore, there was not other way of getting the permanent key.
+ * Revision 1.2 2001/02/15 21:12:41 mpowers Added accessors for key throughout
+ * the api. This breaks compatibility. insertObject now returns the permanent
+ * key for the newly created object. The old way returned a copy of the object
+ * which was an additional read that was often ignored. Now you can read it only
+ * if you need it. Furthermore, there was not other way of getting the permanent
+ * key.
*
- * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:36 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:36 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java
index e466c78..804608f 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java
@@ -25,96 +25,71 @@ import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-public class SerializedFileSoup extends FileSoup
-{
- public SerializedFileSoup( String aPath )
- {
- super( aPath );
- }
+public class SerializedFileSoup extends FileSoup {
+ public SerializedFileSoup(String aPath) {
+ super(aPath);
+ }
+
+ // file access methods
+
+ protected boolean writeFile(String name, Object anObject) {
+ try {
+ File f = new File(getHomeDirectory(), name);
+ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
+ oos.writeObject(anObject);
+ oos.flush();
+ oos.close();
+ return true;
+ } catch (Exception exc) {
+ System.err.println("SerializedFileSoup.writeFile: " + exc);
+ }
- // file access methods
-
- protected boolean writeFile( String name, Object anObject )
- {
- try
- {
- File f = new File( getHomeDirectory(), name );
- ObjectOutputStream oos = new ObjectOutputStream(
- new FileOutputStream( f ) );
- oos.writeObject( anObject );
- oos.flush();
- oos.close();
- return true;
- }
- catch ( Exception exc )
- {
- System.err.println( "SerializedFileSoup.writeFile: " + exc );
+ return false;
}
-
- return false;
- }
-
- protected Object readFile( String name )
- {
- Object result = null;
- try
- {
- File f = new File( getHomeDirectory(), name );
- ObjectInputStream ois = new ObjectInputStream(
- new FileInputStream( f ) );
- result = ois.readObject();
- ois.close();
- }
- catch ( FileNotFoundException exc )
- {
+ protected Object readFile(String name) {
+ Object result = null;
+
+ try {
+ File f = new File(getHomeDirectory(), name);
+ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
+ result = ois.readObject();
+ ois.close();
+ } catch (FileNotFoundException exc) {
result = null;
+ } catch (Exception exc) {
+ System.err.println("SerializedFileSoup.readFile: " + exc);
+ exc.printStackTrace();
}
- catch ( Exception exc )
- {
- System.err.println( "SerializedFileSoup.readFile: " + exc );
- exc.printStackTrace();
- }
- return result;
- }
-
- protected boolean deleteFile( String name )
- {
- try
- {
- File f = new File( getHomeDirectory(), name );
- if ( f.exists() )
- {
- f.delete();
+ return result;
+ }
+
+ protected boolean deleteFile(String name) {
+ try {
+ File f = new File(getHomeDirectory(), name);
+ if (f.exists()) {
+ f.delete();
return true;
- }
- }
- catch ( Exception exc )
- {
- System.err.println( "SerializedFileSoup.deleteFile: " + exc );
- }
+ }
+ } catch (Exception exc) {
+ System.err.println("SerializedFileSoup.deleteFile: " + exc);
+ }
+
+ return false;
+ }
- return false;
- }
-
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:37 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:37 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java
index 104932e..2257fac 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java
@@ -18,23 +18,19 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.datastore;
-public interface UniquelyIdentifiable
-{
- Object getUniqueIdentifier();
- void setUniqueIdentifier( Object id );
+public interface UniquelyIdentifiable {
+ Object getUniqueIdentifier();
+
+ void setUniqueIdentifier(Object id);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:37 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:37 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java
index 94d85fb..cb22f7a 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java
@@ -27,104 +27,80 @@ import java.net.MalformedURLException;
import net.wotonomy.web.xml.XMLRPCDecoder;
import net.wotonomy.web.xml.XMLRPCEncoder;
-public class XMLFileSoup extends FileSoup
-{
- public XMLFileSoup( String aPath )
- {
- super( aPath );
- }
+public class XMLFileSoup extends FileSoup {
+ public XMLFileSoup(String aPath) {
+ super(aPath);
+ }
- // file access methods
-
- protected boolean writeFile( String name, Object anObject )
- {
+ // file access methods
+
+ protected boolean writeFile(String name, Object anObject) {
//System.out.print( "writeFile: " + name + "..." );
- try
- {
- File f = new File( getHomeDirectory(), name );
- FileOutputStream fos = new FileOutputStream( f );
- XMLRPCEncoder encoder = new XMLRPCEncoder();
- encoder.encode( anObject, fos );
- fos.flush();
- fos.close();
- }
- catch ( Exception exc )
- {
- System.err.println( "XMLFileSoup.writeFile: " + exc );
- return false;
- }
+ try {
+ File f = new File(getHomeDirectory(), name);
+ FileOutputStream fos = new FileOutputStream(f);
+ XMLRPCEncoder encoder = new XMLRPCEncoder();
+ encoder.encode(anObject, fos);
+ fos.flush();
+ fos.close();
+ } catch (Exception exc) {
+ System.err.println("XMLFileSoup.writeFile: " + exc);
+ return false;
+ }
//System.out.println( "done." );
- return true;
- }
-
- protected Object readFile( String name )
- {
+ return true;
+ }
+
+ protected Object readFile(String name) {
//System.out.print( "readFile: " + name + "..." );
- Object result = null;
+ Object result = null;
- try
- {
- File f = new File( getHomeDirectory(), name );
- FileInputStream fis = new FileInputStream( f );
- XMLRPCDecoder decoder = new XMLRPCDecoder();
- result = decoder.decode( fis, f.getAbsolutePath(), f.toURL() );
- fis.close();
- }
- catch ( MalformedURLException exc )
- {
+ try {
+ File f = new File(getHomeDirectory(), name);
+ FileInputStream fis = new FileInputStream(f);
+ XMLRPCDecoder decoder = new XMLRPCDecoder();
+ result = decoder.decode(fis, f.getAbsolutePath(), f.toURL());
+ fis.close();
+ } catch (MalformedURLException exc) {
result = null;
- }
- catch ( IOException exc )
- {
+ } catch (IOException exc) {
result = null;
}
//System.out.println( "done." );
- return result;
- }
-
- protected boolean deleteFile( String name )
- {
- try
- {
- File f = new File( getHomeDirectory(), name );
- if ( f.exists() )
- {
- f.delete();
+ return result;
+ }
+
+ protected boolean deleteFile(String name) {
+ try {
+ File f = new File(getHomeDirectory(), name);
+ if (f.exists()) {
+ f.delete();
return true;
- }
- }
- catch ( Exception exc )
- {
- System.err.println( "XMLFileSoup.deleteFile: " + exc );
- }
+ }
+ } catch (Exception exc) {
+ System.err.println("XMLFileSoup.deleteFile: " + exc);
+ }
+
+ return false;
+ }
- return false;
- }
-
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 16:26:19 cgruber
- * Move non-unit-test code to tests project
- * Fix up code to work with proper imports
- * Fix maven dependencies.
+ * $Log$ Revision 1.2 2006/02/19 16:26:19 cgruber Move non-unit-test code to
+ * tests project Fix up code to work with proper imports Fix maven dependencies.
*
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/14 19:29:38 chochos
- * minor cleanup (imports, static method calls, etc)
+ * Revision 1.3 2003/08/14 19:29:38 chochos minor cleanup (imports, static
+ * method calls, etc)
*
- * Revision 1.2 2001/02/07 19:26:28 mpowers
- * XML classes are in new package.
+ * Revision 1.2 2001/02/07 19:26:28 mpowers XML classes are in new package.
*
- * Revision 1.1.1.1 2000/12/21 15:47:23 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:23 mpowers Contributing wotonomy.
*
- * Revision 1.6 2000/12/20 16:25:37 michael
- * Added log to all files.
+ * Revision 1.6 2000/12/20 16:25:37 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
index 491722c..e79c206 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
@@ -29,633 +29,639 @@ import java.util.List;
import java.util.ListIterator;
/**
-* NSArray is an unmodifiable List.
-* Calling the mutator methods of the List interface (add, addAll,
-* set, etc.) on an instance of NSArray will throw an Unsupported
-* Operation exception: use a NSMutableArray instead. This is to
-* simulate Objective-C's pattern of exposing mutator methods only
-* on mutable subinterface, which is wonderful for communicating
-* via interface the contract on returned collections (whether you
-* may modify return values) as well as implementing array faults.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 929 $
-*/
-public class NSArray implements List, Serializable
-{
- /**
- * Actual list that backs this instance.
- */
- List list;
-
- /**
- * Return value when array index is not found.
- */
- public static final int NotFound = -1;
+ * NSArray is an unmodifiable List. Calling the mutator methods of the List
+ * interface (add, addAll, set, etc.) on an instance of NSArray will throw an
+ * Unsupported Operation exception: use a NSMutableArray instead. This is to
+ * simulate Objective-C's pattern of exposing mutator methods only on mutable
+ * subinterface, which is wonderful for communicating via interface the contract
+ * on returned collections (whether you may modify return values) as well as
+ * implementing array faults.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 929 $
+ */
+public class NSArray implements List, Serializable {
+ /**
+ * Actual list that backs this instance.
+ */
+ List list;
/**
- * A constant representing an empty array.
- */
- public static final NSArray EmptyArray = new NSArray();
-
- /**
- * Returns an NSArray backed by the specified List.
- * This is useful to "protect" an internal representation
- * that is returned by a method of return type NSArray.
- */
- public static NSArray arrayBackedByList( List aList )
- {
- return new NSArray( aList, null );
- }
-
- /**
- * A constructor that uses the provided list as the backing
- * list object. This is unlike ArrayList and other
- * java.util.Collection types insofar as that API requires
- * that the provided Collection be copied into the newly constructed
- * Collection.
- *
- * TODO: See if this signature can be reasonably changed, as having a no-op parameter is a little counter-intuitive.
- * @param aList A list that the caller wishes to become the backing list for the NSArray.
- * @param ignored This parameter is entirely ignored, and is only there to distinguish the API.
- */
- NSArray( List aList, Object ignored ) // differentiates
- {
- list = aList;
- }
-
- /**
- * Constructor with a size hint, used by NSMutableArray.
- */
- NSArray( int aSize )
- {
- list = new ArrayList( aSize );
- }
-
- /**
- * Default constructor returns an empty array.
- */
- public NSArray ()
- {
- list = new ArrayList();
- }
+ * Return value when array index is not found.
+ */
+ public static final int NotFound = -1;
/**
- * Produces an array containing only the specified object.
- */
- public NSArray (Object anObject)
- {
- this();
- list.add( anObject );
- }
+ * A constant representing an empty array.
+ */
+ public static final NSArray EmptyArray = new NSArray();
/**
- * Produces an array containing the specified objects.
- */
- public NSArray (Object[] anArray)
- {
- this();
- for ( int i = 0; i < anArray.length; i++ )
- {
- list.add( anArray[i] );
- }
- }
+ * Returns an NSArray backed by the specified List. This is useful to "protect"
+ * an internal representation that is returned by a method of return type
+ * NSArray.
+ */
+ public static NSArray arrayBackedByList(List aList) {
+ return new NSArray(aList, null);
+ }
/**
- * Produces an array containing the objects in the specified collection.
- */
- public NSArray (Collection aCollection)
- {
- this();
- Iterator i = aCollection.iterator();
- while ( i.hasNext() ) list.add( i.next() );
- }
+ * A constructor that uses the provided list as the backing list object. This is
+ * unlike ArrayList and other java.util.Collection types insofar as that API
+ * requires that the provided Collection be copied into the newly constructed
+ * Collection.
+ *
+ * TODO: See if this signature can be reasonably changed, as having a no-op
+ * parameter is a little counter-intuitive.
+ *
+ * @param aList A list that the caller wishes to become the backing list for
+ * the NSArray.
+ * @param ignored This parameter is entirely ignored, and is only there to
+ * distinguish the API.
+ */
+ NSArray(List aList, Object ignored) // differentiates
+ {
+ list = aList;
+ }
/**
- * Returns the number of items in this array.
- */
- public int count ()
- {
- return list.size();
- }
+ * Constructor with a size hint, used by NSMutableArray.
+ */
+ NSArray(int aSize) {
+ list = new ArrayList(aSize);
+ }
/**
- * Returns an array containing all objects in this array
- * plus the specified object.
- */
- public NSArray arrayByAddingObject (Object anObject)
- {
- NSArray result = new NSArray( this );
- result.protectedAdd( anObject );
- return result;
- }
+ * Default constructor returns an empty array.
+ */
+ public NSArray() {
+ list = new ArrayList();
+ }
/**
- * Returns an array containing all objects in this array
- * plus all objects in the specified list.
- */
- public NSArray arrayByAddingObjectsFromArray (Collection aCollection)
- {
- NSArray result = new NSArray( this );
- result.protectedAddAll( aCollection );
- return result;
- }
+ * Produces an array containing only the specified object.
+ */
+ public NSArray(Object anObject) {
+ this();
+ list.add(anObject);
+ }
/**
- * Returns a string containing the string representations of
- * each element in this array, with each element separated from
- * each neighboring element by the specified string.
- */
- public String componentsJoinedByString (String separator)
- {
- StringBuffer buf = new StringBuffer();
- Iterator it = list.iterator();
- if ( it.hasNext() )
- {
- buf.append( it.next().toString() );
- }
- while ( it.hasNext() )
- {
- buf.append( separator );
- buf.append( String.valueOf(it.next()) );
- }
- return buf.toString();
- }
-
- /**
- * Returns whether an equivalent object is contained in this array.
- */
- public boolean containsObject (Object anObject)
- {
- return list.contains( anObject );
- }
+ * Produces an array containing the specified objects.
+ */
+ public NSArray(Object[] anArray) {
+ this();
+ for (int i = 0; i < anArray.length; i++) {
+ list.add(anArray[i]);
+ }
+ }
/**
- * Returns the first object in this array that is equivalent to
- * an object in the specified list, or null if no objects are
- * in common.
- */
- public Object firstObjectCommonWithArray (Collection aCollection)
- {
- if ( aCollection == null ) return null;
-
- Object o;
- Iterator it = list.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( aCollection.contains( o ) ) return o;
- }
- return null;
- }
-
- /**
- * Returns whether the specified list contains elements equivalent
- * to those in this array in the same order.
- */
- public boolean isEqualToArray (List aList)
- {
- return list.equals( aList );
- }
+ * Produces an array containing the objects in the specified collection.
+ */
+ public NSArray(Collection aCollection) {
+ this();
+ Iterator i = aCollection.iterator();
+ while (i.hasNext())
+ list.add(i.next());
+ }
/**
- * Returns the last object in this array, or null if the array is empty.
- */
- public Object lastObject ()
- {
- int i;
- if ( (i = list.size()) == 0 ) return null;
- return list.get( i - 1 );
- }
+ * Returns the number of items in this array.
+ */
+ public int count() {
+ return list.size();
+ }
+
+ /**
+ * Returns an array containing all objects in this array plus the specified
+ * object.
+ */
+ public NSArray arrayByAddingObject(Object anObject) {
+ NSArray result = new NSArray(this);
+ result.protectedAdd(anObject);
+ return result;
+ }
+
+ /**
+ * Returns an array containing all objects in this array plus all objects in the
+ * specified list.
+ */
+ public NSArray arrayByAddingObjectsFromArray(Collection aCollection) {
+ NSArray result = new NSArray(this);
+ result.protectedAddAll(aCollection);
+ return result;
+ }
+
+ /**
+ * Returns a string containing the string representations of each element in
+ * this array, with each element separated from each neighboring element by the
+ * specified string.
+ */
+ public String componentsJoinedByString(String separator) {
+ StringBuffer buf = new StringBuffer();
+ Iterator it = list.iterator();
+ if (it.hasNext()) {
+ buf.append(it.next().toString());
+ }
+ while (it.hasNext()) {
+ buf.append(separator);
+ buf.append(String.valueOf(it.next()));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns whether an equivalent object is contained in this array.
+ */
+ public boolean containsObject(Object anObject) {
+ return list.contains(anObject);
+ }
+
+ /**
+ * Returns the first object in this array that is equivalent to an object in the
+ * specified list, or null if no objects are in common.
+ */
+ public Object firstObjectCommonWithArray(Collection aCollection) {
+ if (aCollection == null)
+ return null;
+
+ Object o;
+ Iterator it = list.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if (aCollection.contains(o))
+ return o;
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the specified list contains elements equivalent to those in
+ * this array in the same order.
+ */
+ public boolean isEqualToArray(List aList) {
+ return list.equals(aList);
+ }
+
+ /**
+ * Returns the last object in this array, or null if the array is empty.
+ */
+ public Object lastObject() {
+ int i;
+ if ((i = list.size()) == 0)
+ return null;
+ return list.get(i - 1);
+ }
/**
*
*/
-/*
- public NSArray sortedArrayUsingSelector (NSSelector);
-*/
+ /*
+ * public NSArray sortedArrayUsingSelector (NSSelector);
+ */
/**
- * Returns an array comprised of only those elements whose
- * indices fall within the specified range.
- */
- public NSArray subarrayWithRange (NSRange aRange)
- {
- //TODO: Test this logic.
- NSArray result = new NSArray();
- if ( aRange == null ) return result;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- int count = count();
- for ( int i = loc; i <= max && i < count; i++ )
- {
- result.protectedAdd( list.get( i ) );
- }
- return result;
- }
-
- /**
- * Returns an enumeration over the the elements of the array.
- */
- public Enumeration objectEnumerator ()
- {
- //TODO: Test this logic.
- return new Enumeration()
- {
- Iterator it = NSArray.this.iterator();
- public boolean hasMoreElements()
- {
+ * Returns an array comprised of only those elements whose indices fall within
+ * the specified range.
+ */
+ public NSArray subarrayWithRange(NSRange aRange) {
+ // TODO: Test this logic.
+ NSArray result = new NSArray();
+ if (aRange == null)
+ return result;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ int count = count();
+ for (int i = loc; i <= max && i < count; i++) {
+ result.protectedAdd(list.get(i));
+ }
+ return result;
+ }
+
+ /**
+ * Returns an enumeration over the the elements of the array.
+ */
+ public Enumeration objectEnumerator() {
+ // TODO: Test this logic.
+ return new Enumeration() {
+ Iterator it = NSArray.this.iterator();
+
+ public boolean hasMoreElements() {
return it.hasNext();
- }
- public Object nextElement()
- {
- return it.next();
- }
- };
+ }
+
+ public Object nextElement() {
+ return it.next();
+ }
+ };
}
/**
- * Returns an enumeration over the elements of the array in reverse order.
- */
- public java.util.Enumeration reverseObjectEnumerator ()
- {
- return new java.util.Enumeration()
- {
- ListIterator it = null;
- public ListIterator getIterator()
- {
- if ( it == null )
- {
- it = NSArray.this.listIterator();
- // zoom to end
- while ( it.hasNext() ) it.next();
+ * Returns an enumeration over the elements of the array in reverse order.
+ */
+ public java.util.Enumeration reverseObjectEnumerator() {
+ return new java.util.Enumeration() {
+ ListIterator it = null;
+
+ public ListIterator getIterator() {
+ if (it == null) {
+ it = NSArray.this.listIterator();
+ // zoom to end
+ while (it.hasNext())
+ it.next();
}
return it;
- }
- public boolean hasMoreElements()
- {
+ }
+
+ public boolean hasMoreElements() {
return getIterator().hasPrevious();
- }
- public Object nextElement()
- {
- return getIterator().previous();
- }
- };
+ }
+
+ public Object nextElement() {
+ return getIterator().previous();
+ }
+ };
}
/**
- * Copies the elements of this array into the specified object array
- * as the array's capacity permits.
- */
- public void getObjects (Object[] anArray)
- {
- getObjects(anArray,null);
- }
-
- /**
- * Copies the elements of this array that fall within the specified range
- * into the specified object array as the array's capacity permits. This
- * method must not overflow, even in the face of a null range, an over or
- * under-sized array, or a bad range. It may underflow and fail to
- * entirely populate the array, if the array is larger than the data to
- * be copied.
- *
- * TODO: Check whether in WebObjects the range supposed to be measured against the parameter or the NSArray itself??? -ceg
- *
- * @param anArray An object array to be filled by this method.
- * @param range An NSRange object representing the range of data in the NSArray to be copied.
- */
- public void getObjects (Object[] array, NSRange range)
- {
- if ( array == null ) return;
- if ( range == null) range = new NSRange(0,array.length);
- int limit = Math.min(Math.min(array.length,range.length()),(count()-range.location()));
- for ( int i = 0; i < limit ; i++ ) {
- //anArray[ i-aRange.location() ] = objectAtIndex( i );
- array[ i ] = objectAtIndex( range.location() + i );
- }
- }
-
- /**
- * Returns the index of the first object in the array equivalent
- * to the specified object. Returns NotFound if the item is not found.
- */
- public int indexOfObject (Object anObject)
- {
- int result = list.indexOf( anObject );
- if ( result == -1 ) return NotFound; // in case this changes
- return result;
- }
+ * Copies the elements of this array into the specified object array as the
+ * array's capacity permits.
+ */
+ public void getObjects(Object[] anArray) {
+ getObjects(anArray, null);
+ }
/**
- * Returns the index of the first object in the array
- * within the specified range equivalent to the specified object.
- * Returns NotFound if the item is not found.
- */
- public int indexOfObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return NotFound;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( list.get(i) ) )
- {
- return i;
- }
- }
- return NotFound;
- }
-
- /**
- * Returns the index of the specified object if it exists
- * in the array, comparing by reference.
- * Returns NotFound if the item is not found.
- */
- public int indexOfIdenticalObject (Object anObject)
- {
- int size = list.size();
- for ( int i = 0; i < size; i++ )
- {
- if ( anObject == list.get(i) )
- {
- return i;
- }
- }
- return NotFound;
- }
-
- /**
- * Returns the index of the first object in the array
- * within the specified range equivalent to the specified object.
- */
- public int indexOfIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( aRange == null ) return NotFound;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == list.get(i) )
- {
- return i;
- }
- }
- return NotFound;
- }
-
- /**
- * Returns the object at the specified index. Throws an
- * IndexOutOfRange exception if the index is out of range.
- */
- public Object objectAtIndex (int anIndex)
- {
- return list.get( anIndex );
- }
+ * Copies the elements of this array that fall within the specified range into
+ * the specified object array as the array's capacity permits. This method must
+ * not overflow, even in the face of a null range, an over or under-sized array,
+ * or a bad range. It may underflow and fail to entirely populate the array, if
+ * the array is larger than the data to be copied.
+ *
+ * TODO: Check whether in WebObjects the range supposed to be measured against
+ * the parameter or the NSArray itself??? -ceg
+ *
+ * @param anArray An object array to be filled by this method.
+ * @param range An NSRange object representing the range of data in the
+ * NSArray to be copied.
+ */
+ public void getObjects(Object[] array, NSRange range) {
+ if (array == null)
+ return;
+ if (range == null)
+ range = new NSRange(0, array.length);
+ int limit = Math.min(Math.min(array.length, range.length()), (count() - range.location()));
+ for (int i = 0; i < limit; i++) {
+ // anArray[ i-aRange.location() ] = objectAtIndex( i );
+ array[i] = objectAtIndex(range.location() + i);
+ }
+ }
/**
- * Returns an array consisting of strings within the specified string
- * as delimited by the specified separator characters.
- */
- public static NSArray componentsSeparatedByString
- (String aString, String aSeparator)
- {
- NSArray result = new NSArray();
- if ( aString == null ) return result;
- if ( aSeparator == null ) return new NSArray( aString );
-
- //FIXME: The spec probably considers the whole
- // string as a separator, unlike string tokenizer.
- java.util.StringTokenizer tokens =
- new java.util.StringTokenizer( aString, aSeparator );
- while ( tokens.hasMoreTokens() )
- {
- result.protectedAdd( tokens.nextToken() );
- }
-
- return result;
- }
-
- public Object clone()
- {
- return new NSArray( list );
- }
-
- public NSArray immutableClone()
- {
- return this;
- }
-
- public NSMutableArray mutableClone()
- {
- return new NSMutableArray( this );
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer();
- buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]);
- for (int i = 0; i < count(); i++) {
- Object x = objectAtIndex(i);
- buf.append(NSPropertyListSerialization.stringForPropertyList(x));
- if (i < count() - 1)
- buf.append(", ");
- }
- buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]);
- return buf.toString();
- }
-
- // interface List: accessors
-
- public boolean contains(Object o) { return list.contains(o); }
- public boolean containsAll(Collection c) { return list.containsAll(c); }
- public boolean equals(Object o) { return list.equals(o); }
- public Object get(int index) { return list.get(index); }
- public int hashCode() {
- int code = 19;
- code *= getClass().hashCode();
- code *= list.hashCode();
- return code;
- }
- public int indexOf(Object o) { return list.indexOf(o); }
- public boolean isEmpty() { return list.isEmpty(); }
- public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
- public int size() { return list.size(); }
- public Object[] toArray() { return list.toArray(); }
- public Object[] toArray(Object[] a) { return list.toArray(a); }
-
- // interface List: mutators
-
-
- public void add(int index, Object element)
- {
- this.list.add(index,element);
- }
-
- public boolean add(Object o)
- {
+ * Returns the index of the first object in the array equivalent to the
+ * specified object. Returns NotFound if the item is not found.
+ */
+ public int indexOfObject(Object anObject) {
+ int result = list.indexOf(anObject);
+ if (result == -1)
+ return NotFound; // in case this changes
+ return result;
+ }
+
+ /**
+ * Returns the index of the first object in the array within the specified range
+ * equivalent to the specified object. Returns NotFound if the item is not
+ * found.
+ */
+ public int indexOfObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return NotFound;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(list.get(i))) {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the index of the specified object if it exists in the array,
+ * comparing by reference. Returns NotFound if the item is not found.
+ */
+ public int indexOfIdenticalObject(Object anObject) {
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ if (anObject == list.get(i)) {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the index of the first object in the array within the specified range
+ * equivalent to the specified object.
+ */
+ public int indexOfIdenticalObject(Object anObject, NSRange aRange) {
+ if (aRange == null)
+ return NotFound;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == list.get(i)) {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the object at the specified index. Throws an IndexOutOfRange
+ * exception if the index is out of range.
+ */
+ public Object objectAtIndex(int anIndex) {
+ return list.get(anIndex);
+ }
+
+ /**
+ * Returns an array consisting of strings within the specified string as
+ * delimited by the specified separator characters.
+ */
+ public static NSArray componentsSeparatedByString(String aString, String aSeparator) {
+ NSArray result = new NSArray();
+ if (aString == null)
+ return result;
+ if (aSeparator == null)
+ return new NSArray(aString);
+
+ // FIXME: The spec probably considers the whole
+ // string as a separator, unlike string tokenizer.
+ java.util.StringTokenizer tokens = new java.util.StringTokenizer(aString, aSeparator);
+ while (tokens.hasMoreTokens()) {
+ result.protectedAdd(tokens.nextToken());
+ }
+
+ return result;
+ }
+
+ public Object clone() {
+ return new NSArray(list);
+ }
+
+ public NSArray immutableClone() {
+ return this;
+ }
+
+ public NSMutableArray mutableClone() {
+ return new NSMutableArray(this);
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]);
+ for (int i = 0; i < count(); i++) {
+ Object x = objectAtIndex(i);
+ buf.append(NSPropertyListSerialization.stringForPropertyList(x));
+ if (i < count() - 1)
+ buf.append(", ");
+ }
+ buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]);
+ return buf.toString();
+ }
+
+ // interface List: accessors
+
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ public boolean containsAll(Collection c) {
+ return list.containsAll(c);
+ }
+
+ public boolean equals(Object o) {
+ return list.equals(o);
+ }
+
+ public Object get(int index) {
+ return list.get(index);
+ }
+
+ public int hashCode() {
+ int code = 19;
+ code *= getClass().hashCode();
+ code *= list.hashCode();
+ return code;
+ }
+
+ public int indexOf(Object o) {
+ return list.indexOf(o);
+ }
+
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ public int lastIndexOf(Object o) {
+ return list.lastIndexOf(o);
+ }
+
+ public int size() {
+ return list.size();
+ }
+
+ public Object[] toArray() {
+ return list.toArray();
+ }
+
+ public Object[] toArray(Object[] a) {
+ return list.toArray(a);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ this.list.add(index, element);
+ }
+
+ public boolean add(Object o) {
return this.list.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- return this.list.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- return this.list.addAll(index,c);
- }
-
- public void clear()
- {
+ }
+
+ public boolean addAll(Collection coll) {
+ return this.list.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ return this.list.addAll(index, c);
+ }
+
+ public void clear() {
this.list.clear();
- }
-
- public Iterator iterator()
- {
- // make a copy to avoid ConcurrentModificationExceptions
- final Iterator i = new LinkedList( list ).iterator();
- return new Iterator()
- {
- public boolean hasNext() {return i.hasNext();}
- public Object next() {return i.next();}
- public void remove() { throw new UnsupportedOperationException(); }
- };
- }
-
- public ListIterator listIterator() { return listIterator(0); }
-
- public ListIterator listIterator(final int index)
- {
- // make a copy to avoid ConcurrentModificationExceptions
- final ListIterator i = new LinkedList( list ).listIterator(index);
- return new ListIterator()
- {
- public boolean hasNext() {return i.hasNext();}
- public Object next() {return i.next();}
- public boolean hasPrevious() {return i.hasPrevious();}
- public Object previous() {return i.previous();}
- public int nextIndex() {return i.nextIndex();}
- public int previousIndex() {return i.previousIndex();}
- public void remove() { throw new UnsupportedOperationException(); }
- public void set(Object o) { throw new UnsupportedOperationException(); }
- public void add(Object o) { throw new UnsupportedOperationException(); }
- };
- }
-
- public Object remove(int index)
- {
+ }
+
+ public Iterator iterator() {
+ // make a copy to avoid ConcurrentModificationExceptions
+ final Iterator i = new LinkedList(list).iterator();
+ return new Iterator() {
+ public boolean hasNext() {
+ return i.hasNext();
+ }
+
+ public Object next() {
+ return i.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public ListIterator listIterator() {
+ return listIterator(0);
+ }
+
+ public ListIterator listIterator(final int index) {
+ // make a copy to avoid ConcurrentModificationExceptions
+ final ListIterator i = new LinkedList(list).listIterator(index);
+ return new ListIterator() {
+ public boolean hasNext() {
+ return i.hasNext();
+ }
+
+ public Object next() {
+ return i.next();
+ }
+
+ public boolean hasPrevious() {
+ return i.hasPrevious();
+ }
+
+ public Object previous() {
+ return i.previous();
+ }
+
+ public int nextIndex() {
+ return i.nextIndex();
+ }
+
+ public int previousIndex() {
+ return i.previousIndex();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public Object remove(int index) {
return this.list.remove(index);
- }
-
- public boolean remove(Object o)
- {
+ }
+
+ public boolean remove(Object o) {
return this.list.remove(o);
- }
+ }
- public boolean removeAll(Collection coll)
- {
+ public boolean removeAll(Collection coll) {
return this.list.removeAll(coll);
- }
+ }
- public boolean retainAll(Collection coll)
- {
+ public boolean retainAll(Collection coll) {
return this.list.retainAll(coll);
- }
-
- public Object set(int index, Object element)
- {
- return this.list.set(index,element);
- }
-
- public List subList(int fromIndex, int toIndex)
- {
- return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
- }
-
- /**
- * Provided for the use of subclasses like ArrayFault.
- */
- protected boolean protectedAdd( Object o )
- {
- return list.add( o );
- }
-
- /**
- * Provided for the use of subclasses like ArrayFault.
- */
- protected boolean protectedAddAll( Collection coll )
- {
- return list.addAll( coll );
- }
+ }
+
+ public Object set(int index, Object element) {
+ return this.list.set(index, element);
+ }
+
+ public List subList(int fromIndex, int toIndex) {
+ return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
+ }
+
+ /**
+ * Provided for the use of subclasses like ArrayFault.
+ */
+ protected boolean protectedAdd(Object o) {
+ return list.add(o);
+ }
+
+ /**
+ * Provided for the use of subclasses like ArrayFault.
+ */
+ protected boolean protectedAddAll(Collection coll) {
+ return list.addAll(coll);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/03/10 00:52:27 cgruber
- * Add tests for NSArray and fix some problems that became obvious as a result.
+ * $Log$ Revision 1.2 2006/03/10 00:52:27 cgruber Add tests for NSArray and fix
+ * some problems that became obvious as a result.
*
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.16 2005/07/13 14:12:44 cgruber
- * Add mutableClone() and immutableClone() per. WebObjects 5.3 conformance.
+ * Revision 1.16 2005/07/13 14:12:44 cgruber Add mutableClone() and
+ * immutableClone() per. WebObjects 5.3 conformance.
*
- * Revision 1.15 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.15 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.14 2003/08/05 00:48:56 chochos
- * use NSPropertyListSerialization to get the opening and closing tokens for the string representation
+ * Revision 1.14 2003/08/05 00:48:56 chochos use NSPropertyListSerialization to
+ * get the opening and closing tokens for the string representation
*
- * Revision 1.13 2003/08/04 20:26:10 chochos
- * use NSPropertyListSerialization inside toString()
+ * Revision 1.13 2003/08/04 20:26:10 chochos use NSPropertyListSerialization
+ * inside toString()
*
- * Revision 1.12 2003/08/04 18:18:43 chochos
- * toString() yields strings in the same format as Apple's NSArray
+ * Revision 1.12 2003/08/04 18:18:43 chochos toString() yields strings in the
+ * same format as Apple's NSArray
*
- * Revision 1.11 2003/01/28 19:44:20 mpowers
- * Fixed reverse enumerator.
+ * Revision 1.11 2003/01/28 19:44:20 mpowers Fixed reverse enumerator.
*
- * Revision 1.10 2003/01/18 23:49:55 mpowers
- * Added mutableClone().
+ * Revision 1.10 2003/01/18 23:49:55 mpowers Added mutableClone().
*
- * Revision 1.9 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.9 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.8 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.8 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.7 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.7 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.6 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.6 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.5 2002/10/24 18:16:30 mpowers
- * Now enforcing NSArray's immutable nature.
+ * Revision 1.5 2002/10/24 18:16:30 mpowers Now enforcing NSArray's immutable
+ * nature.
*
- * Revision 1.4 2002/03/08 19:02:54 mpowers
- * Long-overdue speed optimization of indexOfIdenticalObject.
+ * Revision 1.4 2002/03/08 19:02:54 mpowers Long-overdue speed optimization of
+ * indexOfIdenticalObject.
*
- * Revision 1.3 2002/02/13 22:02:56 mpowers
- * Fixed: bug in componentsSeparatedByString when separator is null
- * (thanks to Cedrik LIME).
+ * Revision 1.3 2002/02/13 22:02:56 mpowers Fixed: bug in
+ * componentsSeparatedByString when separator is null (thanks to Cedrik LIME).
*
- * Revision 1.2 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.2 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:37 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:37 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java
index b735404..49dda88 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java
@@ -67,7 +67,7 @@ public class NSBundle {
private static NSMutableDictionary _languageCodes = new NSMutableDictionary();
private static NSBundle _mainBundle = null;
-
+
protected static NetworkClassLoader _classLoader = new NetworkClassLoader(ClassLoader.getSystemClassLoader());
/* Instance variables */
@@ -94,8 +94,8 @@ public class NSBundle {
/**
* The default constructor, which is only public to support other framework
- * functionality, and to be API compatible with Apple's WebObjects.
- * Generally, framework users should use bundleForXXXX() methods.
+ * functionality, and to be API compatible with Apple's WebObjects. Generally,
+ * framework users should use bundleForXXXX() methods.
*/
public NSBundle() {
}
@@ -118,11 +118,10 @@ public class NSBundle {
}
/**
- * Returns the bundle that contains the provided class, if any. Otherwise,
- * it returns null. Because NSBundles have a specialized class-loader, if
- * any two bundles contain duiplicates of the same class, the second will
- * fail to load. TODO: Determine if class-load scoping of duplicate classes
- * is appropriate.
+ * Returns the bundle that contains the provided class, if any. Otherwise, it
+ * returns null. Because NSBundles have a specialized class-loader, if any two
+ * bundles contain duiplicates of the same class, the second will fail to load.
+ * TODO: Determine if class-load scoping of duplicate classes is appropriate.
*
* @param class1
* @return NSBundle
@@ -133,8 +132,7 @@ public class NSBundle {
}
/**
- * @deprecated Apple's WebObjects says you should not load from arbitrary
- * path.
+ * @deprecated Apple's WebObjects says you should not load from arbitrary path.
* @param path
* @return
*/
@@ -150,9 +148,9 @@ public class NSBundle {
/**
* <strong>Note:</strong>This method is only in Wotonomy.
*
- * This method returns a bundle at a given URL, registering that bundle as
- * well. If the bundle has already been loaded/registered, it is simply
- * returned from the cache.
+ * This method returns a bundle at a given URL, registering that bundle as well.
+ * If the bundle has already been loaded/registered, it is simply returned from
+ * the cache.
*
* @param url
* @return
@@ -170,14 +168,11 @@ public class NSBundle {
StringBuffer filename = new StringBuffer(f.getName());
int extensionIndex = filename.lastIndexOf(".");
if (extensionIndex == -1) {
- NSLog.err
- .appendln("Named URL does not point to a bundle with an extension: "
- + url);
+ NSLog.err.appendln("Named URL does not point to a bundle with an extension: " + url);
return null;
}
String basename = filename.substring(0, extensionIndex);
- String extension = filename.substring(extensionIndex + 1, filename
- .length());
+ String extension = filename.substring(extensionIndex + 1, filename.length());
System.out.println("basename: " + basename);
System.out.println("extension: " + extension);
result = new NSBundle();
@@ -185,16 +180,15 @@ public class NSBundle {
result.isFramework = extension.equals("framework");
if (f.isDirectory()) {
try {
- File javadir = new File(f.getCanonicalPath() + sep + "Contents"
- + sep + "Resources" + sep + "Java");
+ File javadir = new File(f.getCanonicalPath() + sep + "Contents" + sep + "Resources" + sep + "Java");
System.out.println(javadir);
System.out.println(javadir.exists());
File[] jars = javadir.listFiles();
-
- } catch (IOException e) { }
+
+ } catch (IOException e) {
+ }
} else {
- throw new RuntimeException(
- "Compressed bundle files not currently supported.");
+ throw new RuntimeException("Compressed bundle files not currently supported.");
}
throw new RuntimeException("Method not finished.");
} else {
@@ -205,10 +199,8 @@ public class NSBundle {
JarFile f;
throw new RuntimeException("Method not finished.");
} catch (IOException e) {
- NSLog.err
- .appendln("IOException loading framework jar from URL "
- + url + " - message: "
- + e.getLocalizedMessage());
+ NSLog.err.appendln(
+ "IOException loading framework jar from URL " + url + " - message: " + e.getLocalizedMessage());
StringWriter stacktrace = new StringWriter();
e.printStackTrace(new PrintWriter(stacktrace));
NSLog.err.appendln(stacktrace);
@@ -218,10 +210,9 @@ public class NSBundle {
}
/**
- * This method returns a bundle, either from cache, or if it doesn't exist
- * yet, it attempts to look it up - first from the classpath, then from the
- * resource path. TODO: Determine if the lookup order is the desired
- * semantic.
+ * This method returns a bundle, either from cache, or if it doesn't exist yet,
+ * it attempts to look it up - first from the classpath, then from the resource
+ * path. TODO: Determine if the lookup order is the desired semantic.
*
* @param name
* @return
@@ -237,9 +228,9 @@ public class NSBundle {
/**
* Used to set the "Main" application bundle, in which primary resources are
- * loaded for GUI applications. This is mostly only relevant for
- * XXApplication objects. This should therefore not be generally used by
- * consumers of the framework.
+ * loaded for GUI applications. This is mostly only relevant for XXApplication
+ * objects. This should therefore not be generally used by consumers of the
+ * framework.
*
* @param aBundle
*/
@@ -252,14 +243,13 @@ public class NSBundle {
}
/**
- * Get the default prefix for locale. TODO: This really needs to be made
- * dynamic somehow.
+ * Get the default prefix for locale. TODO: This really needs to be made dynamic
+ * somehow.
*
* @return
*/
protected static String defaultLocalePrefix() {
- String language = (String) _languageCodes.objectForKey(Locale
- .getDefault().getLanguage());
+ String language = (String) _languageCodes.objectForKey(Locale.getDefault().getLanguage());
return language + ".lproj";
}
@@ -283,8 +273,8 @@ public class NSBundle {
}
/**
- * Returns a byte array for the given resource path. TODO: Lookup semantics
- * in WebObjects javadocs.
+ * Returns a byte array for the given resource path. TODO: Lookup semantics in
+ * WebObjects javadocs.
*
* @param path
* @return
@@ -303,8 +293,8 @@ public class NSBundle {
}
/**
- * Returns an input stream for a given resource path. TODO: Lookup semantics
- * in WebObjects javadocs.
+ * Returns an input stream for a given resource path. TODO: Lookup semantics in
+ * WebObjects javadocs.
*
* @param path
* @return
@@ -339,14 +329,12 @@ public class NSBundle {
* @deprecated Don't use this method, use
* resourcePathForLocalizedResourceNamed() instead.
*/
- public String pathForResource(String aName, String anExtension,
- String subDir) {
+ public String pathForResource(String aName, String anExtension, String subDir) {
return this.resourcePathForLocalizedResourceNamed(aName, subDir);
}
/**
- * @deprecated Don't use this method, use resourcePathsForResources()
- * instead.
+ * @deprecated Don't use this method, use resourcePathsForResources() instead.
*/
public NSArray pathsForResources(String aName, String anExtension) {
throw new UnsupportedOperationException("Method not yet implemented.");
@@ -362,27 +350,24 @@ public class NSBundle {
}
/**
- * @deprecated Resources are now accessed using the bytesForResourcePath()
- * and inputStreamForResourcePath() methods.
+ * @deprecated Resources are now accessed using the bytesForResourcePath() and
+ * inputStreamForResourcePath() methods.
*/
public String resourcePath() {
throw new UnsupportedOperationException("Method not yet implemented.");
// TODO: Implement.
}
- public String resourcePathForLocalizedResourceNamed(String aName,
- String subDir) {
+ public String resourcePathForLocalizedResourceNamed(String aName, String subDir) {
throw new UnsupportedOperationException("Method not yet implemented.");
// TODO: Implement.
}
- public NSArray resourcePathsForDirectories(String extension,
- String subdirPath) {
+ public NSArray resourcePathsForDirectories(String extension, String subdirPath) {
throw new UnsupportedOperationException("Method not yet implemented.");
}
- public NSArray resourcePathsForLocalizedResources(String extension,
- String subdirPath) {
+ public NSArray resourcePathsForLocalizedResources(String extension, String subdirPath) {
throw new UnsupportedOperationException("Method not yet implemented.");
}
@@ -395,8 +380,8 @@ public class NSBundle {
int i = 0;
if (classNames != null)
i = classNames.count();
- return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'"
- + path + "' packages:'" + packages + "' " + i + " classes >";
+ return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'" + path + "' packages:'" + packages
+ + "' " + i + " classes >";
}
/* Static initialization code */
@@ -412,7 +397,7 @@ public class NSBundle {
static {
NSBundle._initLanguages();
-
+
}
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java
index ca32dd5..8a1721a 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java
@@ -25,89 +25,87 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
-* A class that defines a simple encode/decode paradigm. Subclasses
-* would handle the target format.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A class that defines a simple encode/decode paradigm. Subclasses would handle
+ * the target format.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public abstract class NSCoder {
- public NSCoder() {
- }
+ public NSCoder() {
+ }
- public abstract void encodeBoolean(boolean flag);
+ public abstract void encodeBoolean(boolean flag);
- public abstract void encodeByte(byte byte0);
+ public abstract void encodeByte(byte byte0);
- public abstract void encodeBytes(byte abyte0[]);
+ public abstract void encodeBytes(byte abyte0[]);
- public abstract void encodeChar(char c);
+ public abstract void encodeChar(char c);
- public abstract void encodeShort(short word0);
+ public abstract void encodeShort(short word0);
- public abstract void encodeInt(int i);
+ public abstract void encodeInt(int i);
- public abstract void encodeLong(long l);
+ public abstract void encodeLong(long l);
- public abstract void encodeFloat(float f);
+ public abstract void encodeFloat(float f);
- public abstract void encodeDouble(double d);
+ public abstract void encodeDouble(double d);
- public abstract void encodeObject(Object obj);
+ public abstract void encodeObject(Object obj);
- public abstract void encodeClass(Class class1);
+ public abstract void encodeClass(Class class1);
- public abstract void encodeObjects(Object aobj[]);
+ public abstract void encodeObjects(Object aobj[]);
- public abstract boolean decodeBoolean();
+ public abstract boolean decodeBoolean();
- public abstract byte decodeByte();
+ public abstract byte decodeByte();
- public abstract byte[] decodeBytes();
+ public abstract byte[] decodeBytes();
- public abstract char decodeChar();
+ public abstract char decodeChar();
- public abstract short decodeShort();
+ public abstract short decodeShort();
- public abstract int decodeInt();
+ public abstract int decodeInt();
- public abstract long decodeLong();
+ public abstract long decodeLong();
- public abstract float decodeFloat();
+ public abstract float decodeFloat();
- public abstract double decodeDouble();
+ public abstract double decodeDouble();
- public abstract Object decodeObject();
+ public abstract Object decodeObject();
- public abstract Class decodeClass();
+ public abstract Class decodeClass();
- public abstract Object[] decodeObjects();
+ public abstract Object[] decodeObjects();
- public void prepareForWriting(OutputStream outputstream) {
- }
+ public void prepareForWriting(OutputStream outputstream) {
+ }
- public void prepareForReading(InputStream inputstream) {
- }
+ public void prepareForReading(InputStream inputstream) {
+ }
- public void finishCoding() {
- }
+ public void finishCoding() {
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.2 2002/06/25 19:03:02 cgruber
- * Internal documentation fixes.
+ * Revision 1.2 2002/06/25 19:03:02 cgruber Internal documentation fixes.
*
- * Revision 1.1 2002/06/25 07:52:57 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java
index 56e4124..c578dbc 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java
@@ -24,15 +24,14 @@ package net.wotonomy.foundation;
import java.math.BigInteger;
/**
-* A helper interface supporting the NSCoder APIs. At present it
-* very confusing to me how this even works from a structural
-* perspective, but to be consistent with WebObjects APIs, this will
-* have to be properly implemented.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
+ * A helper interface supporting the NSCoder APIs. At present it very confusing
+ * to me how this even works from a structural perspective, but to be consistent
+ * with WebObjects APIs, this will have to be properly implemented.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
public interface NSCoding {
@@ -69,9 +68,7 @@ public interface NSCoding {
}
/** Not yet implemented */
- protected static void _encodeBigInteger(
- NSCoder nscoder,
- BigInteger biginteger) {
+ protected static void _encodeBigInteger(NSCoder nscoder, BigInteger biginteger) {
throw new UnsupportedOperationException("Not Yet Implemented");
}
@@ -273,8 +270,7 @@ public interface NSCoding {
/** Helper class for NSCoding. */
public static abstract class Support {
- private static NSMutableDictionary classSupportMap =
- new NSMutableDictionary(16);
+ private static NSMutableDictionary classSupportMap = new NSMutableDictionary(16);
public static Support supportForClass(Class aClass) {
Support support = null;
@@ -294,9 +290,9 @@ public interface NSCoding {
classSupportMap.setObjectForKey(support, class1);
}
- /** Return the class of a given object. It boggles the mind
- * as to why this is not a static, but in the original, it's
- * not. &lt;sigh&gt;
+ /**
+ * Return the class of a given object. It boggles the mind as to why this is not
+ * a static, but in the original, it's not. &lt;sigh&gt;
*/
public Class classForCoder(Object obj) {
return obj.getClass();
@@ -324,48 +320,40 @@ public interface NSCoding {
setSupportForClass(new _LongSupport(), java.lang.Long.class);
setSupportForClass(new _FloatSupport(), java.lang.Float.class);
setSupportForClass(new _DoubleSupport(), java.lang.Double.class);
- setSupportForClass(
- new _BigIntegerSupport(),
- java.math.BigInteger.class);
- setSupportForClass(
- new _BigDecimalSupport(),
- java.math.BigDecimal.class);
+ setSupportForClass(new _BigIntegerSupport(), java.math.BigInteger.class);
+ setSupportForClass(new _BigDecimalSupport(), java.math.BigDecimal.class);
setSupportForClass(new _DateSupport(), java.util.Date.class);
- setSupportForClass(
- new _CharacterSupport(),
- java.lang.Character.class);
+ setSupportForClass(new _CharacterSupport(), java.lang.Character.class);
}
public Support() {
}
}
- //CEG: I'm not sure why these are here, since NSCoding is an interface.
- // It doesn't seem to even be used anywhere.
- //CEG: I'm not even sure why this compiles!!
- //public abstract Class classForCoder();
+ // CEG: I'm not sure why these are here, since NSCoding is an interface.
+ // It doesn't seem to even be used anywhere.
+ // CEG: I'm not even sure why this compiles!!
+ // public abstract Class classForCoder();
- //CEG: I'm not sure why these are here, since NSCoding is an interface.
- // It doesn't seem to even be used anywhere.
- //CEG: I'm not even sure why this compiles!!
- //public abstract void encodeWithCoder(NSCoder nscoder);
+ // CEG: I'm not sure why these are here, since NSCoding is an interface.
+ // It doesn't seem to even be used anywhere.
+ // CEG: I'm not even sure why this compiles!!
+ // public abstract void encodeWithCoder(NSCoder nscoder);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.2 2002/06/25 19:03:02 cgruber
- * Internal documentation fixes.
+ * Revision 1.2 2002/06/25 19:03:02 cgruber Internal documentation fixes.
*
- * Revision 1.1 2002/06/25 07:52:56 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java
index 287a59b..6c88d19 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java
@@ -23,82 +23,79 @@ package net.wotonomy.foundation;
import java.util.Comparator;
-
/**
-* An object that compares two other objects. As a convenience, it
-* also implements java.util.Comparator.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 913 $
-*/
+ * An object that compares two other objects. As a convenience, it also
+ * implements java.util.Comparator.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 913 $
+ */
public abstract class NSComparator implements Comparator {
- protected static class _NSSelectorComparator extends NSComparator {
+ protected static class _NSSelectorComparator extends NSComparator {
- public int compare(Object obj, Object obj1) throws ComparisonException {
+ public int compare(Object obj, Object obj1) throws ComparisonException {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public _NSSelectorComparator(NSSelector nsselector) {
+ public _NSSelectorComparator(NSSelector nsselector) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
- }
-
- private static class StandInComparator extends NSComparator {
+ }
+ }
- public StandInComparator() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ private static class StandInComparator extends NSComparator {
- public int compare(Object obj, Object obj1) throws ComparisonException {
+ public StandInComparator() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- }
+ public int compare(Object obj, Object obj1) throws ComparisonException {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public static class ComparisonException extends ClassCastException {
+ }
- public ComparisonException(String s) {
- super(s);
- }
- }
+ public static class ComparisonException extends ClassCastException {
+ public ComparisonException(String s) {
+ super(s);
+ }
+ }
- public static final NSComparator AscendingStringComparator = new StandInComparator();
- public static final NSComparator DescendingStringComparator = new StandInComparator();
- public static final NSComparator AscendingCaseInsensitiveStringComparator = new StandInComparator();
- public static final NSComparator DescendingCaseInsensitiveStringComparator = new StandInComparator();
- public static final NSComparator AscendingNumberComparator = new StandInComparator();
- public static final NSComparator DescendingNumberComparator = new StandInComparator();
- public static final NSComparator AscendingTimestampComparator = new StandInComparator();
- public static final NSComparator DescendingTimestampComparator = new StandInComparator();
- public static final int OrderedAscending = -1;
- public static final int OrderedSame = 0;
- public static final int OrderedDescending = 1;
+ public static final NSComparator AscendingStringComparator = new StandInComparator();
+ public static final NSComparator DescendingStringComparator = new StandInComparator();
+ public static final NSComparator AscendingCaseInsensitiveStringComparator = new StandInComparator();
+ public static final NSComparator DescendingCaseInsensitiveStringComparator = new StandInComparator();
+ public static final NSComparator AscendingNumberComparator = new StandInComparator();
+ public static final NSComparator DescendingNumberComparator = new StandInComparator();
+ public static final NSComparator AscendingTimestampComparator = new StandInComparator();
+ public static final NSComparator DescendingTimestampComparator = new StandInComparator();
+ public static final int OrderedAscending = -1;
+ public static final int OrderedSame = 0;
+ public static final int OrderedDescending = 1;
- public NSComparator() {
- }
+ public NSComparator() {
+ }
- public abstract int compare(Object obj, Object obj1) throws ClassCastException;
+ public abstract int compare(Object obj, Object obj1) throws ClassCastException;
- public static int _compareObjects(Comparable comparable, Comparable comparable1) {
+ public static int _compareObjects(Comparable comparable, Comparable comparable1) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/03/10 00:52:27 cgruber
- * Add tests for NSArray and fix some problems that became obvious as a result.
+ * $Log$ Revision 1.2 2006/03/10 00:52:27 cgruber Add tests for NSArray and fix
+ * some problems that became obvious as a result.
*
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.1 2002/06/25 07:52:56 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
index 36c527c..67f1d59 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
@@ -24,96 +24,85 @@ import java.io.IOException;
import java.io.InputStream;
/**
-* A pure java implementation of NSData, which
-* is basically a wrapper on a byte array.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSData
-{
- public static final NSData EmptyData = new NSData();
+ * A pure java implementation of NSData, which is basically a wrapper on a byte
+ * array.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSData {
+ public static final NSData EmptyData = new NSData();
- protected byte[] bytes;
+ protected byte[] bytes;
- /**
- * Default constructor creates a zero-data object.
- */
- public NSData ()
- {
- bytes = new byte[0];
- }
+ /**
+ * Default constructor creates a zero-data object.
+ */
+ public NSData() {
+ bytes = new byte[0];
+ }
- /**
- * Creates an object containing a copy of the specified bytes.
- */
- public NSData (byte[] data)
- {
- this( data, 0, data.length );
- }
+ /**
+ * Creates an object containing a copy of the specified bytes.
+ */
+ public NSData(byte[] data) {
+ this(data, 0, data.length);
+ }
- /**
- * Creates an object containing a copy of the bytes from the specified
- * array within the specified range.
- */
- public NSData (byte[] data, int start, int length)
- {
- bytes = new byte[ length ];
- for ( int i = 0; i < length; i++ )
- {
- bytes[i] = data[ start+i ];
- }
- }
+ /**
+ * Creates an object containing a copy of the bytes from the specified array
+ * within the specified range.
+ */
+ public NSData(byte[] data, int start, int length) {
+ bytes = new byte[length];
+ for (int i = 0; i < length; i++) {
+ bytes[i] = data[start + i];
+ }
+ }
- /**
- * Creates an object containing the bytes of the specified string.
- */
- public NSData (String aString)
- {
- this( aString.getBytes() );
- }
+ /**
+ * Creates an object containing the bytes of the specified string.
+ */
+ public NSData(String aString) {
+ this(aString.getBytes());
+ }
- /**
- * Creates an object containing the contents of the specified file.
- * Errors reading the file will produce an empty or partially blank array.
- */
- public NSData (File aFile)
- {
- int len = (int) aFile.length();
- byte[] data = new byte[ len ];
- try
- {
- new java.io.FileInputStream( aFile ).read( data );
- }
- catch ( Exception exc )
- {
- // produce an empty or partially blank array
- }
+ /**
+ * Creates an object containing the contents of the specified file. Errors
+ * reading the file will produce an empty or partially blank array.
+ */
+ public NSData(File aFile) {
+ int len = (int) aFile.length();
+ byte[] data = new byte[len];
+ try {
+ new java.io.FileInputStream(aFile).read(data);
+ } catch (Exception exc) {
+ // produce an empty or partially blank array
+ }
bytes = data;
- }
+ }
- /**
- * Creates an object containing the contents of the specified URL.
- */
- public NSData (java.net.URL aURL)
- {
- throw new RuntimeException( "Not Implemented" );
- }
+ /**
+ * Creates an object containing the contents of the specified URL.
+ */
+ public NSData(java.net.URL aURL) {
+ throw new RuntimeException("Not Implemented");
+ }
- /**
- * Creates an object containing a copy of the contents of the
- * specified NSData object.
- */
- public NSData (NSData aData)
- {
- this( aData.bytes() );
- }
+ /**
+ * Creates an object containing a copy of the contents of the specified NSData
+ * object.
+ */
+ public NSData(NSData aData) {
+ this(aData.bytes());
+ }
/**
- * Creates a new NSData object from the bytes in the input stream.
- * The input stream is read fully and is not closed.
- * @param stream The stream to read from.
+ * Creates a new NSData object from the bytes in the input stream. The input
+ * stream is read fully and is not closed.
+ *
+ * @param stream The stream to read from.
* @param chunkSize The buffer size used to read from the stream.
* @throws IOException if the stream cannot be read from.
*/
@@ -130,134 +119,119 @@ public class NSData
bytes = bout.toByteArray();
}
- /**
- * Returns the length of the contained data.
- */
- public int length ()
- {
- return bytes.length;
- }
+ /**
+ * Returns the length of the contained data.
+ */
+ public int length() {
+ return bytes.length;
+ }
- /**
- * Returns whether the specified data is equivalent to these data.
- */
- public boolean isEqualToData (NSData aData)
- {
- if (length() != aData.length())
- return false;
- byte[] a = bytes();
- byte[] b = aData.bytes();
-
- for ( int i = 0; i < a.length; i++ ) {
- if ( a[i] != b[i] )
+ /**
+ * Returns whether the specified data is equivalent to these data.
+ */
+ public boolean isEqualToData(NSData aData) {
+ if (length() != aData.length())
+ return false;
+ byte[] a = bytes();
+ byte[] b = aData.bytes();
+
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i])
return false;
}
return true;
- }
+ }
- /**
- * Return the bytes within the data that fall within the specified range.
- */
- public NSData subdataWithRange (NSRange aRange)
- {
- int loc = aRange.location();
- byte[] src = bytes();
- byte[] data = new byte[ aRange.length() ];
- System.arraycopy(src, loc, data, 0, data.length);
- return new NSData( data );
- }
+ /**
+ * Return the bytes within the data that fall within the specified range.
+ */
+ public NSData subdataWithRange(NSRange aRange) {
+ int loc = aRange.location();
+ byte[] src = bytes();
+ byte[] data = new byte[aRange.length()];
+ System.arraycopy(src, loc, data, 0, data.length);
+ return new NSData(data);
+ }
+
+ /**
+ * Writes the contents of this data to the specified URL. If atomically is true,
+ * then the data is written to a temporary file and then renamed to the name
+ * specified by the URL when the data transfer is complete.
+ */
+ public boolean writeToURL(java.net.URL aURL, boolean atomically) {
+ throw new RuntimeException("Not Implemented");
+ }
- /**
- * Writes the contents of this data to the specified URL.
- * If atomically is true, then the data is written to a temporary
- * file and then renamed to the name specified by the URL when
- * the data transfer is complete.
- */
- public boolean writeToURL (java.net.URL aURL, boolean atomically)
- {
- throw new RuntimeException( "Not Implemented" );
- }
+ /**
+ * Convenience to return the contents of the specified file.
+ */
+ public static NSData dataWithContentsOfMappedFile(java.io.File aFile) {
+ return new NSData(aFile);
+ }
- /**
- * Convenience to return the contents of the specified file.
- */
- public static NSData dataWithContentsOfMappedFile (java.io.File aFile)
- {
- return new NSData( aFile );
- }
+ /**
+ * Returns a copy of the bytes starting at the specified location and ranging
+ * for the specified length.
+ */
+ public byte[] bytes(int location, int length) {
+ byte[] data = new byte[length];
+ for (int i = 0; i < length; i++) {
+ data[i] = bytes[location + i];
+ }
+ return data;
+ }
- /**
- * Returns a copy of the bytes starting at the specified location
- * and ranging for the specified length.
- */
- public byte[] bytes (int location, int length)
- {
- byte[] data = new byte[ length ];
- for ( int i = 0; i < length; i++ )
- {
- data[i] = bytes[ location + i ];
- }
- return data;
- }
-
- /**
- * Returns a copy of the bytes backing this data object.
- * NOTE: This method is not in the NSData spec and is
- * included for convenience only.
- */
- public byte[] bytes()
- {
- return bytes( 0, length() );
- }
+ /**
+ * Returns a copy of the bytes backing this data object. NOTE: This method is
+ * not in the NSData spec and is included for convenience only.
+ */
+ public byte[] bytes() {
+ return bytes(0, length());
+ }
- public String toString() {
- String hex = "0123456789ABCDEF";
- StringBuffer buf = new StringBuffer();
- buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DATA]);
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- buf.append(hex.charAt((b & 0xf0) >> 4));
- buf.append(hex.charAt(b & 0x0f));
- if (i % 5 == 4)
- buf.append(' ');
- }
- buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DATA]);
- return buf.toString();
- }
+ public String toString() {
+ String hex = "0123456789ABCDEF";
+ StringBuffer buf = new StringBuffer();
+ buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DATA]);
+ for (int i = 0; i < bytes.length; i++) {
+ byte b = bytes[i];
+ buf.append(hex.charAt((b & 0xf0) >> 4));
+ buf.append(hex.charAt(b & 0x0f));
+ if (i % 5 == 4)
+ buf.append(' ');
+ }
+ buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DATA]);
+ return buf.toString();
+ }
public boolean isEqual(Object obj) {
if (obj == this)
return true;
if (obj instanceof NSData)
- return isEqualToData((NSData)obj);
+ return isEqualToData((NSData) obj);
return false;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/19 01:53:52 chochos
- * added constructor with an InputStream
+ * Revision 1.5 2003/08/19 01:53:52 chochos added constructor with an
+ * InputStream
*
- * Revision 1.4 2003/08/05 00:51:31 chochos
- * get the enclosing tokens from NSPropertyListSerialization
+ * Revision 1.4 2003/08/05 00:51:31 chochos get the enclosing tokens from
+ * NSPropertyListSerialization
*
- * Revision 1.3 2003/08/04 22:45:47 chochos
- * toString() prints out the bytes in hex (in property list format)
+ * Revision 1.3 2003/08/04 22:45:47 chochos toString() prints out the bytes in
+ * hex (in property list format)
*
- * Revision 1.2 2003/08/02 01:52:00 chochos
- * added EmptyData
+ * Revision 1.2 2003/08/02 01:52:00 chochos added EmptyData
*
- * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
index d5b6f61..a2121fd 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
@@ -23,17 +23,16 @@ import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
-* A pure java implementation of NSDate that extends
-* java.util.Date for greater java compatibility.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
-public class NSDate extends Date
-{
+ * A pure java implementation of NSDate that extends java.util.Date for greater
+ * java compatibility.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
+public class NSDate extends Date {
// NSComparisonResult compatibility
-
+
public static final int NSOrderedAscending = -1;
public static final int NSOrderedSame = 0;
public static final int NSOrderedDescending = 1;
@@ -41,158 +40,142 @@ public class NSDate extends Date
// public static final double TimeIntervalSince1970;
// public static final NSDate DateFor1970;
- /**
- * Default constructor represents the current date.
- */
- public NSDate ()
- {
- super();
- }
-
- /**
- * Represents the specified number of seconds from the current date.
- */
- public NSDate (double seconds)
- {
- super( (long) new NSDate().getTime() +
- timeIntervalToMilliseconds(seconds) );
- }
-
- /**
- * Represents the specified number of seconds from the specified date.
- */
- public NSDate (double seconds, Date sinceDate)
- {
- super( (long) sinceDate.getTime() +
- timeIntervalToMilliseconds(seconds) );
- }
-
- /**
- * Returns the interval between this date and 1 January 2001 GMT.
- */
- public double timeIntervalSinceReferenceDate ()
- {
- GregorianCalendar referenceDate =
- new GregorianCalendar( TimeZone.getTimeZone( "GMT" ) );
- referenceDate.set( 2001, 0, 0, 0, 0, 0 );
- return timeIntervalSinceDate( referenceDate.getTime() );
- }
-
- /**
- * Returns the interval between this date and the specified date
- * in seconds.
- */
- public double timeIntervalSinceDate (Date aDate)
- {
- return millisecondsToTimeInterval(
- this.getTime() - aDate.getTime() );
- }
-
- /**
- * Returns the interval between this date and the current date
- * in seconds.
- */
- public double timeIntervalSinceNow ()
- {
- return timeIntervalSinceDate( new NSDate() );
- }
-
- /**
- * Compares this date to the specified date and returns the
- * earlier date. Unspecified which is returned if both are equal.
- */
- public NSDate earlierDate (NSDate aDate)
- {
- if ( aDate == null ) return this;
- if ( after( aDate ) ) return aDate;
- return this;
- }
-
- /**
- * Compares this date to the specified date and returns the
- * later date. Unspecified which is returned if both are equal.
- */
- public NSDate laterDate (NSDate aDate)
- {
- if ( aDate == null ) return this;
- if ( before( aDate ) ) return aDate;
- return this;
- }
-
- /**
- * Returns a negative value if the specified date is later than
- * this date, a positive value if the specified date is earlier
- * than this date, or zero if the dates are equal. The return
- * values are compatible with type NSComparisonResult.
- */
- public int compare (Date aDate)
- {
- if ( before( aDate ) ) return NSOrderedAscending;
- if ( after( aDate ) ) return NSOrderedDescending;
- return NSOrderedSame;
- }
-
- /**
- * Returns whether the this date is equal to the specified date,
- * per the result of equals().
- */
- public boolean isEqualToDate (Date aDate)
- {
- return equals( aDate );
- }
-
- /**
- * Returns a date that differs from this date by the specified
- * number of seconds.
- */
- public NSDate dateByAddingTimeInterval (double seconds)
- {
- return new NSDate( seconds, this );
- }
-
- /**
- * Returns the number of seconds between now and the reference date.
- */
- public static double currentTimeIntervalSinceReferenceDate ()
- {
- return new NSDate().timeIntervalSinceReferenceDate();
- }
-
- /**
- * Converts seconds to milliseconds. Included for compatibility.
- */
- public static long timeIntervalToMilliseconds (double seconds)
- {
- return (long) seconds*1000;
- }
-
- /**
- * Converts milliseconds to seconds. Included for compatibility.
- */
- public static double millisecondsToTimeInterval (long millis)
- {
- return millis/1000.0;
- }
-
- /**
- * Returns a date that is greater than all representable dates.
- */
- public static NSDate distantFuture ()
- {
- NSDate result = new NSDate();
- result.setTime( Long.MAX_VALUE );
- return result;
- }
-
- /**
- * Returns a date that is less than all representable dates.
- */
- public static NSDate distantPast ()
- {
- NSDate result = new NSDate();
- result.setTime( Long.MIN_VALUE );
- return result;
- }
+ /**
+ * Default constructor represents the current date.
+ */
+ public NSDate() {
+ super();
+ }
+
+ /**
+ * Represents the specified number of seconds from the current date.
+ */
+ public NSDate(double seconds) {
+ super((long) new NSDate().getTime() + timeIntervalToMilliseconds(seconds));
+ }
+
+ /**
+ * Represents the specified number of seconds from the specified date.
+ */
+ public NSDate(double seconds, Date sinceDate) {
+ super((long) sinceDate.getTime() + timeIntervalToMilliseconds(seconds));
+ }
+
+ /**
+ * Returns the interval between this date and 1 January 2001 GMT.
+ */
+ public double timeIntervalSinceReferenceDate() {
+ GregorianCalendar referenceDate = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+ referenceDate.set(2001, 0, 0, 0, 0, 0);
+ return timeIntervalSinceDate(referenceDate.getTime());
+ }
+
+ /**
+ * Returns the interval between this date and the specified date in seconds.
+ */
+ public double timeIntervalSinceDate(Date aDate) {
+ return millisecondsToTimeInterval(this.getTime() - aDate.getTime());
+ }
+
+ /**
+ * Returns the interval between this date and the current date in seconds.
+ */
+ public double timeIntervalSinceNow() {
+ return timeIntervalSinceDate(new NSDate());
+ }
+
+ /**
+ * Compares this date to the specified date and returns the earlier date.
+ * Unspecified which is returned if both are equal.
+ */
+ public NSDate earlierDate(NSDate aDate) {
+ if (aDate == null)
+ return this;
+ if (after(aDate))
+ return aDate;
+ return this;
+ }
+
+ /**
+ * Compares this date to the specified date and returns the later date.
+ * Unspecified which is returned if both are equal.
+ */
+ public NSDate laterDate(NSDate aDate) {
+ if (aDate == null)
+ return this;
+ if (before(aDate))
+ return aDate;
+ return this;
+ }
+
+ /**
+ * Returns a negative value if the specified date is later than this date, a
+ * positive value if the specified date is earlier than this date, or zero if
+ * the dates are equal. The return values are compatible with type
+ * NSComparisonResult.
+ */
+ public int compare(Date aDate) {
+ if (before(aDate))
+ return NSOrderedAscending;
+ if (after(aDate))
+ return NSOrderedDescending;
+ return NSOrderedSame;
+ }
+
+ /**
+ * Returns whether the this date is equal to the specified date, per the result
+ * of equals().
+ */
+ public boolean isEqualToDate(Date aDate) {
+ return equals(aDate);
+ }
+
+ /**
+ * Returns a date that differs from this date by the specified number of
+ * seconds.
+ */
+ public NSDate dateByAddingTimeInterval(double seconds) {
+ return new NSDate(seconds, this);
+ }
+
+ /**
+ * Returns the number of seconds between now and the reference date.
+ */
+ public static double currentTimeIntervalSinceReferenceDate() {
+ return new NSDate().timeIntervalSinceReferenceDate();
+ }
+
+ /**
+ * Converts seconds to milliseconds. Included for compatibility.
+ */
+ public static long timeIntervalToMilliseconds(double seconds) {
+ return (long) seconds * 1000;
+ }
+
+ /**
+ * Converts milliseconds to seconds. Included for compatibility.
+ */
+ public static double millisecondsToTimeInterval(long millis) {
+ return millis / 1000.0;
+ }
+
+ /**
+ * Returns a date that is greater than all representable dates.
+ */
+ public static NSDate distantFuture() {
+ NSDate result = new NSDate();
+ result.setTime(Long.MAX_VALUE);
+ return result;
+ }
+
+ /**
+ * Returns a date that is less than all representable dates.
+ */
+ public static NSDate distantPast() {
+ NSDate result = new NSDate();
+ result.setTime(Long.MIN_VALUE);
+ return result;
+ }
// inherited from java.util.Date
// public java.lang.String toString ();
@@ -202,16 +185,12 @@ public class NSDate extends Date
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:28 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:28 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java
index 235a7bb..a4e9cd5 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java
@@ -24,309 +24,268 @@ import java.util.Iterator;
import java.util.Map;
/**
-* A pure java implementation of NSDictionary that
-* implements Map for greater java interoperability.
-*
-* @author michael@mpowers.net
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSDictionary extends HashMap implements NSKeyValueCoding
-{
- public static final NSDictionary EmptyDictionary = new NSDictionary();
-
- /**
- * Default constructor produces an empty dictionary.
- */
- public NSDictionary ()
- {
- super();
- }
-
- /**
- * Constructor produces an empty dictionary with an initial capacity.
- */
- public NSDictionary (int initialCapacity)
- {
- super(initialCapacity);
- }
-
- /**
- * Produces a dictionary that contains one key referencing one value.
- */
- public NSDictionary (Object key, Object value)
- {
- super();
- put( key, value );
- }
-
- /**
- * Produces a dictionary containing the specified keys and values.
- * An IllegalArgumentException is thrown if the arrays are not
- * of the same length.
- */
- public NSDictionary (Object[] objects, Object[] keys)
- {
- super();
- if ( keys.length != objects.length )
- {
- throw new IllegalArgumentException( "Array lengths do not match." );
- }
-
- for ( int i = 0; i < keys.length; i++ )
- {
- put( keys[i], objects[i] );
- }
- }
-
- /**
- * Produces a dictionary that is a copy of the specified map (or dictionary).
- */
- public NSDictionary (Map aMap)
- {
- super( aMap );
- }
-
- /**
- * Returns a count of the key-value pairs in this dictionary.
- */
- public int count ()
- {
- return size();
- }
-
- /**
- * Returns an NSArray containing all keys in this dictionary.
- */
- public NSArray allKeys ()
- {
- return new NSArray( keySet() );
-
- }
-
- /**
- * Returns an NSArray containing all keys that reference the
- * specified value.
- */
- public NSArray allKeysForObject (Object value)
- {
- NSMutableArray result = new NSMutableArray();
- Map.Entry entry;
+ * A pure java implementation of NSDictionary that implements Map for greater
+ * java interoperability.
+ *
+ * @author michael@mpowers.net
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSDictionary extends HashMap implements NSKeyValueCoding {
+ public static final NSDictionary EmptyDictionary = new NSDictionary();
+
+ /**
+ * Default constructor produces an empty dictionary.
+ */
+ public NSDictionary() {
+ super();
+ }
+
+ /**
+ * Constructor produces an empty dictionary with an initial capacity.
+ */
+ public NSDictionary(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ /**
+ * Produces a dictionary that contains one key referencing one value.
+ */
+ public NSDictionary(Object key, Object value) {
+ super();
+ put(key, value);
+ }
+
+ /**
+ * Produces a dictionary containing the specified keys and values. An
+ * IllegalArgumentException is thrown if the arrays are not of the same length.
+ */
+ public NSDictionary(Object[] objects, Object[] keys) {
+ super();
+ if (keys.length != objects.length) {
+ throw new IllegalArgumentException("Array lengths do not match.");
+ }
+
+ for (int i = 0; i < keys.length; i++) {
+ put(keys[i], objects[i]);
+ }
+ }
+
+ /**
+ * Produces a dictionary that is a copy of the specified map (or dictionary).
+ */
+ public NSDictionary(Map aMap) {
+ super(aMap);
+ }
+
+ /**
+ * Returns a count of the key-value pairs in this dictionary.
+ */
+ public int count() {
+ return size();
+ }
+
+ /**
+ * Returns an NSArray containing all keys in this dictionary.
+ */
+ public NSArray allKeys() {
+ return new NSArray(keySet());
+
+ }
+
+ /**
+ * Returns an NSArray containing all keys that reference the specified value.
+ */
+ public NSArray allKeysForObject(Object value) {
+ NSMutableArray result = new NSMutableArray();
+ Map.Entry entry;
Iterator it = entrySet().iterator();
- while ( it.hasNext() )
- {
+ while (it.hasNext()) {
entry = (Map.Entry) it.next();
// handle null values
- if ( ( value == null ) && ( entry.getValue() == null )
- || ( value.equals( entry.getValue() ) ) )
- {
+ if ((value == null) && (entry.getValue() == null) || (value.equals(entry.getValue()))) {
// if match, add to result set
- result.addObject( entry.getKey() );
+ result.addObject(entry.getKey());
}
}
-
+
return result;
- }
-
- /**
- * Returns an NSArray containing all values in this dictionary.
- */
- public NSArray allValues ()
- {
- return new NSArray( values() );
- }
-
- /**
- * Returns whether the specified dictionary has the same or
- * equivalent key-value pairs as this dictionary.
- */
- public boolean isEqualToDictionary (NSDictionary aDictionary)
- {
- return equals( aDictionary );
- }
-
- /**
- * Returns an array of objects for the specified array of keys.
- * If a key isn't found, the marker parameter will be placed
- * in the corresponding index(es) in the returned array.
- */
- public NSArray objectsForKeys (NSArray anArray, Object aMarker)
- {
- NSMutableArray result = new NSMutableArray();
- if ( anArray == null ) return result;
-
- Object value;
- Enumeration enumeration = anArray.objectEnumerator();
- while ( enumeration.hasMoreElements() )
- {
- value = objectForKey( enumeration.nextElement() );
- if ( value == null )
- {
- value = aMarker;
- }
- result.addObject( value );
- }
- return result;
- }
-
- /**
- * Returns an enumeration over the keys in this dictionary.
- */
- public java.util.Enumeration keyEnumerator ()
- {
- return new java.util.Enumeration()
- {
- Iterator it = NSDictionary.this.keySet().iterator();
- public boolean hasMoreElements()
- {
+ }
+
+ /**
+ * Returns an NSArray containing all values in this dictionary.
+ */
+ public NSArray allValues() {
+ return new NSArray(values());
+ }
+
+ /**
+ * Returns whether the specified dictionary has the same or equivalent key-value
+ * pairs as this dictionary.
+ */
+ public boolean isEqualToDictionary(NSDictionary aDictionary) {
+ return equals(aDictionary);
+ }
+
+ /**
+ * Returns an array of objects for the specified array of keys. If a key isn't
+ * found, the marker parameter will be placed in the corresponding index(es) in
+ * the returned array.
+ */
+ public NSArray objectsForKeys(NSArray anArray, Object aMarker) {
+ NSMutableArray result = new NSMutableArray();
+ if (anArray == null)
+ return result;
+
+ Object value;
+ Enumeration enumeration = anArray.objectEnumerator();
+ while (enumeration.hasMoreElements()) {
+ value = objectForKey(enumeration.nextElement());
+ if (value == null) {
+ value = aMarker;
+ }
+ result.addObject(value);
+ }
+ return result;
+ }
+
+ /**
+ * Returns an enumeration over the keys in this dictionary.
+ */
+ public java.util.Enumeration keyEnumerator() {
+ return new java.util.Enumeration() {
+ Iterator it = NSDictionary.this.keySet().iterator();
+
+ public boolean hasMoreElements() {
return it.hasNext();
- }
- public Object nextElement()
- {
- return it.next();
- }
- };
- }
-
- /**
- * Returns an enumeration over the values in this dictionary.
- */
- public java.util.Enumeration objectEnumerator ()
- {
- return new java.util.Enumeration()
- {
- Iterator it = NSDictionary.this.values().iterator();
- public boolean hasMoreElements()
- {
+ }
+
+ public Object nextElement() {
+ return it.next();
+ }
+ };
+ }
+
+ /**
+ * Returns an enumeration over the values in this dictionary.
+ */
+ public java.util.Enumeration objectEnumerator() {
+ return new java.util.Enumeration() {
+ Iterator it = NSDictionary.this.values().iterator();
+
+ public boolean hasMoreElements() {
return it.hasNext();
- }
- public Object nextElement()
- {
- return it.next();
- }
- };
+ }
+
+ public Object nextElement() {
+ return it.next();
+ }
+ };
+ }
+
+ /**
+ * Returns the value for the specified key, or null if the key is not found.
+ */
+ public Object objectForKey(Object aKey) {
+ return get(aKey);
+ }
+
+ // interface NSKeyValueCoding
+
+ public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this );
+ Object result = objectForKey(aKey);
+ if (result == null)
+ result = NSKeyValueCodingSupport.valueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : "
+ // + aValue + "->" + this );
+ put(aKey, aValue); // FIXME: technically cheating since this is a read-only class
+ }
+
+ public Object storedValueForKey(String aKey) {
+ Object result = objectForKey(aKey);
+ if (result == null)
+ result = NSKeyValueCodingSupport.storedValueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ put(aKey, aValue); // FIXME: technically cheating since this is a read-only class
+ }
+
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return NSKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ NSKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ public void unableToSetNullForKey(String aKey) {
+ NSKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ public Object validateTakeValueForKeyPath(Object aValue, String aKey) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ Enumeration enumeration = keyEnumerator();
+ boolean quote = false;
+ buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DICTIONARY]);
+ while (enumeration.hasMoreElements()) {
+ if (buf.length() == 1)
+ buf.append(' ');
+ Object k = enumeration.nextElement();
+ buf.append(NSPropertyListSerialization.stringForPropertyList(k));
+ buf.append(" = ");
+ k = objectForKey(k);
+ buf.append(NSPropertyListSerialization.stringForPropertyList(k));
+ buf.append("; ");
+ }
+ buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DICTIONARY]);
+ return buf.toString();
}
-
- /**
- * Returns the value for the specified key, or null
- * if the key is not found.
- */
- public Object objectForKey (Object aKey)
- {
- return get( aKey );
- }
-
- // interface NSKeyValueCoding
-
- public Object valueForKey (String aKey)
- { // System.out.println( "valueForKey: " + aKey + "->" + this );
- Object result = objectForKey( aKey );
- if ( result == null )
- result = NSKeyValueCodingSupport.valueForKey( this, aKey );
- return result;
- }
-
- public void takeValueForKey (Object aValue, String aKey)
- { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this );
- put( aKey, aValue ); //FIXME: technically cheating since this is a read-only class
- }
-
- public Object storedValueForKey (String aKey)
- {
- Object result = objectForKey( aKey );
- if ( result == null )
- result = NSKeyValueCodingSupport.storedValueForKey( this, aKey );
- return result;
- }
-
- public void takeStoredValueForKey (Object aValue, String aKey)
- {
- put( aKey, aValue ); //FIXME: technically cheating since this is a read-only class
- }
-
- public Object handleQueryWithUnboundKey (String aKey)
- {
- return NSKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- public void handleTakeValueForUnboundKey (Object aValue, String aKey)
- {
- NSKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- public void unableToSetNullForKey (String aKey)
- {
- NSKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- public Object validateTakeValueForKeyPath (Object aValue, String aKey)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer();
- Enumeration enumeration = keyEnumerator();
- boolean quote = false;
- buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DICTIONARY]);
- while (enumeration.hasMoreElements()) {
- if (buf.length() == 1)
- buf.append(' ');
- Object k = enumeration.nextElement();
- buf.append(NSPropertyListSerialization.stringForPropertyList(k));
- buf.append(" = ");
- k = objectForKey(k);
- buf.append(NSPropertyListSerialization.stringForPropertyList(k));
- buf.append("; ");
- }
- buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DICTIONARY]);
- return buf.toString();
- }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.9 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.8 2003/08/05 00:50:14 chochos
- * use NSPropertyListSerialization to get the tokens to enclose the string description
+ * Revision 1.8 2003/08/05 00:50:14 chochos use NSPropertyListSerialization to
+ * get the tokens to enclose the string description
*
- * Revision 1.7 2003/08/04 20:26:10 chochos
- * use NSPropertyListSerialization inside toString()
+ * Revision 1.7 2003/08/04 20:26:10 chochos use NSPropertyListSerialization
+ * inside toString()
*
- * Revision 1.6 2003/08/04 18:49:38 chochos
- * NSDictionary(Object[], Object[]) was taking the parameters in the wrong order; for compatibility with Apple's NSDictionary, objects comes first, then keys.
+ * Revision 1.6 2003/08/04 18:49:38 chochos NSDictionary(Object[], Object[]) was
+ * taking the parameters in the wrong order; for compatibility with Apple's
+ * NSDictionary, objects comes first, then keys.
*
- * Revision 1.5 2003/08/04 18:26:19 chochos
- * fixed opening '{'
+ * Revision 1.5 2003/08/04 18:26:19 chochos fixed opening '{'
*
- * Revision 1.4 2003/01/28 22:11:30 mpowers
- * Now implements NSKeyValueCoding.
+ * Revision 1.4 2003/01/28 22:11:30 mpowers Now implements NSKeyValueCoding.
*
- * Revision 1.3 2002/06/30 17:58:06 mpowers
- * Add a capacity constructor and static empty dictionary: thanks cgruber.
+ * Revision 1.3 2002/06/30 17:58:06 mpowers Add a capacity constructor and
+ * static empty dictionary: thanks cgruber.
*
- * Revision 1.2 2001/02/23 23:43:41 mpowers
- * Removed ill-advised this.
+ * Revision 1.2 2001/02/23 23:43:41 mpowers Removed ill-advised this.
*
- * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java
index 46df7d2..49b84a2 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java
@@ -22,14 +22,14 @@ $Id: NSDisposable.java 893 2006-02-16 13:22:23Z cgruber $
package net.wotonomy.foundation;
/**
-* Interface for objects that respond to dispose();
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * Interface for objects that respond to dispose();
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public interface NSDisposable {
- public abstract void dispose();
+ public abstract void dispose();
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java
index 1db0ad2..10f54af 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java
@@ -23,135 +23,115 @@ import java.io.PrintWriter;
import java.io.StringWriter;
/**
-* Serves to wrap an exception inside of a RuntimeException,
-* which is not required to be declared in a throws statement.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * Serves to wrap an exception inside of a RuntimeException, which is not
+ * required to be declared in a throws statement.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
-public class NSForwardException extends RuntimeException
-{
+public class NSForwardException extends RuntimeException {
protected String message;
protected Throwable wrappedThrowable;
-
+
/**
- * Default constructor.
- */
- public NSForwardException()
- {
+ * Default constructor.
+ */
+ public NSForwardException() {
super();
message = null;
- wrappedThrowable = null;
+ wrappedThrowable = null;
}
-
+
/**
- * Standard constructor with message.
- */
- public NSForwardException( String aMessage )
- {
- super( aMessage );
+ * Standard constructor with message.
+ */
+ public NSForwardException(String aMessage) {
+ super(aMessage);
message = aMessage;
wrappedThrowable = null;
}
-
+
/**
- * Specifies a throwable to wrap.
- */
- public NSForwardException( Throwable aThrowable )
- {
+ * Specifies a throwable to wrap.
+ */
+ public NSForwardException(Throwable aThrowable) {
super();
message = null;
wrappedThrowable = aThrowable;
}
-
+
/**
- * Specifies a message and a throwable to wrap.
- */
- public NSForwardException( Throwable aThrowable, String aMessage )
- {
- super( aMessage );
+ * Specifies a message and a throwable to wrap.
+ */
+ public NSForwardException(Throwable aThrowable, String aMessage) {
+ super(aMessage);
message = aMessage;
wrappedThrowable = aThrowable;
}
-
- /**
- * Returns the wrapped throwable.
- */
- public Throwable originalException()
- {
- return wrappedThrowable;
- }
-
- public void printStackTrace(PrintWriter s)
- {
- if ( message != null )
- {
- s.println( toString() );
+
+ /**
+ * Returns the wrapped throwable.
+ */
+ public Throwable originalException() {
+ return wrappedThrowable;
+ }
+
+ public void printStackTrace(PrintWriter s) {
+ if (message != null) {
+ s.println(toString());
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace( s );
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace(s);
return;
}
- super.printStackTrace( s );
+ super.printStackTrace(s);
}
-
- public void printStackTrace(PrintStream s)
- {
- if ( message != null )
- {
- s.println( toString() );
+
+ public void printStackTrace(PrintStream s) {
+ if (message != null) {
+ s.println(toString());
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace( s );
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace(s);
return;
}
- super.printStackTrace( s );
+ super.printStackTrace(s);
}
-
- public void printStackTrace()
- {
- if ( message != null )
- {
- System.err.println( toString() );
+
+ public void printStackTrace() {
+ if (message != null) {
+ System.err.println(toString());
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace();
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace();
return;
}
super.printStackTrace();
}
-
- public String stackTrace()
- {
- StringWriter writer = new StringWriter();
- PrintWriter printWriter = new PrintWriter( writer );
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace( printWriter );
+
+ public String stackTrace() {
+ StringWriter writer = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(writer);
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace(printWriter);
+ } else {
+ super.printStackTrace(printWriter);
}
- else
- {
- super.printStackTrace( printWriter );
- }
- printWriter.flush();
- printWriter.close();
- return writer.toString();
- }
-
- public String toString()
- {
- String result = message;
- if ( result == null ) result = "";
- if ( wrappedThrowable != null )
- {
- result = wrappedThrowable.toString() + " : " + result;
+ printWriter.flush();
+ printWriter.close();
+ return writer.toString();
+ }
+
+ public String toString() {
+ String result = message;
+ if (result == null)
+ result = "";
+ if (wrappedThrowable != null) {
+ result = wrappedThrowable.toString() + " : " + result;
}
- return result;
- }
-
+ return result;
+ }
+
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java
index 5792303..9eece7e 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java
@@ -25,374 +25,293 @@ import net.wotonomy.foundation.internal.NullPrimitiveException;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* NSKeyValueCoding defines an interface for classes that
-* need to have more control over the wotonomy's property
-* introspection facilities. <br><br>
-*
-* On an object that implements this interface, wotonomy
-* will call these methods, and otherwise use the static
-* methods on NSKeyValueCodingSupport. <br><br>
-*
-* NSKeyValueCodingSupport implements the default behaviors
-* for each of these methods, so classes implementing this
-* interface can call those methods to acheive the same
-* behavior. <br><br>
-*
-* valueForKey and takeValueForKey are called in response
-* to user actions, like viewing an object or updating its
-* value in a user interface. These should call the public
-* getter and setter methods on the object itself and the
-* operations should be subject to validation. <br><br>
-*
-* storedValueForKey and takeStoredValueForKey are called
-* in response to wotonomy actions, like snapshotting,
-* faulting, commits, and reverts. These operations should
-* bypass the public methods and directly modify the internal
-* state of the object without validation.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface NSKeyValueCoding
-{
+ * NSKeyValueCoding defines an interface for classes that need to have more
+ * control over the wotonomy's property introspection facilities. <br>
+ * <br>
+ *
+ * On an object that implements this interface, wotonomy will call these
+ * methods, and otherwise use the static methods on NSKeyValueCodingSupport.
+ * <br>
+ * <br>
+ *
+ * NSKeyValueCodingSupport implements the default behaviors for each of these
+ * methods, so classes implementing this interface can call those methods to
+ * acheive the same behavior. <br>
+ * <br>
+ *
+ * valueForKey and takeValueForKey are called in response to user actions, like
+ * viewing an object or updating its value in a user interface. These should
+ * call the public getter and setter methods on the object itself and the
+ * operations should be subject to validation. <br>
+ * <br>
+ *
+ * storedValueForKey and takeStoredValueForKey are called in response to
+ * wotonomy actions, like snapshotting, faulting, commits, and reverts. These
+ * operations should bypass the public methods and directly modify the internal
+ * state of the object without validation.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface NSKeyValueCoding {
public static final Null NullValue = new Null();
- /**
- * Returns the value for the specified property.
- * If the property does not exist, this method should
- * call handleQueryWithUnboundKey.
- */
- Object valueForKey( String aKey );
-
- /**
- * Sets the property to the specified value.
- * If the property does not exist, this method should
- * call handleTakeValueForUnboundKey.
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey.
- */
- void takeValueForKey( Object aValue, String aKey );
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property.
- */
- Object storedValueForKey( String aKey );
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value.
- */
- void takeStoredValueForKey( Object aValue, String aKey );
-
- /**
- * Called by valueForKey when the specified key is
- * not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- Object handleQueryWithUnboundKey( String aKey );
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- void handleTakeValueForUnboundKey( Object aValue, String aKey );
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types. Implementing
- * classes should handle this case appropriately
- * or otherwise throw an exception.
- */
- void unableToSetNullForKey( String aKey );
-
- /**
- * Static utility methods that
- * call the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- public class Utility
- {
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public Object valueForKey(
- Object anObject, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- return ((NSKeyValueCoding)anObject).valueForKey( aKey );
- }
- return DefaultImplementation.valueForKey( anObject, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public void takeValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
- }
- DefaultImplementation.takeValueForKey( anObject, aValue, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public Object storedValueForKey(
- Object anObject, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- return ((NSKeyValueCoding)anObject).storedValueForKey( aKey );
- }
- return DefaultImplementation.storedValueForKey( anObject, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public void takeStoredValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).takeStoredValueForKey( aValue, aKey );
- }
- DefaultImplementation.takeStoredValueForKey( anObject, aValue, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public Object handleQueryWithUnboundKey(
- Object anObject, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
- }
- return DefaultImplementation.handleQueryWithUnboundKey( anObject, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public void handleTakeValueForUnboundKey(
- Object anObject, Object aValue, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( aValue, aKey );
- }
- DefaultImplementation.handleTakeValueForUnboundKey( anObject, aValue, aKey );
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCoding, otherwise calls the method
- * on DefaultImplementation.
- */
- static public void unableToSetNullForKey(
- Object anObject, String aKey )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey );
- }
- DefaultImplementation.unableToSetNullForKey( anObject, aKey );
- }
- }
-
- public class DefaultImplementation
- {
- /**
- * Returns the value for the specified property key
- * on the specified object. <br><br>
- *
- * If the property does not exist, this method calls
- * handleQueryWithUnboundKey on the object if it
- * implements NSKeyValueCoding, otherwise calls
- * handleQueryWithUnboundKey on this class. <br><br>
- */
- static public Object valueForKey(
- Object anObject, String aKey )
- {
- if ( anObject == null ) return null;
- //TODO: may need to handle "." nesting here so
- // that handleQueryWithUnboundKey gets called for
- // for the nested object, not the parent object
-
- //Correction: need to handle key paths in
- // KeyValueCodingAdditionsSupport.
-
- try
- {
- return Introspector.get( anObject, aKey );
- }
- catch ( IntrospectorException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
- }
- return handleQueryWithUnboundKey( anObject, aKey );
- }
- }
-
- /**
- * Sets the property to the specified value on
- * the specified object.
- *
- * If the property does not exist, this method calls
- * handleTakeValueForUnboundKey on the object if it
- * implements NSKeyValueCoding, otherwise calls
- * handleTakeValueForUnboundKey on this class.
- *
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey
- * on the object if it implements NSKeyValueCoding,
- * otherwise calls unableToSetNullForKey on this class.
- */
- static public void takeValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- if ( anObject == null ) return;
- //TODO: may need to handle "." nesting here so
- // that handleTakeValueForUnboundKey gets called for
- // for the nested object, not the parent object
- try
- {
- Introspector.set( anObject, aKey, aValue );
- }
- catch ( NullPrimitiveException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey );
- }
- else
- {
- unableToSetNullForKey( anObject, aKey );
- }
- }
- catch ( MissingPropertyException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey(
- aValue, aKey );
- }
- else
- {
- handleTakeValueForUnboundKey( anObject, aValue, aKey );
- }
- }
-
- }
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property on
- * the specified object.
- *
- * This implementation currently calls valueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public Object storedValueForKey(
- Object anObject, String aKey )
- {
- //TODO: this currently just calls valueForKey
- return valueForKey( anObject, aKey );
- }
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value on the
- * specified object.
- *
- * This implementation currently calls takeValueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public void takeStoredValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- //TODO: this currently just calls takeValueForKey
- takeValueForKey( anObject, aValue, aKey );
- }
-
- /**
- * Called by valueForKey when the specified key is
- * not found on the specified object, if that object
- * does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public Object handleQueryWithUnboundKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object: "
- + aKey + " : " + anObject );
- }
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on the specified object, if that object
- * does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void handleTakeValueForUnboundKey(
- Object anObject, Object aValue, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object while setting value: "
- + aKey + " : " + anObject + " : " + aValue );
- }
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types, if the specified
- * object does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void unableToSetNullForKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Tried to key on object to null: "
- + aKey + " : " + anObject );
- }
- }
+ /**
+ * Returns the value for the specified property. If the property does not exist,
+ * this method should call handleQueryWithUnboundKey.
+ */
+ Object valueForKey(String aKey);
+
+ /**
+ * Sets the property to the specified value. If the property does not exist,
+ * this method should call handleTakeValueForUnboundKey. If the property is of a
+ * type that cannot allow null (e.g. primitive types) and aValue is null, this
+ * method should call unableToSetNullForKey.
+ */
+ void takeValueForKey(Object aValue, String aKey);
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property.
+ */
+ Object storedValueForKey(String aKey);
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value.
+ */
+ void takeStoredValueForKey(Object aValue, String aKey);
+
+ /**
+ * Called by valueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ Object handleQueryWithUnboundKey(String aKey);
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ void handleTakeValueForUnboundKey(Object aValue, String aKey);
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types. Implementing classes should
+ * handle this case appropriately or otherwise throw an exception.
+ */
+ void unableToSetNullForKey(String aKey);
+
+ /**
+ * Static utility methods that call the appropriate method if the object
+ * implements NSKeyValueCoding, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public class Utility {
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public Object valueForKey(Object anObject, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ return ((NSKeyValueCoding) anObject).valueForKey(aKey);
+ }
+ return DefaultImplementation.valueForKey(anObject, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public void takeValueForKey(Object anObject, Object aValue, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).takeValueForKey(aValue, aKey);
+ }
+ DefaultImplementation.takeValueForKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public Object storedValueForKey(Object anObject, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ return ((NSKeyValueCoding) anObject).storedValueForKey(aKey);
+ }
+ return DefaultImplementation.storedValueForKey(anObject, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).takeStoredValueForKey(aValue, aKey);
+ }
+ DefaultImplementation.takeStoredValueForKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public Object handleQueryWithUnboundKey(Object anObject, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey);
+ }
+ return DefaultImplementation.handleQueryWithUnboundKey(anObject, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey);
+ }
+ DefaultImplementation.handleTakeValueForUnboundKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Calls the appropriate method if the object implements NSKeyValueCoding,
+ * otherwise calls the method on DefaultImplementation.
+ */
+ static public void unableToSetNullForKey(Object anObject, String aKey) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey);
+ }
+ DefaultImplementation.unableToSetNullForKey(anObject, aKey);
+ }
+ }
+
+ public class DefaultImplementation {
+ /**
+ * Returns the value for the specified property key on the specified object.
+ * <br>
+ * <br>
+ *
+ * If the property does not exist, this method calls handleQueryWithUnboundKey
+ * on the object if it implements NSKeyValueCoding, otherwise calls
+ * handleQueryWithUnboundKey on this class. <br>
+ * <br>
+ */
+ static public Object valueForKey(Object anObject, String aKey) {
+ if (anObject == null)
+ return null;
+ // TODO: may need to handle "." nesting here so
+ // that handleQueryWithUnboundKey gets called for
+ // for the nested object, not the parent object
+
+ // Correction: need to handle key paths in
+ // KeyValueCodingAdditionsSupport.
+
+ try {
+ return Introspector.get(anObject, aKey);
+ } catch (IntrospectorException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey);
+ }
+ return handleQueryWithUnboundKey(anObject, aKey);
+ }
+ }
+
+ /**
+ * Sets the property to the specified value on the specified object.
+ *
+ * If the property does not exist, this method calls
+ * handleTakeValueForUnboundKey on the object if it implements NSKeyValueCoding,
+ * otherwise calls handleTakeValueForUnboundKey on this class.
+ *
+ * If the property is of a type that cannot allow null (e.g. primitive types)
+ * and aValue is null, this method should call unableToSetNullForKey on the
+ * object if it implements NSKeyValueCoding, otherwise calls
+ * unableToSetNullForKey on this class.
+ */
+ static public void takeValueForKey(Object anObject, Object aValue, String aKey) {
+ if (anObject == null)
+ return;
+ // TODO: may need to handle "." nesting here so
+ // that handleTakeValueForUnboundKey gets called for
+ // for the nested object, not the parent object
+ try {
+ Introspector.set(anObject, aKey, aValue);
+ } catch (NullPrimitiveException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey);
+ } else {
+ unableToSetNullForKey(anObject, aKey);
+ }
+ } catch (MissingPropertyException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey);
+ } else {
+ handleTakeValueForUnboundKey(anObject, aValue, aKey);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property on the specified object.
+ *
+ * This implementation currently calls valueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public Object storedValueForKey(Object anObject, String aKey) {
+ // TODO: this currently just calls valueForKey
+ return valueForKey(anObject, aKey);
+ }
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value on the specified object.
+ *
+ * This implementation currently calls takeValueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) {
+ // TODO: this currently just calls takeValueForKey
+ takeValueForKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Called by valueForKey when the specified key is not found on the specified
+ * object, if that object does not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public Object handleQueryWithUnboundKey(Object anObject, String aKey) {
+ throw new WotonomyException("Key not found for object: " + aKey + " : " + anObject);
+ }
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on the
+ * specified object, if that object does not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) {
+ throw new WotonomyException(
+ "Key not found for object while setting value: " + aKey + " : " + anObject + " : " + aValue);
+ }
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types, if the specified object does
+ * not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void unableToSetNullForKey(Object anObject, String aKey) {
+ throw new WotonomyException("Tried to key on object to null: " + aKey + " : " + anObject);
+ }
+ }
public class Null {
public Null() {
@@ -406,26 +325,19 @@ public interface NSKeyValueCoding
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/07 02:43:56 chochos
- * added NullValue, which points to a Null instance.
+ * Revision 1.3 2003/08/07 02:43:56 chochos added NullValue, which points to a
+ * Null instance.
*
- * Revision 1.2 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.2 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.1 2003/01/17 14:40:49 mpowers
- * Adding files to fix build.
+ * Revision 1.1 2003/01/17 14:40:49 mpowers Adding files to fix build.
*
- * Revision 1.2 2001/03/28 16:12:30 mpowers
- * Documented interface.
+ * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface.
*
- * Revision 1.1 2001/03/27 23:25:05 mpowers
- * Contributing interface, no docs yet.
+ * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java
index 785facd..39428ad 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java
@@ -22,192 +22,161 @@ import java.util.List;
import java.util.Map;
/**
-* NSKeyValueCodingAdditions defines an interface for classes
-* that need to have more control over the wotonomy's bulk
-* property copying and cloning facilities. <br><br>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface NSKeyValueCodingAdditions extends NSKeyValueCoding
-{
- /**
- * Returns the value for the specified key path, which is
- * a series of keys delimited by ".", for example:
- * "createTime.year.length".
- */
- Object valueForKeyPath( String aKeyPath );
-
- /**
- * Sets the value for the specified key path, which is
- * a series of keys delimited by ".", for example:
- * "createTime.year.length".
- * The value is set for the last object referenced by
- * the key path.
- */
- void takeValueForKeyPath( Object aValue, String aKeyPath );
-
- /**
- * Returns a Map of the specified keys to their values,
- * each of which might be obtained by calling valueForKey.
- */
- NSDictionary valuesForKeys( List aKeyList );
-
- /**
- * Takes the keys from the specified map as properties
- * and applies the corresponding values, each of which
- * might be set by calling takeValueForKey.
- */
- void takeValuesFromDictionary( Map aMap );
-
-
- /**
- * Static utility methods that
- * call the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public class Utility
- {
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static void takeValuesFromDictionary(
- Object object, Map dictionary)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- ((NSKeyValueCodingAdditions)object).takeValuesFromDictionary(dictionary);
- } else {
- DefaultImplementation.takeValuesFromDictionary(object, dictionary);
- }
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static void takeValueForKeyPath(
- Object object, Object aValue, String aKeyPath)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- ((NSKeyValueCodingAdditions)object).takeValueForKeyPath(aValue, aKeyPath);
- } else {
- DefaultImplementation.takeValueForKeyPath(object, aValue, aKeyPath);
- }
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static NSDictionary valuesForKeys(
- Object object, List keys)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- return ((NSKeyValueCodingAdditions)object).valuesForKeys(keys);
- } else {
- return DefaultImplementation.valuesForKeys(object, keys);
- }
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static Object valueForKeyPath(
- Object object, String aKeyPath)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- return ((NSKeyValueCodingAdditions)object).valueForKeyPath(aKeyPath);
- } else {
- return DefaultImplementation.valueForKeyPath(object, aKeyPath);
- }
- }
- }
-
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public class DefaultImplementation
- {
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public static void takeValuesFromDictionary(
- Object object, Map dictionary)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public static void takeValueForKeyPath(
- Object object, Object aValue, String aKeyPath)
- {
- // currently, NSKeyValueCoding.takeValueForKey accepts paths
- NSKeyValueCoding.DefaultImplementation.takeValueForKey( object, aValue, aKeyPath );
- }
-
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public static NSDictionary valuesForKeys(
- Object object, List keys)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public static Object valueForKeyPath(
- Object object, String aKeyPath)
- {
- // currently, NSKeyValueCoding.valueForKey accepts paths
- return NSKeyValueCoding.DefaultImplementation.valueForKey( object, aKeyPath );
- }
- }
+ * NSKeyValueCodingAdditions defines an interface for classes that need to have
+ * more control over the wotonomy's bulk property copying and cloning
+ * facilities. <br>
+ * <br>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface NSKeyValueCodingAdditions extends NSKeyValueCoding {
+ /**
+ * Returns the value for the specified key path, which is a series of keys
+ * delimited by ".", for example: "createTime.year.length".
+ */
+ Object valueForKeyPath(String aKeyPath);
+
+ /**
+ * Sets the value for the specified key path, which is a series of keys
+ * delimited by ".", for example: "createTime.year.length". The value is set for
+ * the last object referenced by the key path.
+ */
+ void takeValueForKeyPath(Object aValue, String aKeyPath);
+
+ /**
+ * Returns a Map of the specified keys to their values, each of which might be
+ * obtained by calling valueForKey.
+ */
+ NSDictionary valuesForKeys(List aKeyList);
+
+ /**
+ * Takes the keys from the specified map as properties and applies the
+ * corresponding values, each of which might be set by calling takeValueForKey.
+ */
+ void takeValuesFromDictionary(Map aMap);
+
+ /**
+ * Static utility methods that call the appropriate method if the object
+ * implements NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public class Utility {
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static void takeValuesFromDictionary(Object object, Map dictionary) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ ((NSKeyValueCodingAdditions) object).takeValuesFromDictionary(dictionary);
+ } else {
+ DefaultImplementation.takeValuesFromDictionary(object, dictionary);
+ }
+ }
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static void takeValueForKeyPath(Object object, Object aValue, String aKeyPath) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ ((NSKeyValueCodingAdditions) object).takeValueForKeyPath(aValue, aKeyPath);
+ } else {
+ DefaultImplementation.takeValueForKeyPath(object, aValue, aKeyPath);
+ }
+ }
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static NSDictionary valuesForKeys(Object object, List keys) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ return ((NSKeyValueCodingAdditions) object).valuesForKeys(keys);
+ } else {
+ return DefaultImplementation.valuesForKeys(object, keys);
+ }
+ }
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static Object valueForKeyPath(Object object, String aKeyPath) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ return ((NSKeyValueCodingAdditions) object).valueForKeyPath(aKeyPath);
+ } else {
+ return DefaultImplementation.valueForKeyPath(object, aKeyPath);
+ }
+ }
+ }
+
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public class DefaultImplementation {
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public static void takeValuesFromDictionary(Object object, Map dictionary) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public static void takeValueForKeyPath(Object object, Object aValue, String aKeyPath) {
+ // currently, NSKeyValueCoding.takeValueForKey accepts paths
+ NSKeyValueCoding.DefaultImplementation.takeValueForKey(object, aValue, aKeyPath);
+ }
+
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public static NSDictionary valuesForKeys(Object object, List keys) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public static Object valueForKeyPath(Object object, String aKeyPath) {
+ // currently, NSKeyValueCoding.valueForKey accepts paths
+ return NSKeyValueCoding.DefaultImplementation.valueForKey(object, aKeyPath);
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.2 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.1 2003/01/17 14:40:49 mpowers
- * Adding files to fix build.
+ * Revision 1.1 2003/01/17 14:40:49 mpowers Adding files to fix build.
*
- * Revision 1.3 2001/12/10 15:25:11 mpowers
- * Now properly extending NSKeyValueCoding.
+ * Revision 1.3 2001/12/10 15:25:11 mpowers Now properly extending
+ * NSKeyValueCoding.
*
- * Revision 1.2 2001/04/28 14:12:23 mpowers
- * Refactored cloning/copying into KeyValueCodingUtilities.
+ * Revision 1.2 2001/04/28 14:12:23 mpowers Refactored cloning/copying into
+ * KeyValueCodingUtilities.
*
- * Revision 1.1 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.1 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
- * Revision 1.2 2001/03/28 16:12:30 mpowers
- * Documented interface.
+ * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface.
*
- * Revision 1.1 2001/03/27 23:25:05 mpowers
- * Contributing interface, no docs yet.
+ * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java
index a947896..8fa4646 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java
@@ -25,204 +25,154 @@ import net.wotonomy.foundation.internal.NullPrimitiveException;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* NSKeyValueCodingSupport defines default behavior for
-* classes implementing NSKeyValueSupport. <br><br>
-*
-* On an object that does not implement NSKeyValueCoding,
-* wotonomy will call the methods on this class directly.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
-public class NSKeyValueCodingSupport
-{
- /**
- * Returns the value for the specified property key
- * on the specified object. <br><br>
- *
- * If the property does not exist, this method calls
- * handleQueryWithUnboundKey on the object if it
- * implements NSKeyValueCoding, otherwise calls
- * handleQueryWithUnboundKey on this class. <br><br>
- */
- static public Object valueForKey(
- Object anObject, String aKey )
- {
- //TODO: may need to handle "." nesting here so
- // that handleQueryWithUnboundKey gets called for
- // for the nested object, not the parent object
-
- //Correction: need to handle key paths in
- // KeyValueCodingAdditionsSupport.
-
- try
- {
- return Introspector.get( anObject, aKey );
- }
- catch ( IntrospectorException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
- }
- return handleQueryWithUnboundKey( anObject, aKey );
- }
- }
-
- /**
- * Sets the property to the specified value on
- * the specified object.
- *
- * If the property does not exist, this method calls
- * handleTakeValueForUnboundKey on the object if it
- * implements NSKeyValueCoding, otherwise calls
- * handleTakeValueForUnboundKey on this class.
- *
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey
- * on the object if it implements NSKeyValueCoding,
- * otherwise calls unableToSetNullForKey on this class.
- */
- static public void takeValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- //TODO: may need to handle "." nesting here so
- // that handleTakeValueForUnboundKey gets called for
- // for the nested object, not the parent object
-
- try
- {
- Introspector.set( anObject, aKey, aValue );
- }
- catch ( NullPrimitiveException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey );
- }
- else
- {
- unableToSetNullForKey( anObject, aKey );
- }
- }
- catch ( MissingPropertyException exc )
- {
- if ( anObject instanceof NSKeyValueCoding )
- {
- ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey(
- aValue, aKey );
- }
- else
- {
- handleTakeValueForUnboundKey( anObject, aValue, aKey );
- }
- }
-
- }
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property on
- * the specified object.
- *
- * This implementation currently calls valueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public Object storedValueForKey(
- Object anObject, String aKey )
- {
- //TODO: this currently just calls valueForKey
- return valueForKey( anObject, aKey );
- }
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value on the
- * specified object.
- *
- * This implementation currently calls takeValueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public void takeStoredValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- //TODO: this currently just calls takeValueForKey
- takeValueForKey( anObject, aValue, aKey );
- }
-
- /**
- * Called by valueForKey when the specified key is
- * not found on the specified object, if that object
- * does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public Object handleQueryWithUnboundKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object: "
- + aKey + " : " + anObject );
- }
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on the specified object, if that object
- * does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void handleTakeValueForUnboundKey(
- Object anObject, Object aValue, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object while setting value: "
- + aKey + " : " + anObject + " : " + aValue );
- }
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types, if the specified
- * object does not implement NSKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void unableToSetNullForKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Tried to key on object to null: "
- + aKey + " : " + anObject );
- }
+ * NSKeyValueCodingSupport defines default behavior for classes implementing
+ * NSKeyValueSupport. <br>
+ * <br>
+ *
+ * On an object that does not implement NSKeyValueCoding, wotonomy will call the
+ * methods on this class directly.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
+public class NSKeyValueCodingSupport {
+ /**
+ * Returns the value for the specified property key on the specified object.
+ * <br>
+ * <br>
+ *
+ * If the property does not exist, this method calls handleQueryWithUnboundKey
+ * on the object if it implements NSKeyValueCoding, otherwise calls
+ * handleQueryWithUnboundKey on this class. <br>
+ * <br>
+ */
+ static public Object valueForKey(Object anObject, String aKey) {
+ // TODO: may need to handle "." nesting here so
+ // that handleQueryWithUnboundKey gets called for
+ // for the nested object, not the parent object
+
+ // Correction: need to handle key paths in
+ // KeyValueCodingAdditionsSupport.
+
+ try {
+ return Introspector.get(anObject, aKey);
+ } catch (IntrospectorException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey);
+ }
+ return handleQueryWithUnboundKey(anObject, aKey);
+ }
+ }
+
+ /**
+ * Sets the property to the specified value on the specified object.
+ *
+ * If the property does not exist, this method calls
+ * handleTakeValueForUnboundKey on the object if it implements NSKeyValueCoding,
+ * otherwise calls handleTakeValueForUnboundKey on this class.
+ *
+ * If the property is of a type that cannot allow null (e.g. primitive types)
+ * and aValue is null, this method should call unableToSetNullForKey on the
+ * object if it implements NSKeyValueCoding, otherwise calls
+ * unableToSetNullForKey on this class.
+ */
+ static public void takeValueForKey(Object anObject, Object aValue, String aKey) {
+ // TODO: may need to handle "." nesting here so
+ // that handleTakeValueForUnboundKey gets called for
+ // for the nested object, not the parent object
+
+ try {
+ Introspector.set(anObject, aKey, aValue);
+ } catch (NullPrimitiveException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey);
+ } else {
+ unableToSetNullForKey(anObject, aKey);
+ }
+ } catch (MissingPropertyException exc) {
+ if (anObject instanceof NSKeyValueCoding) {
+ ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey);
+ } else {
+ handleTakeValueForUnboundKey(anObject, aValue, aKey);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property on the specified object.
+ *
+ * This implementation currently calls valueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public Object storedValueForKey(Object anObject, String aKey) {
+ // TODO: this currently just calls valueForKey
+ return valueForKey(anObject, aKey);
+ }
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value on the specified object.
+ *
+ * This implementation currently calls takeValueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) {
+ // TODO: this currently just calls takeValueForKey
+ takeValueForKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Called by valueForKey when the specified key is not found on the specified
+ * object, if that object does not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public Object handleQueryWithUnboundKey(Object anObject, String aKey) {
+ throw new WotonomyException("Key not found for object: " + aKey + " : " + anObject);
+ }
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on the
+ * specified object, if that object does not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) {
+ throw new WotonomyException(
+ "Key not found for object while setting value: " + aKey + " : " + anObject + " : " + aValue);
+ }
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types, if the specified object does
+ * not implement NSKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void unableToSetNullForKey(Object anObject, String aKey) {
+ throw new WotonomyException("Tried to key on object to null: " + aKey + " : " + anObject);
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/17 14:40:50 mpowers
- * Adding files to fix build.
+ * Revision 1.1 2003/01/17 14:40:50 mpowers Adding files to fix build.
*
- * Revision 1.4 2001/05/18 21:04:33 mpowers
- * Reimplemented EditingContext.initializeObject.
+ * Revision 1.4 2001/05/18 21:04:33 mpowers Reimplemented
+ * EditingContext.initializeObject.
*
- * Revision 1.3 2001/04/27 00:28:29 mpowers
- * Fixed a return value.
+ * Revision 1.3 2001/04/27 00:28:29 mpowers Fixed a return value.
*
- * Revision 1.2 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.2 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.1 2001/03/28 17:49:33 mpowers
- * Implemented NSKeyValueCodingSupport.
+ * Revision 1.1 2001/03/28 17:49:33 mpowers Implemented NSKeyValueCodingSupport.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java
index e6a5147..45afdde 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java
@@ -24,85 +24,78 @@ package net.wotonomy.foundation;
import EDU.oswego.cs.dl.util.concurrent.Mutex;
/**
-* A simple mutually-exclusive lock. Currently an API-compliance
-* subclass of an external Mutex class, conforming to the API and
-* behavior of com.webobjects.foundation.NSLock. This class implements
-* the NSLocking protocol (interface), and is implemented using
-* Doug Lea's concurrent programming package.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*
-*/
+ * A simple mutually-exclusive lock. Currently an API-compliance subclass of an
+ * external Mutex class, conforming to the API and behavior of
+ * com.webobjects.foundation.NSLock. This class implements the NSLocking
+ * protocol (interface), and is implemented using Doug Lea's concurrent
+ * programming package.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ *
+ */
public class NSLock extends Mutex implements NSLocking {
-
- public NSLock() {
- }
-
- public synchronized void lock() {
- try {
- acquire();
- } catch (InterruptedException interruptedexception) {
- notify();
- }
- }
-
- public synchronized void unlock() {
- release();
- }
-
- public synchronized boolean tryLock() {
- return tryLock(0);
- }
-
- public synchronized boolean tryLock(long l) {
- try {
- return attempt(l);
- } catch (InterruptedException interruptedexception) {
- notify();
- return false;
- }
- }
-
- public boolean tryLock(NSTimestamp nstimestamp) {
- return tryLock(nstimestamp.getTime() - System.currentTimeMillis());
- }
-
- public String toString() {
+ public NSLock() {
+ }
+
+ public synchronized void lock() {
+ try {
+ acquire();
+ } catch (InterruptedException interruptedexception) {
+ notify();
+ }
+ }
+
+ public synchronized void unlock() {
+ release();
+ }
+
+ public synchronized boolean tryLock() {
+ return tryLock(0);
+ }
+
+ public synchronized boolean tryLock(long l) {
+ try {
+ return attempt(l);
+ } catch (InterruptedException interruptedexception) {
+ notify();
+ return false;
+ }
+ }
+
+ public boolean tryLock(NSTimestamp nstimestamp) {
+ return tryLock(nstimestamp.getTime() - System.currentTimeMillis());
+ }
+
+ public String toString() {
return getClass().getName() + " <" + (inuse_ ? "Locked" : "Unlocked") + ">";
- }
+ }
- public synchronized boolean isLocked() {
+ public synchronized boolean isLocked() {
return inuse_;
- }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.4 2002/06/25 19:03:02 cgruber
- * Internal documentation fixes.
+ * Revision 1.4 2002/06/25 19:03:02 cgruber Internal documentation fixes.
*
- * Revision 1.3 2002/06/25 18:52:56 cgruber
- * Fix javadocs that resulted from bad cut-and-paste of the
- * boilerplate.
+ * Revision 1.3 2002/06/25 18:52:56 cgruber Fix javadocs that resulted from bad
+ * cut-and-paste of the boilerplate.
*
- * Revision 1.2 2002/06/25 17:45:52 cgruber
- * Add implementation of NSLock using Doug Lea's concurrent
- * programming APIs.
+ * Revision 1.2 2002/06/25 17:45:52 cgruber Add implementation of NSLock using
+ * Doug Lea's concurrent programming APIs.
*
- * Revision 1.1 2002/06/25 07:52:57 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All
- * API consistent with WebObjects, but with no implementation, nor
- * any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java
index f8c8ff4..d5925b5 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java
@@ -22,38 +22,35 @@ $Id: NSLocking.java 892 2006-02-16 12:47:16Z cgruber $
package net.wotonomy.foundation;
/**
-* Defines a simple locking protocol. Very course-grain locking.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
+ * Defines a simple locking protocol. Very course-grain locking.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
public interface NSLocking {
- public static final long OneSecond = 1000L;
- public static final long OneMinute = 60000L;
- public static final long OneHour = 0x36ee80L;
- public static final long OneDay = 0x5265c00L;
- public static final long OneWeek = 0x240c8400L;
- public static final long OneYear = 0x758f0dfc0L;
- public static final long OneCentury = 0x2debe176700L;
+ public static final long OneSecond = 1000L;
+ public static final long OneMinute = 60000L;
+ public static final long OneHour = 0x36ee80L;
+ public static final long OneDay = 0x5265c00L;
+ public static final long OneWeek = 0x240c8400L;
+ public static final long OneYear = 0x758f0dfc0L;
+ public static final long OneCentury = 0x2debe176700L;
- public abstract void lock();
+ public abstract void lock();
- public abstract void unlock();
+ public abstract void unlock();
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.2 2002/06/21 22:11:19 cgruber
- * Add a log trail
+ * Revision 1.2 2002/06/21 22:11:19 cgruber Add a log trail
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java
index 52e4090..b447bd3 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java
@@ -24,466 +24,399 @@ import java.io.PrintStream;
import java.util.Date;
/**
-* NSLog is foundation's built-in logging facility: IMPLEMENTED, BUT NOT TESTED.
-* By default, all groups are enabled, and debug level is DebugLevelOff.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSLog
-{
- public static long DebugGroupApplicationGeneration = 1L << 3;
- public static long DebugGroupArchiving = 1L << 6;
- public static long DebugGroupAssociations = 1L << 19;
- public static long DebugGroupComponentBindings = 1L << 9;
- public static long DebugGroupControllers = 1L << 20;
- public static long DebugGroupComponents = 1L << 26;
- public static long DebugGroupDatabaseAccess = 1L << 16;
- public static long DebugGroupDeployment = 1L << 22;
- public static long DebugGroupEnterpriseObjects = 1L << 1;
- public static long DebugGroupFormatting = 1L << 10;
- public static long DebugGroupIO = 1L << 13;
- public static long DebugGroupJSPServlets = 1L << 27;
- public static long DebugGroupKeyValueCoding = 1L << 8;
- public static long DebugGroupModel = 1L << 15;
- public static long DebugGroupMultithreading = 1L << 4;
- public static long DebugGroupParsing = 1L << 23;
- public static long DebugGroupQualifiers = 1L << 11;
- public static long DebugGroupReflection = 1L << 24;
- public static long DebugGroupRequestHandling = 1L << 25;
- public static long DebugGroupResources = 1L << 5;
- public static long DebugGroupRules = 1L << 21;
- public static long DebugGroupSQLGeneration = 1L << 17;
- public static long DebugGroupTiming = 1L << 14;
- public static long DebugGroupUserInterface = 1L << 18;
- public static long DebugGroupValidation = 1L << 7;
- public static long DebugGroupWebObjects = 1L << 2;
- public static long DebugGroupWebServices = 1L << 2;
-
- public static int DebugLevelOff = 0;
- public static int DebugLevelCritical = 1;
- public static int DebugLevelInformational = 2;
- public static int DebugLevelDetailed = 3;
-
- /**
- * The logger to which debug statements should be
- * conditionally written. By default, these messages
- * appear on the standard error stream.
- */
- public static Logger debug;
-
- /**
- * The logger to which error messages should be written,
- * which may not always be user-visible. By default,
- * these messages appear on the standard error stream.
- */
- public static Logger err;
-
- /**
- * The logger to which user-visible messages should be written.
- * By default, these messages appear on the standard output stream.
- */
- public static Logger out;
-
- private static long allowedGroups;
- private static int allowedLevel;
-
- static
- {
- debug = new PrintStreamLogger( System.err );
- err = new PrintStreamLogger( System.err );
- out = new PrintStreamLogger( System.out );
-
- //TODO: need to initialize the debug level and groups based
- // on the value of the NSDebugLevel and NSDebugGroup properties
- allowedGroups = Long.MAX_VALUE;
- allowedLevel = 0;
- }
-
- /**
- * Adds the specified group masks to those allowed for logging.
- */
- public static void allowDebugLoggingForGroups(long aDebugGroups)
- {
- allowedGroups = allowedGroups | aDebugGroups;
- }
-
- /**
- * Returns the current logging debug level.
- */
- public static int allowedDebugLevel()
- {
- return allowedLevel;
- }
-
- /**
- * Returns whether logging is allowed for the specified groups masks.
- */
- public static boolean debugLoggingAllowedForGroups(long aDebugGroups)
- {
- return ( allowedGroups == ( allowedGroups | aDebugGroups ) );
- }
-
- /**
- * Returns whether logging is allowed for the specified level.
- */
- public static boolean debugLoggingAllowedForLevel(int aDebugLevel)
- {
- return ( allowedLevel >= aDebugLevel );
- }
-
- /**
- * Returns whether logging allowed for the specified groups masks
- * at the specified level. Convenience method.
- */
- public static boolean debugLoggingAllowedForLevelAndGroups(int aDebugLevel,
- long aDebugGroups)
- {
- return ( ( allowedLevel >= aDebugLevel )
- && ( allowedGroups == ( allowedGroups | aDebugGroups ) ) );
- }
-
- /**
- * Convenience to obtain a java PrintStream for the specified file path.
- * Returns null if the stream could not be created.
- */
- public static PrintStream printStreamForPath(String aPath)
- {
- try
- {
- return new PrintStream( new FileOutputStream( aPath ) );
- }
- catch ( Throwable t )
- {
- }
- return null;
- }
-
- /**
- * Removes the specified group masks from those allowed for logging.
- */
- public static void refuseDebugLoggingForGroups(long aDebugGroups)
- {
- allowedGroups = ( allowedGroups | aDebugGroups ) ^ aDebugGroups;
- }
-
- /**
- * Sets the allowed groups to only those specified by the mask.
- */
- public static void setAllowedDebugGroups(long aDebugGroups)
- {
- allowedGroups = aDebugGroups;
- }
-
- /**
- * Sets the current debug level.
- */
- public static void setAllowedDebugLevel(int aDebugLevel)
- {
- allowedLevel = aDebugLevel;
- }
-
- /**
- * Sets the current debug logger.
- * Does nothing if logger is null.
- */
- public static void setDebug(NSLog.Logger logger)
- {
- if ( logger != null )
- {
- debug = logger;
- }
- }
-
- /**
- * Sets the current error logger.
- * Does nothing if logger is null.
- */
- public static void setErr(NSLog.Logger logger)
- {
- if ( logger != null )
- {
- err = logger;
- }
- }
-
- /**
- * Sets the current output logger.
- * Does nothing if logger is null.
- */
- public static void setOut(NSLog.Logger logger)
- {
- if ( logger != null )
- {
- out = logger;
- }
- }
-
- /**
- * Convenience to write the throwable's stack trace
- * to a string.
- */
- public static String throwableAsString(Throwable t)
- {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- PrintStream ps = new PrintStream( os );
- t.printStackTrace( ps );
- return os.toString();
- }
-
- /**
- * The abstract superclass of all Logger implementations.
- */
- static abstract public class Logger
- {
- private boolean enabled;
- private boolean verbose;
-
- /**
- * Default constructor sets enabled
- * and verbose to true.
- */
- public Logger()
- {
- enabled = true;
- verbose = true;
- }
-
- /**
- * Convenience to append a Boolean.
- */
- public void appendln(boolean aValue)
- {
- appendln( new Boolean( aValue ) );
- }
-
- /**
- * Convenience to append a Byte.
- */
- public void appendln(byte aValue)
- {
- appendln( new Byte( aValue ) );
- }
-
- /**
- * Convenience to write a String
- * comprised of the byte array using
- * the default encoding.
- */
- public void appendln(byte[] aValue)
- {
- appendln( new String( aValue ) );
- }
-
- /**
- * Convenience to append a Character.
- */
- public void appendln(char aValue)
- {
- appendln( new Character( aValue ) );
- }
-
- /**
- * Convenience to append a String
- * comprised of the character array.
- */
- public void appendln(char[] aValue)
- {
- appendln( new String( aValue ) );
- }
-
- /**
- * Convenience to append a Double.
- */
- public void appendln(double aValue)
- {
- appendln( new Double( aValue ) );
- }
-
- /**
- * Convenience to append a Float.
- */
- public void appendln(float aValue)
- {
- appendln( new Float( aValue ) );
- }
-
- /**
- * Convenience to append a Integer.
- */
- public void appendln(int aValue)
- {
- appendln( new Integer( aValue ) );
- }
-
- /**
- * Convenience to append a Long.
- */
- public void appendln(long aValue)
- {
- appendln( new Long( aValue ) );
- }
-
- /**
- * Convenience to append a Short
- */
- public void appendln(short aValue)
- {
- appendln( new Short( aValue ) );
- }
-
- /**
- * Convenience to append a Throwable.
- */
- public void appendln(Throwable aValue)
- {
- appendln( NSLog.throwableAsString( aValue ) );
- }
-
- /**
- * Writes the object to the log.
- */
- public abstract void appendln(Object aValue);
-
- /**
- * Appends a line to the log.
- */
- public abstract void appendln();
-
- /**
- * Flushes any buffered output to the log.
- */
- public abstract void flush();
-
- /**
- * Returns whether the logger is enabled,
- * the meaning of which is defined by the
- * implementing class.
- */
- public boolean isEnabled()
- {
- return enabled;
- }
-
- /**
- * Returns whether the logger is verbose,
- * the meaning of which is defined by the
- * implementing class.
- */
- public boolean isVerbose()
- {
- return verbose;
- }
-
- /**
- * Sets whether the logger is enabled,
- * the meaning of which is defined by the
- * implementing class.
- */
- public void setIsEnabled(boolean aBool)
- {
- enabled = aBool;
- }
-
- /**
- * Sets whether the logger is verbose,
- * the meaning of which is defined by the
- * implementing class.
- */
- public void setIsVerbose(boolean aBool)
- {
- verbose = aBool;
- }
- }
-
- /**
- * The default implementation of Logger that writes to a Java
- * PrintStream. If not enabled, no output is written.
- * If verbose, output is in format: "[time] <thread name> message".
- */
- static public class PrintStreamLogger extends Logger
- {
- private PrintStream thePrintStream;
-
- /**
- * Constructor takes a PrintStream.
- */
- public PrintStreamLogger(PrintStream ps)
- {
- thePrintStream = ps;
- }
-
- /**
- * Sends a newline to the print stream.
- */
- public void appendln()
- {
- if ( isEnabled() )
- {
- thePrintStream.println();
- }
- }
-
- /**
- * Writes the throwable to the print stream.
- */
- public void appendln(Throwable aValue)
- {
- appendln( NSLog.throwableAsString( aValue ) );
- }
-
- /**
- * Writes aValue.toString to the print stream.
- */
- public void appendln(Object aValue)
- {
- if ( isEnabled() )
- {
- if ( isVerbose() )
- {
- thePrintStream.print( '[' + new Date().toString() + "] <" +
- Thread.currentThread().getName() + "> " );
- }
- if ( aValue == null ) aValue = "null";
- thePrintStream.println( aValue.toString() );
- }
- }
-
- /**
- * Flushes the print stream.
- */
- public void flush()
- {
- thePrintStream.flush();
- }
-
- /**
- * Returns the current print stream.
- */
- public PrintStream printStream()
- {
- return thePrintStream;
- }
-
- /**
- * Replaces the current print stream.
- */
- public void setPrintStream(PrintStream aStream)
- {
- thePrintStream = aStream;
- }
- }
+ * NSLog is foundation's built-in logging facility: IMPLEMENTED, BUT NOT TESTED.
+ * By default, all groups are enabled, and debug level is DebugLevelOff.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSLog {
+ public static long DebugGroupApplicationGeneration = 1L << 3;
+ public static long DebugGroupArchiving = 1L << 6;
+ public static long DebugGroupAssociations = 1L << 19;
+ public static long DebugGroupComponentBindings = 1L << 9;
+ public static long DebugGroupControllers = 1L << 20;
+ public static long DebugGroupComponents = 1L << 26;
+ public static long DebugGroupDatabaseAccess = 1L << 16;
+ public static long DebugGroupDeployment = 1L << 22;
+ public static long DebugGroupEnterpriseObjects = 1L << 1;
+ public static long DebugGroupFormatting = 1L << 10;
+ public static long DebugGroupIO = 1L << 13;
+ public static long DebugGroupJSPServlets = 1L << 27;
+ public static long DebugGroupKeyValueCoding = 1L << 8;
+ public static long DebugGroupModel = 1L << 15;
+ public static long DebugGroupMultithreading = 1L << 4;
+ public static long DebugGroupParsing = 1L << 23;
+ public static long DebugGroupQualifiers = 1L << 11;
+ public static long DebugGroupReflection = 1L << 24;
+ public static long DebugGroupRequestHandling = 1L << 25;
+ public static long DebugGroupResources = 1L << 5;
+ public static long DebugGroupRules = 1L << 21;
+ public static long DebugGroupSQLGeneration = 1L << 17;
+ public static long DebugGroupTiming = 1L << 14;
+ public static long DebugGroupUserInterface = 1L << 18;
+ public static long DebugGroupValidation = 1L << 7;
+ public static long DebugGroupWebObjects = 1L << 2;
+ public static long DebugGroupWebServices = 1L << 2;
+
+ public static int DebugLevelOff = 0;
+ public static int DebugLevelCritical = 1;
+ public static int DebugLevelInformational = 2;
+ public static int DebugLevelDetailed = 3;
+
+ /**
+ * The logger to which debug statements should be conditionally written. By
+ * default, these messages appear on the standard error stream.
+ */
+ public static Logger debug;
+
+ /**
+ * The logger to which error messages should be written, which may not always be
+ * user-visible. By default, these messages appear on the standard error stream.
+ */
+ public static Logger err;
+
+ /**
+ * The logger to which user-visible messages should be written. By default,
+ * these messages appear on the standard output stream.
+ */
+ public static Logger out;
+
+ private static long allowedGroups;
+ private static int allowedLevel;
+
+ static {
+ debug = new PrintStreamLogger(System.err);
+ err = new PrintStreamLogger(System.err);
+ out = new PrintStreamLogger(System.out);
+
+ // TODO: need to initialize the debug level and groups based
+ // on the value of the NSDebugLevel and NSDebugGroup properties
+ allowedGroups = Long.MAX_VALUE;
+ allowedLevel = 0;
+ }
+
+ /**
+ * Adds the specified group masks to those allowed for logging.
+ */
+ public static void allowDebugLoggingForGroups(long aDebugGroups) {
+ allowedGroups = allowedGroups | aDebugGroups;
+ }
+
+ /**
+ * Returns the current logging debug level.
+ */
+ public static int allowedDebugLevel() {
+ return allowedLevel;
+ }
+
+ /**
+ * Returns whether logging is allowed for the specified groups masks.
+ */
+ public static boolean debugLoggingAllowedForGroups(long aDebugGroups) {
+ return (allowedGroups == (allowedGroups | aDebugGroups));
+ }
+
+ /**
+ * Returns whether logging is allowed for the specified level.
+ */
+ public static boolean debugLoggingAllowedForLevel(int aDebugLevel) {
+ return (allowedLevel >= aDebugLevel);
+ }
+
+ /**
+ * Returns whether logging allowed for the specified groups masks at the
+ * specified level. Convenience method.
+ */
+ public static boolean debugLoggingAllowedForLevelAndGroups(int aDebugLevel, long aDebugGroups) {
+ return ((allowedLevel >= aDebugLevel) && (allowedGroups == (allowedGroups | aDebugGroups)));
+ }
+
+ /**
+ * Convenience to obtain a java PrintStream for the specified file path. Returns
+ * null if the stream could not be created.
+ */
+ public static PrintStream printStreamForPath(String aPath) {
+ try {
+ return new PrintStream(new FileOutputStream(aPath));
+ } catch (Throwable t) {
+ }
+ return null;
+ }
+
+ /**
+ * Removes the specified group masks from those allowed for logging.
+ */
+ public static void refuseDebugLoggingForGroups(long aDebugGroups) {
+ allowedGroups = (allowedGroups | aDebugGroups) ^ aDebugGroups;
+ }
+
+ /**
+ * Sets the allowed groups to only those specified by the mask.
+ */
+ public static void setAllowedDebugGroups(long aDebugGroups) {
+ allowedGroups = aDebugGroups;
+ }
+
+ /**
+ * Sets the current debug level.
+ */
+ public static void setAllowedDebugLevel(int aDebugLevel) {
+ allowedLevel = aDebugLevel;
+ }
+
+ /**
+ * Sets the current debug logger. Does nothing if logger is null.
+ */
+ public static void setDebug(NSLog.Logger logger) {
+ if (logger != null) {
+ debug = logger;
+ }
+ }
+
+ /**
+ * Sets the current error logger. Does nothing if logger is null.
+ */
+ public static void setErr(NSLog.Logger logger) {
+ if (logger != null) {
+ err = logger;
+ }
+ }
+
+ /**
+ * Sets the current output logger. Does nothing if logger is null.
+ */
+ public static void setOut(NSLog.Logger logger) {
+ if (logger != null) {
+ out = logger;
+ }
+ }
+
+ /**
+ * Convenience to write the throwable's stack trace to a string.
+ */
+ public static String throwableAsString(Throwable t) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(os);
+ t.printStackTrace(ps);
+ return os.toString();
+ }
+
+ /**
+ * The abstract superclass of all Logger implementations.
+ */
+ static abstract public class Logger {
+ private boolean enabled;
+ private boolean verbose;
+
+ /**
+ * Default constructor sets enabled and verbose to true.
+ */
+ public Logger() {
+ enabled = true;
+ verbose = true;
+ }
+
+ /**
+ * Convenience to append a Boolean.
+ */
+ public void appendln(boolean aValue) {
+ appendln(new Boolean(aValue));
+ }
+
+ /**
+ * Convenience to append a Byte.
+ */
+ public void appendln(byte aValue) {
+ appendln(new Byte(aValue));
+ }
+
+ /**
+ * Convenience to write a String comprised of the byte array using the default
+ * encoding.
+ */
+ public void appendln(byte[] aValue) {
+ appendln(new String(aValue));
+ }
+
+ /**
+ * Convenience to append a Character.
+ */
+ public void appendln(char aValue) {
+ appendln(new Character(aValue));
+ }
+
+ /**
+ * Convenience to append a String comprised of the character array.
+ */
+ public void appendln(char[] aValue) {
+ appendln(new String(aValue));
+ }
+
+ /**
+ * Convenience to append a Double.
+ */
+ public void appendln(double aValue) {
+ appendln(new Double(aValue));
+ }
+
+ /**
+ * Convenience to append a Float.
+ */
+ public void appendln(float aValue) {
+ appendln(new Float(aValue));
+ }
+
+ /**
+ * Convenience to append a Integer.
+ */
+ public void appendln(int aValue) {
+ appendln(new Integer(aValue));
+ }
+
+ /**
+ * Convenience to append a Long.
+ */
+ public void appendln(long aValue) {
+ appendln(new Long(aValue));
+ }
+
+ /**
+ * Convenience to append a Short
+ */
+ public void appendln(short aValue) {
+ appendln(new Short(aValue));
+ }
+
+ /**
+ * Convenience to append a Throwable.
+ */
+ public void appendln(Throwable aValue) {
+ appendln(NSLog.throwableAsString(aValue));
+ }
+
+ /**
+ * Writes the object to the log.
+ */
+ public abstract void appendln(Object aValue);
+
+ /**
+ * Appends a line to the log.
+ */
+ public abstract void appendln();
+
+ /**
+ * Flushes any buffered output to the log.
+ */
+ public abstract void flush();
+
+ /**
+ * Returns whether the logger is enabled, the meaning of which is defined by the
+ * implementing class.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Returns whether the logger is verbose, the meaning of which is defined by the
+ * implementing class.
+ */
+ public boolean isVerbose() {
+ return verbose;
+ }
+
+ /**
+ * Sets whether the logger is enabled, the meaning of which is defined by the
+ * implementing class.
+ */
+ public void setIsEnabled(boolean aBool) {
+ enabled = aBool;
+ }
+
+ /**
+ * Sets whether the logger is verbose, the meaning of which is defined by the
+ * implementing class.
+ */
+ public void setIsVerbose(boolean aBool) {
+ verbose = aBool;
+ }
+ }
+
+ /**
+ * The default implementation of Logger that writes to a Java PrintStream. If
+ * not enabled, no output is written. If verbose, output is in format: "[time]
+ * <thread name> message".
+ */
+ static public class PrintStreamLogger extends Logger {
+ private PrintStream thePrintStream;
+
+ /**
+ * Constructor takes a PrintStream.
+ */
+ public PrintStreamLogger(PrintStream ps) {
+ thePrintStream = ps;
+ }
+
+ /**
+ * Sends a newline to the print stream.
+ */
+ public void appendln() {
+ if (isEnabled()) {
+ thePrintStream.println();
+ }
+ }
+
+ /**
+ * Writes the throwable to the print stream.
+ */
+ public void appendln(Throwable aValue) {
+ appendln(NSLog.throwableAsString(aValue));
+ }
+
+ /**
+ * Writes aValue.toString to the print stream.
+ */
+ public void appendln(Object aValue) {
+ if (isEnabled()) {
+ if (isVerbose()) {
+ thePrintStream.print('[' + new Date().toString() + "] <" + Thread.currentThread().getName() + "> ");
+ }
+ if (aValue == null)
+ aValue = "null";
+ thePrintStream.println(aValue.toString());
+ }
+ }
+
+ /**
+ * Flushes the print stream.
+ */
+ public void flush() {
+ thePrintStream.flush();
+ }
+
+ /**
+ * Returns the current print stream.
+ */
+ public PrintStream printStream() {
+ return thePrintStream;
+ }
+
+ /**
+ * Replaces the current print stream.
+ */
+ public void setPrintStream(PrintStream aStream) {
+ thePrintStream = aStream;
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/31 22:33:00 mpowers
- * Contributing NSLog.
+ * Revision 1.1 2003/01/31 22:33:00 mpowers Contributing NSLog.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java
index abed576..3492141 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java
@@ -24,136 +24,134 @@ package net.wotonomy.foundation;
import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
/**
-* A Read-Write lock that allows unlimited number of calling threads to
-* acquire read locks, but only one thread to acquire a write lock. It
-* is also reentrant, allowing each thread to re-acquire it's lock
-* recursively. For that reason it is somewhat slower, as there is a
-* hash lookup when attempting to acquire and release reader locks. Of
-* course a writer lock is quite a bit slower than a reader lock. A
-* write lock is mutally exclusive with read locks, though a thread
-* that has obtained a read-lock may be promoted to a write lock and
-* vice versa when conditions permit.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A Read-Write lock that allows unlimited number of calling threads to acquire
+ * read locks, but only one thread to acquire a write lock. It is also
+ * reentrant, allowing each thread to re-acquire it's lock recursively. For that
+ * reason it is somewhat slower, as there is a hash lookup when attempting to
+ * acquire and release reader locks. Of course a writer lock is quite a bit
+ * slower than a reader lock. A write lock is mutally exclusive with read locks,
+ * though a thread that has obtained a read-lock may be promoted to a write lock
+ * and vice versa when conditions permit.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class NSMultiReaderLock extends ReentrantWriterPreferenceReadWriteLock implements NSLocking {
- NSMutableDictionary _readerSuspended = new NSMutableDictionary();
-
- public NSMultiReaderLock() {
- }
-
- public void lockForReading() {
- try {
- readerLock_.acquire();
- } catch (InterruptedException interruptedexception) {
- // Null behavior, as notify() is already called
- // by acquire();
- // We may want to log here.
- }
- }
-
- public void unlockForReading() {
- readerLock_.release();
- }
-
- public void lock() {
- lockForWriting();
- }
-
- public void lockForWriting() {
- try {
- writerLock_.acquire();
- } catch (InterruptedException interruptedexception) {
- // Null behavior, as notify() is already called
- // by acquire();
- // We may want to log here.
- }
- }
-
- public void unlock() {
- unlockForWriting();
- }
-
- public void unlockForWriting() {
- writerLock_.release();
- }
-
- /** @see com.webobjects.foundation.NSMultiReaderLock#suspendReaderLock() */
- public void suspendReaderLocks() {
- Thread thisThread = Thread.currentThread();
- Integer suspendedReaders = (Integer)_readerSuspended.get(thisThread);
- if (suspendedReaders != null && suspendedReaders.intValue() > 0) return;
- // logic is to override startRead / endRead and ensure that the suspension
- // isn't improperly stopped.
+ NSMutableDictionary _readerSuspended = new NSMutableDictionary();
+
+ public NSMultiReaderLock() {
+ }
+
+ public void lockForReading() {
+ try {
+ readerLock_.acquire();
+ } catch (InterruptedException interruptedexception) {
+ // Null behavior, as notify() is already called
+ // by acquire();
+ // We may want to log here.
+ }
+ }
+
+ public void unlockForReading() {
+ readerLock_.release();
+ }
+
+ public void lock() {
+ lockForWriting();
+ }
+
+ public void lockForWriting() {
+ try {
+ writerLock_.acquire();
+ } catch (InterruptedException interruptedexception) {
+ // Null behavior, as notify() is already called
+ // by acquire();
+ // We may want to log here.
+ }
+ }
+
+ public void unlock() {
+ unlockForWriting();
+ }
+
+ public void unlockForWriting() {
+ writerLock_.release();
+ }
+
+ /** @see com.webobjects.foundation.NSMultiReaderLock#suspendReaderLock() */
+ public void suspendReaderLocks() {
+ Thread thisThread = Thread.currentThread();
+ Integer suspendedReaders = (Integer) _readerSuspended.get(thisThread);
+ if (suspendedReaders != null && suspendedReaders.intValue() > 0)
+ return;
+ // logic is to override startRead / endRead and ensure that the suspension
+ // isn't improperly stopped.
throw new UnsupportedOperationException("Not Yet Implemented");
- }
-
- /** @see com.webobjects.foundation.NSMultiReaderLock#retrieveReaderLock() */
- public void retrieveReaderLocks() {
- Thread thisThread = Thread.currentThread();
- Integer suspendedReaders = (Integer)_readerSuspended.get(thisThread);
- if (suspendedReaders != null && suspendedReaders.intValue() > 0) return;
- // logic is to override startRead / endRead and ensure that the suspension
- // isn't improperly stopped.
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
-
- public boolean tryLockForWriting() {
- try {
- return writerLock_.attempt(0);
- } catch (InterruptedException interruptedexception) {
- // notify() is already called by attempt();
- // We may want to log here.
- return false;
- }
- }
-
- public boolean tryLockForReading() {
- try {
- return readerLock_.attempt(0);
- } catch (InterruptedException interruptedexception) {
- // notify() is already called by attempt();
- // We may want to log here.
- return false;
- }
- }
-
- public String toString() {
+ }
+
+ /** @see com.webobjects.foundation.NSMultiReaderLock#retrieveReaderLock() */
+ public void retrieveReaderLocks() {
+ Thread thisThread = Thread.currentThread();
+ Integer suspendedReaders = (Integer) _readerSuspended.get(thisThread);
+ if (suspendedReaders != null && suspendedReaders.intValue() > 0)
+ return;
+ // logic is to override startRead / endRead and ensure that the suspension
+ // isn't improperly stopped.
throw new UnsupportedOperationException("Not Yet Implemented");
- }
-
- protected String _padString(long l, int i) {
+ }
+
+ public boolean tryLockForWriting() {
+ try {
+ return writerLock_.attempt(0);
+ } catch (InterruptedException interruptedexception) {
+ // notify() is already called by attempt();
+ // We may want to log here.
+ return false;
+ }
+ }
+
+ public boolean tryLockForReading() {
+ try {
+ return readerLock_.attempt(0);
+ } catch (InterruptedException interruptedexception) {
+ // notify() is already called by attempt();
+ // We may want to log here.
+ return false;
+ }
+ }
+
+ public String toString() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- protected String _padString(String s, int i, boolean flag) {
+ protected String _padString(long l, int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
+ protected String _padString(String s, int i, boolean flag) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.2 2002/06/26 00:40:22 cgruber
- * Add implementation, using ReentrantWriterPreferenceReadWriteLock
- * as a base.
+ * Revision 1.2 2002/06/26 00:40:22 cgruber Add implementation, using
+ * ReentrantWriterPreferenceReadWriteLock as a base.
*
- * suspendReaderLocks and retreiveReaderLocks is the one
- * that's likeliest to be a pain.
+ * suspendReaderLocks and retreiveReaderLocks is the one that's likeliest to be
+ * a pain.
*
- * Revision 1.1 2002/06/25 07:52:57 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java
index f705000..c75de01 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java
@@ -24,406 +24,345 @@ import java.util.List;
import java.util.ListIterator;
/**
-* NSMutableArray extends NSArray to allow modification.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSMutableArray extends NSArray
-{
- /**
- * Returns an NSArray backed by the specified List.
- * This is useful to "protect" an internal representation
- * that is returned by a method of return type NSArray.
- */
- public static NSMutableArray mutableArrayBackedByList( List aList )
- {
- return new NSMutableArray( aList, null );
- }
-
- NSMutableArray( List aList, Object ignored ) // differentiates
- {
- super( aList, ignored );
- }
-
+ * NSMutableArray extends NSArray to allow modification.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSMutableArray extends NSArray {
+ /**
+ * Returns an NSArray backed by the specified List. This is useful to "protect"
+ * an internal representation that is returned by a method of return type
+ * NSArray.
+ */
+ public static NSMutableArray mutableArrayBackedByList(List aList) {
+ return new NSMutableArray(aList, null);
+ }
+
+ NSMutableArray(List aList, Object ignored) // differentiates
+ {
+ super(aList, ignored);
+ }
+
/**
- * Default constructor returns an empty array.
- */
- public NSMutableArray ()
- {
- super();
+ * Default constructor returns an empty array.
+ */
+ public NSMutableArray() {
+ super();
//System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() );
- }
+ }
/**
- * Constructor with a size hint.
- */
- public NSMutableArray ( int aSize )
- {
- super();
+ * Constructor with a size hint.
+ */
+ public NSMutableArray(int aSize) {
+ super();
//System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() );
- }
+ }
/**
- * Produces an array containing only the specified object.
- */
- public NSMutableArray (Object anObject)
- {
- super( anObject );
+ * Produces an array containing only the specified object.
+ */
+ public NSMutableArray(Object anObject) {
+ super(anObject);
//System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() );
- }
+ }
/**
- * Produces an array containing the specified objects.
- */
- public NSMutableArray (Object[] anArray)
- {
- super( anArray );
+ * Produces an array containing the specified objects.
+ */
+ public NSMutableArray(Object[] anArray) {
+ super(anArray);
//System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() );
- }
+ }
/**
- * Produces an array containing the objects in the specified collection.
- */
- public NSMutableArray (Collection aCollection)
- {
- super( aCollection );
+ * Produces an array containing the objects in the specified collection.
+ */
+ public NSMutableArray(Collection aCollection) {
+ super(aCollection);
//System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() );
- }
+ }
/**
- * Removes the last object from the array.
- */
- public void removeLastObject ()
- {
- list.remove( count() - 1 );
- }
+ * Removes the last object from the array.
+ */
+ public void removeLastObject() {
+ list.remove(count() - 1);
+ }
/**
- * Removes the object at the specified index.
- */
- public void removeObjectAtIndex (int index)
- {
- list.remove( index );
- }
+ * Removes the object at the specified index.
+ */
+ public void removeObjectAtIndex(int index) {
+ list.remove(index);
+ }
/**
- * Adds all objects in the specified collection.
- */
- public void addObjectsFromArray (Collection aCollection)
- {
- list.addAll( aCollection );
- }
+ * Adds all objects in the specified collection.
+ */
+ public void addObjectsFromArray(Collection aCollection) {
+ list.addAll(aCollection);
+ }
/**
- * Removes all objects from the array.
- */
- public void removeAllObjects ()
- {
- list.clear();
- }
+ * Removes all objects from the array.
+ */
+ public void removeAllObjects() {
+ list.clear();
+ }
/**
- * Removes all objects equivalent to the specified object
- * within the range of specified indices.
- */
- public void removeObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( list.get( i ) ) )
- {
- list.remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all objects equivalent to the specified object within the range of
+ * specified indices.
+ */
+ public void removeObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(list.get(i))) {
+ list.remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all instances of the specified object within the
- * range of specified indices, comparing by reference.
- */
- public void removeIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == list.get( i ) )
- {
- list.remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all instances of the specified object within the range of specified
+ * indices, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == list.get(i)) {
+ list.remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all objects in the specified collection from the array.
- */
- public void removeObjectsInArray (Collection aCollection)
- {
- list.removeAll( aCollection );
- }
+ * Removes all objects in the specified collection from the array.
+ */
+ public void removeObjectsInArray(Collection aCollection) {
+ list.removeAll(aCollection);
+ }
/**
- * Removes all objects in the indices within the specified range
- * from the array.
- */
- public void removeObjectsInRange (NSRange aRange)
- {
- if ( aRange == null ) return;
-
- for ( int i = 0; i < aRange.length(); i++ )
- {
- list.remove( aRange.location() );
- }
- }
+ * Removes all objects in the indices within the specified range from the array.
+ */
+ public void removeObjectsInRange(NSRange aRange) {
+ if (aRange == null)
+ return;
+
+ for (int i = 0; i < aRange.length(); i++) {
+ list.remove(aRange.location());
+ }
+ }
/**
- * Replaces objects in the current range with objects from
- * the specified range of the specified array. If currentRange
- * is larger than otherRange, the extra objects are removed.
- * If otherRange is larger than currentRange, the extra objects
- * are added.
- */
- public void replaceObjectsInRange (NSRange currentRange,
- List otherArray, NSRange otherRange)
- {
- if ( ( currentRange == null ) || ( otherArray == null ) ||
- ( otherRange == null ) ) return;
-
+ * Replaces objects in the current range with objects from the specified range
+ * of the specified array. If currentRange is larger than otherRange, the extra
+ * objects are removed. If otherRange is larger than currentRange, the extra
+ * objects are added.
+ */
+ public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ if ((currentRange == null) || (otherArray == null) || (otherRange == null))
+ return;
+
// transform otherRange if out of bounds for array
- if ( otherRange.maxRange() > otherArray.size() )
- {
+ if (otherRange.maxRange() > otherArray.size()) {
// TODO: Test this logic.
- int loc = Math.min( otherRange.location(), otherArray.size() - 1 );
- otherRange = new NSRange( loc, otherArray.size() - loc );
+ int loc = Math.min(otherRange.location(), otherArray.size() - 1);
+ otherRange = new NSRange(loc, otherArray.size() - loc);
}
-
+
Object o;
- List subList = list.subList(
- currentRange.location(), currentRange.maxRange() );
+ List subList = list.subList(currentRange.location(), currentRange.maxRange());
int otherIndex = otherRange.location();
// TODO: Test this logic.
- for ( int i = 0; i < subList.size(); i++ )
- {
- if ( otherIndex < otherRange.maxRange() )
- { // set object
- subList.set( i, otherArray.get( otherIndex ) );
- }
- else
- { // remove extra elements from currentRange
- subList.remove( i );
- i--;
+ for (int i = 0; i < subList.size(); i++) {
+ if (otherIndex < otherRange.maxRange()) { // set object
+ subList.set(i, otherArray.get(otherIndex));
+ } else { // remove extra elements from currentRange
+ subList.remove(i);
+ i--;
}
otherIndex++;
}
// TODO: Test this logic.
- for ( int i = otherIndex; i < otherRange.maxRange(); i++ )
- {
- list.add( otherArray.get( i ) );
+ for (int i = otherIndex; i < otherRange.maxRange(); i++) {
+ list.add(otherArray.get(i));
}
}
/**
- * Clears the current array and then populates it with the
- * contents of the specified collection.
- */
- public void setArray (Collection aCollection)
- {
- list.clear();
- list.addAll( aCollection );
- }
+ * Clears the current array and then populates it with the contents of the
+ * specified collection.
+ */
+ public void setArray(Collection aCollection) {
+ list.clear();
+ list.addAll(aCollection);
+ }
/**
- * Sorts this array using the values from the specified selector.
- */
- public void sortUsingSelector (NSSelector aSelector)
- {
- //TODO: implement
- throw new UnsupportedOperationException( "Not implemented yet." );
- }
+ * Sorts this array using the values from the specified selector.
+ */
+ public void sortUsingSelector(NSSelector aSelector) {
+ // TODO: implement
+ throw new UnsupportedOperationException("Not implemented yet.");
+ }
/**
- * Removes all objects equivalent to the specified object.
- */
- public void removeObject (Object anObject)
- {
- list.remove( anObject );
- }
+ * Removes all objects equivalent to the specified object.
+ */
+ public void removeObject(Object anObject) {
+ list.remove(anObject);
+ }
/**
- * Removes all occurences of the specified object,
- * comparing by reference.
- */
- public void removeIdenticalObject (Object anObject)
- {
- Iterator it = list.iterator();
- while ( it.hasNext() )
- {
- if ( it.next() == anObject )
- {
- it.remove();
- }
- }
- }
+ * Removes all occurences of the specified object, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject) {
+ Iterator it = list.iterator();
+ while (it.hasNext()) {
+ if (it.next() == anObject) {
+ it.remove();
+ }
+ }
+ }
/**
- * Inserts the specified object into this array at the
- * specified index.
- */
- public void insertObjectAtIndex (Object anObject, int anIndex)
- {
- list.add( anIndex, anObject );
- }
-
+ * Inserts the specified object into this array at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ list.add(anIndex, anObject);
+ }
+
/**
- * Replaces the object at the specified index with the
- * specified object.
- */
- public void replaceObjectAtIndex (int anIndex, Object anObject)
- {
- list.set( anIndex, anObject );
- }
+ * Replaces the object at the specified index with the specified object.
+ */
+ public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ list.set(anIndex, anObject);
+ }
/**
- * Adds the specified object to the end of this array.
- */
- public void addObject (Object anObject)
- {
- list.add( anObject );
- }
-
- public Object clone()
- {
- return new NSMutableArray( list );
- }
-
- public NSArray immutableClone() {
- return new NSArray(this);
- }
-
- public NSMutableArray mutableClone() {
- return new NSMutableArray(this);
- }
-
- // interface List: mutators
-
- public void add(int index, Object element)
- {
- list.add( index, element );
- }
-
- public boolean add(Object o)
- {
- return list.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- return list.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- return list.addAll( index, c );
- }
-
- public void clear()
- {
- list.clear();
- }
-
- public Iterator iterator()
- {
- return list.iterator();
- }
-
- public ListIterator listIterator()
- {
- return list.listIterator();
- }
-
- public ListIterator listIterator(int index)
- {
- return list.listIterator();
- }
-
- public Object remove(int index)
- {
- return list.remove( index );
- }
-
- public boolean remove(Object o)
- {
- return list.remove(o);
- }
-
- public boolean removeAll(Collection coll)
- {
- return list.removeAll(coll);
- }
-
- public boolean retainAll(Collection coll)
- {
- return list.retainAll(coll);
- }
-
- public Object set(int index, Object element)
- {
- return list.set( index, element );
- }
-
- public List subList(int fromIndex, int toIndex)
- {
- return list.subList( fromIndex, toIndex );
- }
-
+ * Adds the specified object to the end of this array.
+ */
+ public void addObject(Object anObject) {
+ list.add(anObject);
+ }
+
+ public Object clone() {
+ return new NSMutableArray(list);
+ }
+
+ public NSArray immutableClone() {
+ return new NSArray(this);
+ }
+
+ public NSMutableArray mutableClone() {
+ return new NSMutableArray(this);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ list.add(index, element);
+ }
+
+ public boolean add(Object o) {
+ return list.add(o);
+ }
+
+ public boolean addAll(Collection coll) {
+ return list.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ return list.addAll(index, c);
+ }
+
+ public void clear() {
+ list.clear();
+ }
+
+ public Iterator iterator() {
+ return list.iterator();
+ }
+
+ public ListIterator listIterator() {
+ return list.listIterator();
+ }
+
+ public ListIterator listIterator(int index) {
+ return list.listIterator();
+ }
+
+ public Object remove(int index) {
+ return list.remove(index);
+ }
+
+ public boolean remove(Object o) {
+ return list.remove(o);
+ }
+
+ public boolean removeAll(Collection coll) {
+ return list.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll) {
+ return list.retainAll(coll);
+ }
+
+ public Object set(int index, Object element) {
+ return list.set(index, element);
+ }
+
+ public List subList(int fromIndex, int toIndex) {
+ return list.subList(fromIndex, toIndex);
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2005/07/13 14:12:44 cgruber
- * Add mutableClone() and immutableClone() per. WebObjects 5.3 conformance.
+ * Revision 1.8 2005/07/13 14:12:44 cgruber Add mutableClone() and
+ * immutableClone() per. WebObjects 5.3 conformance.
*
- * Revision 1.7 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.6 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.5 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.5 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.4 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.4 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.3 2002/10/24 18:16:30 mpowers
- * Now enforcing NSArray's immutable nature.
+ * Revision 1.3 2002/10/24 18:16:30 mpowers Now enforcing NSArray's immutable
+ * nature.
*
- * Revision 1.2 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.2 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java
index c677ea7..c24e04d 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java
@@ -19,95 +19,82 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation;
/**
-* A pure java implementation of NSMutableData, which
-* is basically an editable wrapper for a byte array.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
-public class NSMutableData
- extends NSData
-{
- /**
- * Default constructor creates a zero-data object.
- */
- public NSMutableData ()
- {
- super();
- }
-
- /**
- * Creates an object containing the contents of the specified URL.
- */
- public NSMutableData (java.net.URL aURL)
- {
- super( aURL );
- }
-
- /**
- * Creates an object containing a copy of the contents of the
- * specified NSData object.
- */
- public NSMutableData (NSData aData)
- {
- super( aData );
- }
-
- /**
- * Creates an object containing the specified number of bytes
- * initialized to all zeroes.
- */
- public NSMutableData (int size)
- {
- super( new byte[size] ); // inits to zeroes
- }
+ * A pure java implementation of NSMutableData, which is basically an editable
+ * wrapper for a byte array.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
+public class NSMutableData extends NSData {
+ /**
+ * Default constructor creates a zero-data object.
+ */
+ public NSMutableData() {
+ super();
+ }
+ /**
+ * Creates an object containing the contents of the specified URL.
+ */
+ public NSMutableData(java.net.URL aURL) {
+ super(aURL);
+ }
/**
- * Sets the length of the data to the specified length.
- * If shorter, the data is truncated. If longer, the extra
- * bytes are initialized to zeroes.
- */
- public void setLength (int length)
- {
- byte[] data = new byte[ length ]; // inits to zeroes
- int limit = length;
- if (limit > bytes.length)
- limit = bytes.length;
- for ( int i = 0; i < limit; i++ )
- {
- data[i] = this.bytes[ i ];
- }
- this.bytes = data;
- }
+ * Creates an object containing a copy of the contents of the specified NSData
+ * object.
+ */
+ public NSMutableData(NSData aData) {
+ super(aData);
+ }
/**
- * Appends the specified data to the end of this data.
- */
- public void appendData (NSData aData)
- {
- int len = aData.length();
- byte[] data = new byte[ bytes.length + len ];
-
- int i;
- for ( i = 0; i < bytes.length; i++ )
- {
- data[i] = bytes[i];
- }
-
- byte[] src = aData.bytes( 0, len );
- for ( int j = 0; j < len; j++ )
- {
- data[i+j] = src[j];
- }
-
- bytes = data;
- }
+ * Creates an object containing the specified number of bytes initialized to all
+ * zeroes.
+ */
+ public NSMutableData(int size) {
+ super(new byte[size]); // inits to zeroes
+ }
+
+ /**
+ * Sets the length of the data to the specified length. If shorter, the data is
+ * truncated. If longer, the extra bytes are initialized to zeroes.
+ */
+ public void setLength(int length) {
+ byte[] data = new byte[length]; // inits to zeroes
+ int limit = length;
+ if (limit > bytes.length)
+ limit = bytes.length;
+ for (int i = 0; i < limit; i++) {
+ data[i] = this.bytes[i];
+ }
+ this.bytes = data;
+ }
+
+ /**
+ * Appends the specified data to the end of this data.
+ */
+ public void appendData(NSData aData) {
+ int len = aData.length();
+ byte[] data = new byte[bytes.length + len];
+
+ int i;
+ for (i = 0; i < bytes.length; i++) {
+ data[i] = bytes[i];
+ }
+
+ byte[] src = aData.bytes(0, len);
+ for (int j = 0; j < len; j++) {
+ data[i + j] = src[j];
+ }
+
+ bytes = data;
+ }
public void appendByte(byte b) {
setLength(bytes.length + 1);
- bytes[bytes.length-1] = b;
+ bytes[bytes.length - 1] = b;
}
public void appendBytes(byte[] b) {
@@ -118,50 +105,41 @@ public class NSMutableData
}
/**
- * Increases the size of the byte array by the specified amount.
- */
- public void increaseLengthBy (int increment)
- {
- setLength( length() + increment );
- }
+ * Increases the size of the byte array by the specified amount.
+ */
+ public void increaseLengthBy(int increment) {
+ setLength(length() + increment);
+ }
/**
- * Sets the bytes in the array within the specified range to zero.
- */
- public void resetBytesInRange (NSRange aRange)
- {
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- bytes[i] = 0;
- }
- }
+ * Sets the bytes in the array within the specified range to zero.
+ */
+ public void resetBytesInRange(NSRange aRange) {
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ bytes[i] = 0;
+ }
+ }
/**
- * Copies the data in the specified object to this object,
- * completely replacing the previous contents.
- */
- public void setData (NSData aData)
- {
- bytes = aData.bytes( 0, aData.length() );
- }
+ * Copies the data in the specified object to this object, completely replacing
+ * the previous contents.
+ */
+ public void setData(NSData aData) {
+ bytes = aData.bytes(0, aData.length());
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:57:13 chochos
- * appendByte(), appendBytes()
+ * Revision 1.2 2003/08/06 23:57:13 chochos appendByte(), appendBytes()
*
- * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java
index 0b291a7..ba58189 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java
@@ -22,145 +22,122 @@ import java.util.Enumeration;
import java.util.Map;
/**
-* A pure java implementation of NSMutableDictionary that
-* implements Map for greater java interoperability.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSMutableDictionary
- extends NSDictionary
-{
- /**
- * Default constructor produces an empty dictionary.
- */
- public NSMutableDictionary ()
- {
- super();
- }
-
- /**
- * Default constructor produces an empty dictionary.
- */
- public NSMutableDictionary (int initialSize)
- {
- super(initialSize);
- }
-
- /**
- * Produces a dictionary that contains one key referencing one value.
- */
- public NSMutableDictionary (Object key, Object value)
- {
- super( key, value );
- }
-
- /**
- * Produces a dictionary containing the specified keys and values.
- * An IllegalArgumentException is thrown if the arrays are not
- * of the same length.
- */
- public NSMutableDictionary (Object[] keys, Object[] values)
- {
- super( keys, values );
+ * A pure java implementation of NSMutableDictionary that implements Map for
+ * greater java interoperability.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSMutableDictionary extends NSDictionary {
+ /**
+ * Default constructor produces an empty dictionary.
+ */
+ public NSMutableDictionary() {
+ super();
+ }
+
+ /**
+ * Default constructor produces an empty dictionary.
+ */
+ public NSMutableDictionary(int initialSize) {
+ super(initialSize);
+ }
+
+ /**
+ * Produces a dictionary that contains one key referencing one value.
+ */
+ public NSMutableDictionary(Object key, Object value) {
+ super(key, value);
+ }
+
+ /**
+ * Produces a dictionary containing the specified keys and values. An
+ * IllegalArgumentException is thrown if the arrays are not of the same length.
+ */
+ public NSMutableDictionary(Object[] keys, Object[] values) {
+ super(keys, values);
}
- /**
- * Produces a dictionary that is a copy of the specified map (or dictionary).
- */
- public NSMutableDictionary (Map aMap)
- {
- super( aMap );
- }
-
- /**
- * Removes the key-value pair for the specified key.
- */
- public void removeObjectForKey (Object aKey)
- {
- remove( aKey );
- }
-
- /**
- * Copies all mappings from the specified dictionary to this dictionary,
- * replacing any mappings this map had for any keys in the specified map.
- */
- public void addEntriesFromDictionary (Map aMap)
- {
- putAll( aMap );
- }
-
- /**
- * Removes all mappings from this dictionary.
- */
- public void removeAllObjects ()
- {
- clear();
- }
-
- /**
- * Removes all keys in the specified array from this dictionary.
- */
- public void removeObjectsForKeys (NSArray anArray)
- {
- Enumeration enumeration = anArray.objectEnumerator();
- while ( enumeration.hasMoreElements() )
- {
- removeObjectForKey( enumeration.nextElement() );
- }
- }
-
- /**
- * Clears all mappings in this dictionary and then adds all entries
- * in the specified dictionary.
- */
- public void setDictionary (Map aMap)
- {
- removeAllObjects();
- addEntriesFromDictionary( aMap );
- }
-
- /**
- * Sets the value for the specified key. If the key currently
- * exists to the dictionary, the old value is replaced with the
- * specified value. An IllegalArgumentException is thrown if
- * either the key or value is null.
- */
- public void setObjectForKey (Object aValue, Object aKey)
- {
- if ( ( aKey == null ) || ( aValue == null ) )
- {
- throw new IllegalArgumentException(
- "Cannot use null objects with an NSMutableDictionary." );
- }
- put( aKey, aValue );
- }
+ /**
+ * Produces a dictionary that is a copy of the specified map (or dictionary).
+ */
+ public NSMutableDictionary(Map aMap) {
+ super(aMap);
+ }
+
+ /**
+ * Removes the key-value pair for the specified key.
+ */
+ public void removeObjectForKey(Object aKey) {
+ remove(aKey);
+ }
+
+ /**
+ * Copies all mappings from the specified dictionary to this dictionary,
+ * replacing any mappings this map had for any keys in the specified map.
+ */
+ public void addEntriesFromDictionary(Map aMap) {
+ putAll(aMap);
+ }
+
+ /**
+ * Removes all mappings from this dictionary.
+ */
+ public void removeAllObjects() {
+ clear();
+ }
+
+ /**
+ * Removes all keys in the specified array from this dictionary.
+ */
+ public void removeObjectsForKeys(NSArray anArray) {
+ Enumeration enumeration = anArray.objectEnumerator();
+ while (enumeration.hasMoreElements()) {
+ removeObjectForKey(enumeration.nextElement());
+ }
+ }
+
+ /**
+ * Clears all mappings in this dictionary and then adds all entries in the
+ * specified dictionary.
+ */
+ public void setDictionary(Map aMap) {
+ removeAllObjects();
+ addEntriesFromDictionary(aMap);
+ }
+
+ /**
+ * Sets the value for the specified key. If the key currently exists to the
+ * dictionary, the old value is replaced with the specified value. An
+ * IllegalArgumentException is thrown if either the key or value is null.
+ */
+ public void setObjectForKey(Object aValue, Object aKey) {
+ if ((aKey == null) || (aValue == null)) {
+ throw new IllegalArgumentException("Cannot use null objects with an NSMutableDictionary.");
+ }
+ put(aKey, aValue);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.4 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.3 2002/06/30 17:16:26 mpowers
- * Added new constructor taking an int: thanks cgruber.
+ * Revision 1.3 2002/06/30 17:16:26 mpowers Added new constructor taking an int:
+ * thanks cgruber.
*
*
- * Revision 1.2 2001/02/23 23:43:41 mpowers
- * Removed ill-advised this.
+ * Revision 1.2 2001/02/23 23:43:41 mpowers Removed ill-advised this.
*
- * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java
index a0bcda1..2bfb692 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java
@@ -19,98 +19,84 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation;
/**
-* A pure java implementation of NSMutableRange.
-* An NSMutableRange is a modifiable NSRange.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSMutableRange extends NSRange
-{
- /**
- * Default constructor produces an empty range.
- */
- public NSMutableRange ()
- {
- super();
- }
+ * A pure java implementation of NSMutableRange. An NSMutableRange is a
+ * modifiable NSRange.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSMutableRange extends NSRange {
+ /**
+ * Default constructor produces an empty range.
+ */
+ public NSMutableRange() {
+ super();
+ }
- /**
- * Produces a range that has the same location and length as
- * the specified range.
- */
- public NSMutableRange (NSRange aRange)
- {
- super( aRange );
- }
+ /**
+ * Produces a range that has the same location and length as the specified
+ * range.
+ */
+ public NSMutableRange(NSRange aRange) {
+ super(aRange);
+ }
- /**
- * Produces a range with the specified location and length.
- */
- public NSMutableRange (int location, int length)
- {
- super( location, length );
- }
+ /**
+ * Produces a range with the specified location and length.
+ */
+ public NSMutableRange(int location, int length) {
+ super(location, length);
+ }
- /**
- * Sets the location of this range.
- */
- public void setLocation (int location)
- {
- loc = location;
- }
+ /**
+ * Sets the location of this range.
+ */
+ public void setLocation(int location) {
+ loc = location;
+ }
- /**
- * Sets the length of this range.
- */
- public void setLength (int length)
- {
- len = length;
- }
-
- /**
- * Modifies this range to be the union of this
- * range and the specified range.
- */
- public void unionRange (NSRange aRange)
- {
- NSRange range = rangeByUnioningRange( aRange );
- setLocation( range.location() );
- setLength( range.length() );
- }
+ /**
+ * Sets the length of this range.
+ */
+ public void setLength(int length) {
+ len = length;
+ }
- /**
- * Modifies this range to be the intersection of this
- * range and the specified range.
- */
- public void intersectRange (NSRange aRange)
- {
- NSRange range = rangeByIntersectingRange( aRange );
- setLocation( range.location() );
- setLength( range.length() );
- }
+ /**
+ * Modifies this range to be the union of this range and the specified range.
+ */
+ public void unionRange(NSRange aRange) {
+ NSRange range = rangeByUnioningRange(aRange);
+ setLocation(range.location());
+ setLength(range.length());
+ }
- /**
- * Returns a copy of this range.
- */
- public Object clone ()
- {
- return new NSMutableRange( location(), length() );
- }
+ /**
+ * Modifies this range to be the intersection of this range and the specified
+ * range.
+ */
+ public void intersectRange(NSRange aRange) {
+ NSRange range = rangeByIntersectingRange(aRange);
+ setLocation(range.location());
+ setLength(range.length());
+ }
+
+ /**
+ * Returns a copy of this range.
+ */
+ public Object clone() {
+ return new NSMutableRange(location(), length());
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java
index f288d3f..6b091e2 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java
@@ -21,144 +21,125 @@ package net.wotonomy.foundation;
import java.util.Map;
/**
-* An NSNotification is a generic message that can be
-* dispatched by the NSNotificationCenter.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSNotification
-{
- public static boolean showStack = false;
-
- protected String name;
- protected Object object;
- protected Map userInfo;
-
- // for debugging only
- private Throwable stackTrace;
-
- /**
- * Default constructor creates a new notification
- * with no name, object, or info dictionary.
- */
- public NSNotification ()
- {
- this( null, null, null );
- }
-
- /**
- * Constructor specifying name and object.
- */
- public NSNotification ( String aName, Object anObject )
- {
- this( aName, anObject, null );
- }
-
- /**
- * Constructor specifying name, object, and a Map
- * containing application specific information.
- */
- public NSNotification (
- String aName, Object anObject, Map aUserInfo )
- {
- name = aName;
- object = anObject;
- if ( showStack ) stackTrace = new RuntimeException();
- userInfo = aUserInfo;
- }
-
- /**
- * Returns the name of this notification.
- */
- public String name ()
- {
- return name;
- }
-
- /**
- * Returns the object of this notification.
- */
- public Object object ()
- {
- return object;
- }
-
- /**
- * Returns an NSDictionary that is a copy of
- * the map containing application specific
- * information relating to this notification,
- * or null if no such data exists.
- */
- public NSDictionary userInfo ()
- {
- if ( userInfo == null ) return null;
- return new NSDictionary( userInfo );
- }
-
- /**
- * Returns a Map containing application specific
- * information relating to this notification,
- * or null if no such data exists.
- * Note: this method is not in the spec.
- */
- public Map userInfoMap ()
- {
- return userInfo;
- }
-
- /**
- * Returns the stack trace when this notification was generated,
- * or null if showStack is false, which is the default.
- * NOTE: This method is not part of the specification.
- */
- public Throwable stackTrace()
- {
- return stackTrace;
- }
-
- /**
- * Returns a human-readable string representation.
- */
- public String toString()
- {
- return "[ " + name() + " : " + object() + " : " + userInfo() + " ]";
- }
+ * An NSNotification is a generic message that can be dispatched by the
+ * NSNotificationCenter.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSNotification {
+ public static boolean showStack = false;
+
+ protected String name;
+ protected Object object;
+ protected Map userInfo;
+
+ // for debugging only
+ private Throwable stackTrace;
+
+ /**
+ * Default constructor creates a new notification with no name, object, or info
+ * dictionary.
+ */
+ public NSNotification() {
+ this(null, null, null);
+ }
+
+ /**
+ * Constructor specifying name and object.
+ */
+ public NSNotification(String aName, Object anObject) {
+ this(aName, anObject, null);
+ }
+
+ /**
+ * Constructor specifying name, object, and a Map containing application
+ * specific information.
+ */
+ public NSNotification(String aName, Object anObject, Map aUserInfo) {
+ name = aName;
+ object = anObject;
+ if (showStack)
+ stackTrace = new RuntimeException();
+ userInfo = aUserInfo;
+ }
+
+ /**
+ * Returns the name of this notification.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the object of this notification.
+ */
+ public Object object() {
+ return object;
+ }
+
+ /**
+ * Returns an NSDictionary that is a copy of the map containing application
+ * specific information relating to this notification, or null if no such data
+ * exists.
+ */
+ public NSDictionary userInfo() {
+ if (userInfo == null)
+ return null;
+ return new NSDictionary(userInfo);
+ }
+
+ /**
+ * Returns a Map containing application specific information relating to this
+ * notification, or null if no such data exists. Note: this method is not in the
+ * spec.
+ */
+ public Map userInfoMap() {
+ return userInfo;
+ }
+
+ /**
+ * Returns the stack trace when this notification was generated, or null if
+ * showStack is false, which is the default. NOTE: This method is not part of
+ * the specification.
+ */
+ public Throwable stackTrace() {
+ return stackTrace;
+ }
+
+ /**
+ * Returns a human-readable string representation.
+ */
+ public String toString() {
+ return "[ " + name() + " : " + object() + " : " + userInfo() + " ]";
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2002/10/24 18:16:04 mpowers
- * No longer generating stack trace by default.
+ * Revision 1.7 2002/10/24 18:16:04 mpowers No longer generating stack trace by
+ * default.
*
- * Revision 1.6 2002/06/21 22:02:47 mpowers
- * Oops: Fixed NPE.
+ * Revision 1.6 2002/06/21 22:02:47 mpowers Oops: Fixed NPE.
*
- * Revision 1.5 2002/06/21 21:50:41 mpowers
- * Added a method to get the map directly from the notification.
- * Changed the internal representation to a map not a dictionary.
- * We had been creating a new dictionary with each creation.
+ * Revision 1.5 2002/06/21 21:50:41 mpowers Added a method to get the map
+ * directly from the notification. Changed the internal representation to a map
+ * not a dictionary. We had been creating a new dictionary with each creation.
* This also allows people to modify the contents of the userInfo.
*
- * Revision 1.4 2001/04/09 21:41:49 mpowers
- * Better debugging.
+ * Revision 1.4 2001/04/09 21:41:49 mpowers Better debugging.
*
- * Revision 1.3 2001/02/21 18:31:07 mpowers
- * Finished and tested implementation of NSNotificationCenter.
+ * Revision 1.3 2001/02/21 18:31:07 mpowers Finished and tested implementation
+ * of NSNotificationCenter.
*
- * Revision 1.2 2001/02/20 23:57:03 mpowers
- * Implemented NSNotificationCenter.
+ * Revision 1.2 2001/02/20 23:57:03 mpowers Implemented NSNotificationCenter.
*
- * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java
index aaf8261..cf0af53 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java
@@ -30,642 +30,502 @@ import java.util.Vector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* NSNotificationCenter broadcasts NSNotifications to
-* registered observers. Observers can register for all
-* notifications of a specific type, or all notifications
-* about a specific object, or both. Observers specify
-* the method that will be called when they are notified.
-* A global notification center can be accessed with
-* defaultCenter(), but other centers can be created and
-* used independently of the default center. <br><br>
-*
-* This implementation uses weak references for observers
-* and observables. The advantage to this approach is
-* that you do not need to explicitly unregister observers
-* or observables; they will be unregistered when they are
-* garbage-collected. Note that you will need to retain
-* a reference to any objects you register or they may
-* become unregistered if no other object references them.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSNotificationCenter
-{
- /**
- * Null marker class simplifies equals() logic
- * for CompoundKey class below.
- */
- public static final Object NullMarker = new Object();
-
- private static NSNotificationCenter defaultCenter = null;
-
- /**
- * A Map of (name,object) pairs to a List
- * of (observer,selector) pairs.
- */
- private Hashtable observers; // thread-safe
-
- /**
- * Default constructor creates a new notification center.
- */
- public NSNotificationCenter()
- {
- observers = new Hashtable();
- }
-
- /**
- * Returns the system default center, creating one
- * if it has not yet been created.
- */
- static public NSNotificationCenter defaultCenter()
- {
- if ( defaultCenter == null )
- {
- defaultCenter = new NSNotificationCenter();
- }
- return defaultCenter;
- }
-
+ * NSNotificationCenter broadcasts NSNotifications to registered observers.
+ * Observers can register for all notifications of a specific type, or all
+ * notifications about a specific object, or both. Observers specify the method
+ * that will be called when they are notified. A global notification center can
+ * be accessed with defaultCenter(), but other centers can be created and used
+ * independently of the default center. <br>
+ * <br>
+ *
+ * This implementation uses weak references for observers and observables. The
+ * advantage to this approach is that you do not need to explicitly unregister
+ * observers or observables; they will be unregistered when they are
+ * garbage-collected. Note that you will need to retain a reference to any
+ * objects you register or they may become unregistered if no other object
+ * references them.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSNotificationCenter {
+ /**
+ * Null marker class simplifies equals() logic for CompoundKey class below.
+ */
+ public static final Object NullMarker = new Object();
+
+ private static NSNotificationCenter defaultCenter = null;
+
/**
- * Addes the specified observer to the notification queue for
- * notifications with the specified name or the specified
- * object or both.
- * @param anObserver The observer that wishes to be notified.
- * @param aSelector The selector that will be invoked.
- * Must have exactly one argument, to which a notification
- * will be passed.
- * @param notificationName The name of the notifications for
- * which the observer will be notified. If null, will notify
- * only based on matching anObject.
- * @param anObject The object of the notifications for which
- * the observer will be notified. If null, will notify
- * only based on matching notificationName.
- */
- public void addObserver(
- Object anObserver, NSSelector aSelector,
- String notificationName, Object anObject )
- {
- // remove freed objects
- processKeyQueue();
-
- Object name = notificationName;
- if ( name == null )
- {
- name = NullMarker;
- }
- if ( anObject == null )
- {
- anObject = NullMarker;
- }
- Object key = new CompoundKey( name, anObject );
- Object value = new CompoundValue( anObserver, aSelector );
- List list = (List) observers.get( key );
- if ( list == null )
- {
- // create new list with value and put it in map
- list = new Vector(); // thread-safe
- list.add( value );
- observers.put( new CompoundKey(
- name, anObject, keyQueue ), list );
- }
- else
- {
- // add only if not already in list
- if ( ! list.contains( value ) )
- {
- list.add( value );
- }
- }
- }
-
+ * A Map of (name,object) pairs to a List of (observer,selector) pairs.
+ */
+ private Hashtable observers; // thread-safe
+
+ /**
+ * Default constructor creates a new notification center.
+ */
+ public NSNotificationCenter() {
+ observers = new Hashtable();
+ }
+
+ /**
+ * Returns the system default center, creating one if it has not yet been
+ * created.
+ */
+ static public NSNotificationCenter defaultCenter() {
+ if (defaultCenter == null) {
+ defaultCenter = new NSNotificationCenter();
+ }
+ return defaultCenter;
+ }
+
+ /**
+ * Addes the specified observer to the notification queue for notifications with
+ * the specified name or the specified object or both.
+ *
+ * @param anObserver The observer that wishes to be notified.
+ * @param aSelector The selector that will be invoked. Must have exactly
+ * one argument, to which a notification will be passed.
+ * @param notificationName The name of the notifications for which the observer
+ * will be notified. If null, will notify only based on
+ * matching anObject.
+ * @param anObject The object of the notifications for which the
+ * observer will be notified. If null, will notify only
+ * based on matching notificationName.
+ */
+ public void addObserver(Object anObserver, NSSelector aSelector, String notificationName, Object anObject) {
+ // remove freed objects
+ processKeyQueue();
+
+ Object name = notificationName;
+ if (name == null) {
+ name = NullMarker;
+ }
+ if (anObject == null) {
+ anObject = NullMarker;
+ }
+ Object key = new CompoundKey(name, anObject);
+ Object value = new CompoundValue(anObserver, aSelector);
+ List list = (List) observers.get(key);
+ if (list == null) {
+ // create new list with value and put it in map
+ list = new Vector(); // thread-safe
+ list.add(value);
+ observers.put(new CompoundKey(name, anObject, keyQueue), list);
+ } else {
+ // add only if not already in list
+ if (!list.contains(value)) {
+ list.add(value);
+ }
+ }
+ }
+
/**
- * Posts the specified notification. Notifies all registered
- * observers that match either the notification name or
- * the notification object, or both.
- * @param aNotification The notification that will be passed
- * to the observers selector.
- */
- public void postNotification(
- NSNotification aNotification )
- {
- List mergedList = new LinkedList();
- Object key, observerList;
-
- Object name = aNotification.name();
- Object object = aNotification.object();
-
- if ( name != null )
- {
- if ( object != null )
- { // both are specified
- observerList = observers.get( new CompoundKey( name, object ) );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
- observerList = observers.get( new CompoundKey( name, NullMarker ) );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
- observerList = observers.get( new CompoundKey( NullMarker, object ) );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
- }
- else
- { // object is null
- observerList = observers.get( new CompoundKey( name, NullMarker ) );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
- }
- }
- else
- if ( object != null )
- { // name is null
- observerList = observers.get( new CompoundKey( NullMarker, object ) );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
- }
-
- key = new CompoundKey(
- NullMarker, NullMarker );
- observerList = observers.get( key );
- if ( observerList != null )
- {
- mergedList.addAll( (List) observerList );
- }
-
- CompoundValue value;
- Iterator it = mergedList.iterator();
- while ( it.hasNext() )
- {
- value = (CompoundValue) it.next();
- if ( value.get() == null )
- {
- it.remove();
- }
- else
- {
- try
- {
- value.selector().invoke(
- value.get(),
- new Object[] { aNotification } );
- }
- catch ( Exception exc )
- {
- WotonomyException w = new WotonomyException(
- "Error notifying object: " + value.get() + " : " + aNotification, exc );
+ * Posts the specified notification. Notifies all registered observers that
+ * match either the notification name or the notification object, or both.
+ *
+ * @param aNotification The notification that will be passed to the observers
+ * selector.
+ */
+ public void postNotification(NSNotification aNotification) {
+ List mergedList = new LinkedList();
+ Object key, observerList;
+
+ Object name = aNotification.name();
+ Object object = aNotification.object();
+
+ if (name != null) {
+ if (object != null) { // both are specified
+ observerList = observers.get(new CompoundKey(name, object));
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+ observerList = observers.get(new CompoundKey(name, NullMarker));
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+ observerList = observers.get(new CompoundKey(NullMarker, object));
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+ } else { // object is null
+ observerList = observers.get(new CompoundKey(name, NullMarker));
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+ }
+ } else if (object != null) { // name is null
+ observerList = observers.get(new CompoundKey(NullMarker, object));
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+ }
+
+ key = new CompoundKey(NullMarker, NullMarker);
+ observerList = observers.get(key);
+ if (observerList != null) {
+ mergedList.addAll((List) observerList);
+ }
+
+ CompoundValue value;
+ Iterator it = mergedList.iterator();
+ while (it.hasNext()) {
+ value = (CompoundValue) it.next();
+ if (value.get() == null) {
+ it.remove();
+ } else {
+ try {
+ value.selector().invoke(value.get(), new Object[] { aNotification });
+ } catch (Exception exc) {
+ WotonomyException w = new WotonomyException(
+ "Error notifying object: " + value.get() + " : " + aNotification, exc);
// throw w;
- w.printStackTrace();
-postNotification( "Error notifying object", this, new NSDictionary( "exception", w ) );
- }
- }
- }
-
- }
-
+ w.printStackTrace();
+ postNotification("Error notifying object", this, new NSDictionary("exception", w));
+ }
+ }
+ }
+
+ }
+
/**
- * Posts a notification created from the specified name
- * and object. Calls postNotification( NSNotification ).
- * @param notificationName a String key to distinguish
- * this notification.
- * @param anObject any object, by convention this is
- * the originator of the notification.
- */
- public void postNotification(
- String notificationName, Object anObject )
- {
- postNotification( new NSNotification(
- notificationName, anObject ) );
- }
-
+ * Posts a notification created from the specified name and object. Calls
+ * postNotification( NSNotification ).
+ *
+ * @param notificationName a String key to distinguish this notification.
+ * @param anObject any object, by convention this is the originator of
+ * the notification.
+ */
+ public void postNotification(String notificationName, Object anObject) {
+ postNotification(new NSNotification(notificationName, anObject));
+ }
+
/**
- * Posts a notification created from the specified name,
- * object, and info. Calls postNotification( NSNotification ).
- * @param notificationName a String key to distinguish
- * this notification.
- * @param anObject any object, by convention this is
- * the originator of the notification.
- * @param userInfo a Map containing information specific
- * to the originator of the notification and that may
- * be of interest to a knowledgable observer.
- */
- public void postNotification(
- String notificationName, Object anObject, Map userInfo )
- {
- postNotification( new NSNotification(
- notificationName, anObject, userInfo ) );
- }
-
+ * Posts a notification created from the specified name, object, and info. Calls
+ * postNotification( NSNotification ).
+ *
+ * @param notificationName a String key to distinguish this notification.
+ * @param anObject any object, by convention this is the originator of
+ * the notification.
+ * @param userInfo a Map containing information specific to the
+ * originator of the notification and that may be of
+ * interest to a knowledgable observer.
+ */
+ public void postNotification(String notificationName, Object anObject, Map userInfo) {
+ postNotification(new NSNotification(notificationName, anObject, userInfo));
+ }
+
/**
- * Unregisters the specified observer from all notification
- * queues for which it is registered.
- * @param anObserver The observer to be unregistered.
- */
- public void removeObserver(
- Object anObserver )
- {
- // remove freed objects
- processKeyQueue();
-
- Iterator it = new LinkedList( observers.keySet() ).iterator();
- while ( it.hasNext() )
- {
- removeObserver( anObserver, it.next() );
- }
- }
-
+ * Unregisters the specified observer from all notification queues for which it
+ * is registered.
+ *
+ * @param anObserver The observer to be unregistered.
+ */
+ public void removeObserver(Object anObserver) {
+ // remove freed objects
+ processKeyQueue();
+
+ Iterator it = new LinkedList(observers.keySet()).iterator();
+ while (it.hasNext()) {
+ removeObserver(anObserver, it.next());
+ }
+ }
+
/**
- * Unregisters the specified observer from all notifications
- * queues associated with the specified name or object or both.
- * @param anObserver The observer to be unregistered, if null
- * will unregister all observers for the specified notification
- * name and object.
- * @param notificationName The name of the notification for which
- * the observer will be unregistered, if null will unregister
- * the specified observer for all notifications with the
- * specified object.
- * @param anObject The object for the notification for which
- * the observer will be unregistered, if null will unregister
- * the specified observer for all objects with the specified
- * notification.
- */
- public void removeObserver(
- Object anObserver, String notificationName, Object anObject )
- {
- // remove freed objects
- processKeyQueue();
-
- // get key matches
- List keys = matchingKeys( notificationName, anObject );
-
- // remove specified observer from each matching key
- Iterator it = keys.iterator();
- while ( it.hasNext() )
- {
- removeObserver( anObserver, it.next() );
- }
- }
-
- /**
- * Returns all keys that match the specified name and object,
- * but in this case null parameters are considered wildcards.
- * Pass NullMarkers if you want to explicitly match nulls.
- */
- private List matchingKeys( String name, Object object )
- {
- List result = new LinkedList();
-
- boolean willAdd;
- CompoundKey key;
- Iterator it = observers.keySet().iterator();
- while ( it.hasNext() )
- {
- key = (CompoundKey) it.next();
- willAdd = false;
- if ( ( name == null ) || ( name == key.name() ) )
- {
- if ( ( object == null ) || ( object == key.get() ) )
- {
- willAdd = true;
- }
- }
- if ( willAdd )
- {
- result.add( key );
- }
- }
- return result;
- }
-
- /**
- * Removes the specified observer from the list referenced
- * by the specified key in the observer map.
- */
- private void removeObserver(
- Object anObserver, Object key )
- {
- // if observer null, remove all observers for key
- if ( anObserver == null )
- {
- observers.remove( key );
- return;
- }
-
- List list = (List) observers.get( key );
- if ( list == null ) return;
-
- // remove specified observer from list
- Object observer;
- Iterator it = list.iterator();
- while ( it.hasNext() )
- {
- observer = ((CompoundValue)it.next()).get();
- if ( ( observer == null ) || ( anObserver == observer ) )
- {
- // remove if match or freed object
- it.remove();
-
- // do not return; process entire list
- }
- }
- if ( list.size() == 0 )
- {
- observers.remove( key );
- }
- }
-
- /* Reference queues for cleared WeakKeys */
- private ReferenceQueue keyQueue = new ReferenceQueue();
-
- /**
- * Removes any keys whose object has been garbage collected.
- * (Garbage collected values are removed as they are encountered.)
- */
- private void processKeyQueue()
- {
- CompoundKey ck;
- while ((ck = (CompoundKey)keyQueue.poll()) != null)
- {
- //System.out.println( "EOObserverCenter.processQueue: removing object" );
- observers.remove(ck);
- }
- }
-
- /**
- * Key combining a name with an object.
- * The object is weakly referenced, and keys
- * are deallocated by reference queue.
- * equals() compares by reference.
- */
- private static class CompoundKey extends WeakReference
- {
- private Object name;
- private int hashCode;
-
- /**
- * Creates compound key.
- * Neither name nor object may be null.
- * Use NullMarker to represent null
- * in either name or object.
- */
- public CompoundKey (
- Object aName, Object anObject )
- {
- super( anObject );
- name = aName;
- hashCode = aName.hashCode() + anObject.hashCode();
- }
-
- /**
- * Creates compound key with queue.
- * Neither name nor object may be null.
- * Use NullMarker to represent null
- * in either name or object.
- */
- public CompoundKey (
- Object aName, Object anObject, ReferenceQueue aQueue )
- {
- super( anObject, aQueue );
- name = aName;
- hashCode = aName.hashCode() + anObject.hashCode();
- }
-
- public Object name()
- {
- return name;
- }
-
- public int hashCode()
- {
- return hashCode;
- }
-
- public boolean equals( Object anObject )
- {
- if ( this == anObject ) return true;
- // assumes only used with other compound keys
- CompoundKey key = (CompoundKey) anObject;
- if ( name == key.name || ( name != null && name.equals( key.name ) ) )
- {
- Object object = get();
- if ( object != null )
- {
- // compares by reference
- if ( object == ( key.get() ) )
- {
- return true;
- }
- }
- }
- return false;
- }
-
- public String toString()
- {
- return "[CompoundKey:"+name()+":"+get()+"]";
- }
- }
-
- /**
- * Value combining an object with a selector.
- * The object is weakly referenced, and null
- * values are not allowed.
- */
- private static class CompoundValue extends WeakReference
- {
- private NSSelector selector;
- private int hashCode;
-
- public CompoundValue( Object anObject, NSSelector aSelector )
- {
- super( anObject );
- hashCode = anObject.hashCode();
- selector = aSelector;
- }
-
- public NSSelector selector()
- {
- return selector;
- }
-
- public int hashCode()
- {
- return hashCode;
- }
-
- public boolean equals( Object anObject )
- {
- if ( this == anObject ) return true;
- // assumes only used with other compound values
- CompoundValue value = (CompoundValue) anObject;
- if ( selector == value.selector ||
- ( selector != null && selector.equals( value.selector ) ) )
- {
- Object object = get();
- if ( object != null )
- {
- if ( object == value.get() )
- {
- return true;
- }
- }
- }
- return false;
- }
-
- public String toString()
- {
- return "[CompoundValue:"+get()+":"+selector().name()+"]";
- }
- }
-/*
- public static void main( String[] argv )
- {
- Object aSource = "aSource";
- Object bSource = "bSource";
-
- Object oneTest = new OneTest();
- Object twoTest = new TwoTest();
- NSSelector notifyMeOnce =
- new NSSelector( "notifyMeOnce",
- new Class[] { NSNotification.class } );
- NSSelector notifyMeTwice =
- new NSSelector( "notifyMeTwice",
- new Class[] { NSNotification.class } );
-
- NSNotificationCenter.defaultCenter().addObserver(
- oneTest, notifyMeOnce, "aMessage", null );
-
- NSNotificationCenter.defaultCenter().addObserver(
- oneTest, notifyMeOnce, null, aSource );
-
- NSNotificationCenter.defaultCenter().addObserver(
- twoTest, notifyMeOnce, "aMessage", aSource );
-
- NSNotificationCenter.defaultCenter().addObserver(
- twoTest, notifyMeTwice, null, null );
-
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", bSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", bSource );
- System.out.println( "---" );
-
- NSNotificationCenter.defaultCenter().removeObserver(
- oneTest, null, aSource );
-
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", bSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", bSource );
- System.out.println( "---" );
-
- NSNotificationCenter.defaultCenter().removeObserver(
- null );
-
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "aMessage", bSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", aSource );
- System.out.println();
- NSNotificationCenter.defaultCenter().postNotification(
- "bMessage", bSource );
- System.out.println( "---" );
- }
-
- static private class OneTest
- {
- public void notifyMeOnce( NSNotification aNotification )
- {
- System.out.println( "OneTest.notifyMeOnce: " + aNotification );
- }
- }
-
- static private class TwoTest
- {
- public void notifyMeOnce( NSNotification aNotification )
- {
- System.out.println( "TwoTest.notifyMeOnce: " + aNotification );
- }
- public void notifyMeTwice( NSNotification aNotification )
- {
- System.out.println( "TwoTest.notifyMeTwice: " + aNotification );
- }
- }
-*/
-}
+ * Unregisters the specified observer from all notifications queues associated
+ * with the specified name or object or both.
+ *
+ * @param anObserver The observer to be unregistered, if null will
+ * unregister all observers for the specified
+ * notification name and object.
+ * @param notificationName The name of the notification for which the observer
+ * will be unregistered, if null will unregister the
+ * specified observer for all notifications with the
+ * specified object.
+ * @param anObject The object for the notification for which the
+ * observer will be unregistered, if null will
+ * unregister the specified observer for all objects
+ * with the specified notification.
+ */
+ public void removeObserver(Object anObserver, String notificationName, Object anObject) {
+ // remove freed objects
+ processKeyQueue();
+ // get key matches
+ List keys = matchingKeys(notificationName, anObject);
+ // remove specified observer from each matching key
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ removeObserver(anObserver, it.next());
+ }
+ }
+
+ /**
+ * Returns all keys that match the specified name and object, but in this case
+ * null parameters are considered wildcards. Pass NullMarkers if you want to
+ * explicitly match nulls.
+ */
+ private List matchingKeys(String name, Object object) {
+ List result = new LinkedList();
+
+ boolean willAdd;
+ CompoundKey key;
+ Iterator it = observers.keySet().iterator();
+ while (it.hasNext()) {
+ key = (CompoundKey) it.next();
+ willAdd = false;
+ if ((name == null) || (name == key.name())) {
+ if ((object == null) || (object == key.get())) {
+ willAdd = true;
+ }
+ }
+ if (willAdd) {
+ result.add(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Removes the specified observer from the list referenced by the specified key
+ * in the observer map.
+ */
+ private void removeObserver(Object anObserver, Object key) {
+ // if observer null, remove all observers for key
+ if (anObserver == null) {
+ observers.remove(key);
+ return;
+ }
+
+ List list = (List) observers.get(key);
+ if (list == null)
+ return;
+
+ // remove specified observer from list
+ Object observer;
+ Iterator it = list.iterator();
+ while (it.hasNext()) {
+ observer = ((CompoundValue) it.next()).get();
+ if ((observer == null) || (anObserver == observer)) {
+ // remove if match or freed object
+ it.remove();
+
+ // do not return; process entire list
+ }
+ }
+ if (list.size() == 0) {
+ observers.remove(key);
+ }
+ }
+
+ /* Reference queues for cleared WeakKeys */
+ private ReferenceQueue keyQueue = new ReferenceQueue();
+
+ /**
+ * Removes any keys whose object has been garbage collected. (Garbage collected
+ * values are removed as they are encountered.)
+ */
+ private void processKeyQueue() {
+ CompoundKey ck;
+ while ((ck = (CompoundKey) keyQueue.poll()) != null) {
+ // System.out.println( "EOObserverCenter.processQueue: removing object" );
+ observers.remove(ck);
+ }
+ }
+
+ /**
+ * Key combining a name with an object. The object is weakly referenced, and
+ * keys are deallocated by reference queue. equals() compares by reference.
+ */
+ private static class CompoundKey extends WeakReference {
+ private Object name;
+ private int hashCode;
+
+ /**
+ * Creates compound key. Neither name nor object may be null. Use NullMarker to
+ * represent null in either name or object.
+ */
+ public CompoundKey(Object aName, Object anObject) {
+ super(anObject);
+ name = aName;
+ hashCode = aName.hashCode() + anObject.hashCode();
+ }
+
+ /**
+ * Creates compound key with queue. Neither name nor object may be null. Use
+ * NullMarker to represent null in either name or object.
+ */
+ public CompoundKey(Object aName, Object anObject, ReferenceQueue aQueue) {
+ super(anObject, aQueue);
+ name = aName;
+ hashCode = aName.hashCode() + anObject.hashCode();
+ }
+
+ public Object name() {
+ return name;
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public boolean equals(Object anObject) {
+ if (this == anObject)
+ return true;
+ // assumes only used with other compound keys
+ CompoundKey key = (CompoundKey) anObject;
+ if (name == key.name || (name != null && name.equals(key.name))) {
+ Object object = get();
+ if (object != null) {
+ // compares by reference
+ if (object == (key.get())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+ return "[CompoundKey:" + name() + ":" + get() + "]";
+ }
+ }
+
+ /**
+ * Value combining an object with a selector. The object is weakly referenced,
+ * and null values are not allowed.
+ */
+ private static class CompoundValue extends WeakReference {
+ private NSSelector selector;
+ private int hashCode;
+
+ public CompoundValue(Object anObject, NSSelector aSelector) {
+ super(anObject);
+ hashCode = anObject.hashCode();
+ selector = aSelector;
+ }
+
+ public NSSelector selector() {
+ return selector;
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public boolean equals(Object anObject) {
+ if (this == anObject)
+ return true;
+ // assumes only used with other compound values
+ CompoundValue value = (CompoundValue) anObject;
+ if (selector == value.selector || (selector != null && selector.equals(value.selector))) {
+ Object object = get();
+ if (object != null) {
+ if (object == value.get()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+ return "[CompoundValue:" + get() + ":" + selector().name() + "]";
+ }
+ }
+ /*
+ * public static void main( String[] argv ) { Object aSource = "aSource"; Object
+ * bSource = "bSource";
+ *
+ * Object oneTest = new OneTest(); Object twoTest = new TwoTest(); NSSelector
+ * notifyMeOnce = new NSSelector( "notifyMeOnce", new Class[] {
+ * NSNotification.class } ); NSSelector notifyMeTwice = new NSSelector(
+ * "notifyMeTwice", new Class[] { NSNotification.class } );
+ *
+ * NSNotificationCenter.defaultCenter().addObserver( oneTest, notifyMeOnce,
+ * "aMessage", null );
+ *
+ * NSNotificationCenter.defaultCenter().addObserver( oneTest, notifyMeOnce,
+ * null, aSource );
+ *
+ * NSNotificationCenter.defaultCenter().addObserver( twoTest, notifyMeOnce,
+ * "aMessage", aSource );
+ *
+ * NSNotificationCenter.defaultCenter().addObserver( twoTest, notifyMeTwice,
+ * null, null );
+ *
+ * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "aMessage", bSource ); System.out.println();
+ * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "bMessage", bSource ); System.out.println( "---" );
+ *
+ * NSNotificationCenter.defaultCenter().removeObserver( oneTest, null, aSource
+ * );
+ *
+ * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "aMessage", bSource ); System.out.println();
+ * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "bMessage", bSource ); System.out.println( "---" );
+ *
+ * NSNotificationCenter.defaultCenter().removeObserver( null );
+ *
+ * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "aMessage", bSource ); System.out.println();
+ * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource );
+ * System.out.println(); NSNotificationCenter.defaultCenter().postNotification(
+ * "bMessage", bSource ); System.out.println( "---" ); }
+ *
+ * static private class OneTest { public void notifyMeOnce( NSNotification
+ * aNotification ) { System.out.println( "OneTest.notifyMeOnce: " +
+ * aNotification ); } }
+ *
+ * static private class TwoTest { public void notifyMeOnce( NSNotification
+ * aNotification ) { System.out.println( "TwoTest.notifyMeOnce: " +
+ * aNotification ); } public void notifyMeTwice( NSNotification aNotification )
+ * { System.out.println( "TwoTest.notifyMeTwice: " + aNotification ); } }
+ */
+}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.11 2003/06/03 14:51:15 mpowers
- * Added commented-out println for debugging.
+ * Revision 1.11 2003/06/03 14:51:15 mpowers Added commented-out println for
+ * debugging.
*
- * Revision 1.10 2003/03/27 21:46:00 mpowers
- * Better handling for null parameters on subscribe.
- * Better handling for null parameters on post.
+ * Revision 1.10 2003/03/27 21:46:00 mpowers Better handling for null parameters
+ * on subscribe. Better handling for null parameters on post.
*
- * Revision 1.9 2003/01/28 19:44:38 mpowers
- * Now comparing strings by value not reference.
+ * Revision 1.9 2003/01/28 19:44:38 mpowers Now comparing strings by value not
+ * reference.
*
- * Revision 1.8 2001/06/29 16:14:23 mpowers
- * Fixed a javac compiler error that jikes allowed: shoe's on the other foot!
+ * Revision 1.8 2001/06/29 16:14:23 mpowers Fixed a javac compiler error that
+ * jikes allowed: shoe's on the other foot!
*
- * Revision 1.7 2001/06/07 22:09:03 mpowers
- * Exceptions during a notification are no longer being thrown
- * so we can assure that all notifications get handled.
+ * Revision 1.7 2001/06/07 22:09:03 mpowers Exceptions during a notification are
+ * no longer being thrown so we can assure that all notifications get handled.
* Instead, we're printing stack traces...
*
- * Revision 1.6 2001/04/09 21:41:50 mpowers
- * Better debugging.
+ * Revision 1.6 2001/04/09 21:41:50 mpowers Better debugging.
*
- * Revision 1.5 2001/03/15 21:09:06 mpowers
- * Fixed notifications with null objects.
+ * Revision 1.5 2001/03/15 21:09:06 mpowers Fixed notifications with null
+ * objects.
*
- * Revision 1.4 2001/02/21 21:18:34 mpowers
- * Clarified need to retain references.
+ * Revision 1.4 2001/02/21 21:18:34 mpowers Clarified need to retain references.
*
- * Revision 1.3 2001/02/21 18:31:07 mpowers
- * Finished and tested implementation of NSNotificationCenter.
+ * Revision 1.3 2001/02/21 18:31:07 mpowers Finished and tested implementation
+ * of NSNotificationCenter.
*
- * Revision 1.1.1.1 2000/12/21 15:47:39 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:39 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java
index 7350a39..81dc6e8 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java
@@ -23,323 +23,264 @@ import java.util.LinkedList;
import java.util.List;
/**
-* NSNotificationQueue coalesces notifications to be
-* posted to the NSNotificationCenter and can post them
-* asynchronously. While calling postNotification on
-* the notification center does not return until all
-* receivers have been notified, calling enqueueNotification
-* can return immediately. Use this class when you want
-* to coalesce notifications or notify asynchronously, or
-* both, which is the typical case.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSNotificationQueue
-{
- private static NSNotificationQueue defaultQueue = null;
-
- /**
- * Posting style specifying that the notification should
- * be posted on the next available event loop.
- */
- public static final int PostASAP = 4;
-
- /**
- * Posting style specifying that the notification should
- * be posted on the next available idle loop.
- */
- public static final int PostWhenIdle = 8;
-
- /**
- * Posting style specifying that the notification should
- * be posted immediately. The enqueue method will not
- * return until all receivers have been notified.
- */
- public static final int PostNow = 16;
-
- /**
- * Used to indicate that this notification should not
- * be coalesced with other notifications.
- * Ignored if combined with other coalesce flags.
- */
- public static final int NotificationNoCoalescing = 0;
-
- /**
- * Used to indicate that this notification should
- * be coalesced with other notifications with the
- * same name.
- * May be combined with NotificationCoalescingOnSender.
- */
- public static final int NotificationCoalescingOnName = 1;
-
- /**
- * Used to indicate that this notification should
- * be coalesced with other notifications with the
- * same object argument (which is typically the sender).
- * May be combined with NotificationCoalescingOnName.
- */
- public static final int NotificationCoalescingOnSender = 2;
-
- /**
- * The ASAP queue, which should probably use a LinkedList.
- */
- private List queue;
-
- /**
- * The idle queue, which should probably use a LinkedList.
- */
- private List idleQueue;
-
- /**
- * The notification center we will be using.
- */
- private NSNotificationCenter center;
-
- /**
- * Our private ASAP notifier.
- */
- private Notifier notifier;
-
- /**
- * Our private idle notifier.
- */
- private Notifier idleNotifier;
-
- /**
- * Default constructor creates a new notification queue
- * that uses the default notification center.
- */
- public NSNotificationQueue()
- {
- this( NSNotificationCenter.defaultCenter() );
- }
-
- /**
- * Creates a new notification queue that uses the
- * specified notification center.
- */
- public NSNotificationQueue(
- NSNotificationCenter aCenter )
- {
- queue = new LinkedList();
- idleQueue = new LinkedList();
- center = aCenter;
- notifier = new Notifier( this, queue );
- idleNotifier = new Notifier( this, idleQueue );
- }
-
- /**
- * Returns the system default queue, creating one
- * if it has not yet been created. The system default
- * queue uses the system default notification center.
- */
- static public NSNotificationQueue defaultQueue()
- {
- if ( defaultQueue == null )
- {
- defaultQueue = new NSNotificationQueue();
- }
- return defaultQueue;
- }
-
- /**
- * Removes notifications from the queue that match
- * the specified notification, considering the
- * specified coalesce mask.
- */
- public void dequeueMatchingNotifications(
- NSNotification aNotification,
- int aCoalesceMask)
- {
- if ( aCoalesceMask == NotificationNoCoalescing ) return;
- dequeueFromQueue( aNotification, aCoalesceMask, queue );
- dequeueFromQueue( aNotification, aCoalesceMask, idleQueue );
- }
-
- private void dequeueFromQueue(
- NSNotification aNotification,
- int aCoalesceMask,
- List aQueue )
- {
- synchronized ( aQueue )
- {
- int flag;
- NSNotification notification;
- Object name = aNotification.name();
- Object object = aNotification.object();
- Iterator it = aQueue.iterator();
- while ( it.hasNext() )
- {
- flag = 0;
- notification = (NSNotification) it.next();
- // if NotificationCoalescingOnName
- if ( ( aCoalesceMask == 1 ) || ( aCoalesceMask == 3 ) )
- {
- if ( name == null )
- {
- if ( notification.name() != null )
- {
- flag += NotificationCoalescingOnName;
- }
- }
- else
- {
- // compare by value
- if ( name.equals( notification.name() ) )
- {
- flag += NotificationCoalescingOnName;
- }
- }
- }
- // if NotificationCoalescingOnSender
- if ( aCoalesceMask >= 2 )
- {
- // compare by reference
- if ( object == notification.object() )
- {
- flag += NotificationCoalescingOnSender;
- }
- }
-
- if ( flag == aCoalesceMask )
- {
- it.remove();
- }
- }
- }
- }
-
- /**
- * Adds the notification to the queue to be run at
- * the time specified by the posting style. The
- * notification will be coalesced with other notifications
- * that match the same name and object (sender) argument.
- */
- public void enqueueNotification(
- NSNotification aNotification,
- int aPostingStyle)
- {
- enqueueNotificationWithCoalesceMaskForModes(
- aNotification, aPostingStyle,
- NotificationCoalescingOnName + NotificationCoalescingOnSender,
- null );
- }
-
- /**
- * Adds the notification to the queue to be run at
- * the time specified by the posting style and coelesced
- * as the specified mask indicates.
- * aModeList is currently ignored and may be null.
- */
- public void enqueueNotificationWithCoalesceMaskForModes(
- NSNotification aNotification,
- int aPostingStyle,
- int aCoalesceMask,
- List aModeList)
- {
- dequeueMatchingNotifications( aNotification, aCoalesceMask );
-
- if ( aPostingStyle == PostNow )
- {
- center.postNotification( aNotification );
- return;
- }
-
- if ( aPostingStyle == PostASAP )
- {
- synchronized ( queue )
- {
- queue.add( aNotification );
- if ( ! notifier.willRun )
- {
- // asap runs at the very first run loop ordering, plus one just in case
- NSRunLoop.invokeLaterWithOrder( notifier, 1 );
- notifier.willRun = true;
- }
- }
- return;
- }
-
- if ( aPostingStyle == PostWhenIdle )
- {
- synchronized ( idleQueue )
- {
- idleQueue.add( aNotification );
- if ( ! idleNotifier.willRun )
- {
- // when idle runs at the very last run loop ordering, minus one just in case
- NSRunLoop.invokeLaterWithOrder( idleNotifier, Integer.MAX_VALUE - 1 );
- idleNotifier.willRun = true;
- }
- }
- return;
- }
-
- }
-
- private class Notifier implements Runnable
- {
- public boolean willRun;
-
- NSNotificationQueue parent;
- List queue;
-
- public Notifier(
- NSNotificationQueue aParent, List aQueue )
- {
- willRun = false;
- parent = aParent;
- queue = aQueue;
- }
-
- public void run()
- {
- Iterator it = new LinkedList( queue ).iterator();
- synchronized ( queue )
- {
- queue.clear();
- }
- willRun = false;
-
- // queue must already be cleared and willRun reset
- // because this loop might queue more notifications
- while ( it.hasNext() )
- {
- parent.center.postNotification(
- (NSNotification) it.next() );
- }
- }
- }
+ * NSNotificationQueue coalesces notifications to be posted to the
+ * NSNotificationCenter and can post them asynchronously. While calling
+ * postNotification on the notification center does not return until all
+ * receivers have been notified, calling enqueueNotification can return
+ * immediately. Use this class when you want to coalesce notifications or notify
+ * asynchronously, or both, which is the typical case.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSNotificationQueue {
+ private static NSNotificationQueue defaultQueue = null;
+
+ /**
+ * Posting style specifying that the notification should be posted on the next
+ * available event loop.
+ */
+ public static final int PostASAP = 4;
+
+ /**
+ * Posting style specifying that the notification should be posted on the next
+ * available idle loop.
+ */
+ public static final int PostWhenIdle = 8;
+
+ /**
+ * Posting style specifying that the notification should be posted immediately.
+ * The enqueue method will not return until all receivers have been notified.
+ */
+ public static final int PostNow = 16;
+
+ /**
+ * Used to indicate that this notification should not be coalesced with other
+ * notifications. Ignored if combined with other coalesce flags.
+ */
+ public static final int NotificationNoCoalescing = 0;
+
+ /**
+ * Used to indicate that this notification should be coalesced with other
+ * notifications with the same name. May be combined with
+ * NotificationCoalescingOnSender.
+ */
+ public static final int NotificationCoalescingOnName = 1;
+
+ /**
+ * Used to indicate that this notification should be coalesced with other
+ * notifications with the same object argument (which is typically the sender).
+ * May be combined with NotificationCoalescingOnName.
+ */
+ public static final int NotificationCoalescingOnSender = 2;
+
+ /**
+ * The ASAP queue, which should probably use a LinkedList.
+ */
+ private List queue;
+
+ /**
+ * The idle queue, which should probably use a LinkedList.
+ */
+ private List idleQueue;
+
+ /**
+ * The notification center we will be using.
+ */
+ private NSNotificationCenter center;
+
+ /**
+ * Our private ASAP notifier.
+ */
+ private Notifier notifier;
+
+ /**
+ * Our private idle notifier.
+ */
+ private Notifier idleNotifier;
+
+ /**
+ * Default constructor creates a new notification queue that uses the default
+ * notification center.
+ */
+ public NSNotificationQueue() {
+ this(NSNotificationCenter.defaultCenter());
+ }
+
+ /**
+ * Creates a new notification queue that uses the specified notification center.
+ */
+ public NSNotificationQueue(NSNotificationCenter aCenter) {
+ queue = new LinkedList();
+ idleQueue = new LinkedList();
+ center = aCenter;
+ notifier = new Notifier(this, queue);
+ idleNotifier = new Notifier(this, idleQueue);
+ }
+
+ /**
+ * Returns the system default queue, creating one if it has not yet been
+ * created. The system default queue uses the system default notification
+ * center.
+ */
+ static public NSNotificationQueue defaultQueue() {
+ if (defaultQueue == null) {
+ defaultQueue = new NSNotificationQueue();
+ }
+ return defaultQueue;
+ }
+
+ /**
+ * Removes notifications from the queue that match the specified notification,
+ * considering the specified coalesce mask.
+ */
+ public void dequeueMatchingNotifications(NSNotification aNotification, int aCoalesceMask) {
+ if (aCoalesceMask == NotificationNoCoalescing)
+ return;
+ dequeueFromQueue(aNotification, aCoalesceMask, queue);
+ dequeueFromQueue(aNotification, aCoalesceMask, idleQueue);
+ }
+
+ private void dequeueFromQueue(NSNotification aNotification, int aCoalesceMask, List aQueue) {
+ synchronized (aQueue) {
+ int flag;
+ NSNotification notification;
+ Object name = aNotification.name();
+ Object object = aNotification.object();
+ Iterator it = aQueue.iterator();
+ while (it.hasNext()) {
+ flag = 0;
+ notification = (NSNotification) it.next();
+ // if NotificationCoalescingOnName
+ if ((aCoalesceMask == 1) || (aCoalesceMask == 3)) {
+ if (name == null) {
+ if (notification.name() != null) {
+ flag += NotificationCoalescingOnName;
+ }
+ } else {
+ // compare by value
+ if (name.equals(notification.name())) {
+ flag += NotificationCoalescingOnName;
+ }
+ }
+ }
+ // if NotificationCoalescingOnSender
+ if (aCoalesceMask >= 2) {
+ // compare by reference
+ if (object == notification.object()) {
+ flag += NotificationCoalescingOnSender;
+ }
+ }
+
+ if (flag == aCoalesceMask) {
+ it.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the notification to the queue to be run at the time specified by the
+ * posting style. The notification will be coalesced with other notifications
+ * that match the same name and object (sender) argument.
+ */
+ public void enqueueNotification(NSNotification aNotification, int aPostingStyle) {
+ enqueueNotificationWithCoalesceMaskForModes(aNotification, aPostingStyle,
+ NotificationCoalescingOnName + NotificationCoalescingOnSender, null);
+ }
+
+ /**
+ * Adds the notification to the queue to be run at the time specified by the
+ * posting style and coelesced as the specified mask indicates. aModeList is
+ * currently ignored and may be null.
+ */
+ public void enqueueNotificationWithCoalesceMaskForModes(NSNotification aNotification, int aPostingStyle,
+ int aCoalesceMask, List aModeList) {
+ dequeueMatchingNotifications(aNotification, aCoalesceMask);
+
+ if (aPostingStyle == PostNow) {
+ center.postNotification(aNotification);
+ return;
+ }
+
+ if (aPostingStyle == PostASAP) {
+ synchronized (queue) {
+ queue.add(aNotification);
+ if (!notifier.willRun) {
+ // asap runs at the very first run loop ordering, plus one just in case
+ NSRunLoop.invokeLaterWithOrder(notifier, 1);
+ notifier.willRun = true;
+ }
+ }
+ return;
+ }
+
+ if (aPostingStyle == PostWhenIdle) {
+ synchronized (idleQueue) {
+ idleQueue.add(aNotification);
+ if (!idleNotifier.willRun) {
+ // when idle runs at the very last run loop ordering, minus one just in case
+ NSRunLoop.invokeLaterWithOrder(idleNotifier, Integer.MAX_VALUE - 1);
+ idleNotifier.willRun = true;
+ }
+ }
+ return;
+ }
+
+ }
+
+ private class Notifier implements Runnable {
+ public boolean willRun;
+
+ NSNotificationQueue parent;
+ List queue;
+
+ public Notifier(NSNotificationQueue aParent, List aQueue) {
+ willRun = false;
+ parent = aParent;
+ queue = aQueue;
+ }
+
+ public void run() {
+ Iterator it = new LinkedList(queue).iterator();
+ synchronized (queue) {
+ queue.clear();
+ }
+ willRun = false;
+
+ // queue must already be cleared and willRun reset
+ // because this loop might queue more notifications
+ while (it.hasNext()) {
+ parent.center.postNotification((NSNotification) it.next());
+ }
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/11 18:18:08 chochos
- * improved encoding of strings, removed warnings
+ * Revision 1.6 2003/08/11 18:18:08 chochos improved encoding of strings,
+ * removed warnings
*
- * Revision 1.5 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.5 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.4 2001/11/01 15:49:26 mpowers
- * With NSRunLoop, we can now correctly implement PostASAP and PostWhenIdle.
+ * Revision 1.4 2001/11/01 15:49:26 mpowers With NSRunLoop, we can now correctly
+ * implement PostASAP and PostWhenIdle.
*
- * Revision 1.3 2001/06/25 14:47:24 mpowers
- * Fixed serious error where some notifications were not being posted at all.
- * A simple change to Notifier class fixed the problem. Thanks to glista.
+ * Revision 1.3 2001/06/25 14:47:24 mpowers Fixed serious error where some
+ * notifications were not being posted at all. A simple change to Notifier class
+ * fixed the problem. Thanks to glista.
*
- * Revision 1.2 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.2 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.1 2001/02/24 17:03:22 mpowers
- * Implemented the notification queue, and changed editing context to use it.
+ * Revision 1.1 2001/02/24 17:03:22 mpowers Implemented the notification queue,
+ * and changed editing context to use it.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java
index db1f216..861f576 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java
@@ -21,84 +21,72 @@ package net.wotonomy.foundation;
import java.io.Serializable;
/**
-* NSNull is used to represent null in Collections classes
-* because List and Map do not specify whether null values
-* are allowed and because NSArray and NSDictionary explicitly
-* do not allow null values. <br><br>
-*
-* Use of the static singleton method nullValue() is required
-* by this implementation because Java cannot return a singleton
-* instance from a constructor. Even then, more than one instance
-* may exist in the application due to object serialization.
-* Be sure to compare with equals().
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
-public class NSNull implements Serializable
-{
- private static final NSNull instance = new NSNull();
-
- /**
- * Create a new instance of NSNull.
- */
- private NSNull ()
- {
- }
+ * NSNull is used to represent null in Collections classes because List and Map
+ * do not specify whether null values are allowed and because NSArray and
+ * NSDictionary explicitly do not allow null values. <br>
+ * <br>
+ *
+ * Use of the static singleton method nullValue() is required by this
+ * implementation because Java cannot return a singleton instance from a
+ * constructor. Even then, more than one instance may exist in the application
+ * due to object serialization. Be sure to compare with equals().
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
+public class NSNull implements Serializable {
+ private static final NSNull instance = new NSNull();
- /**
- * Returns the static instance of nullValue.
- * Note that serialization may mean that more than
- * one instance of NSNull exists, so be sure to
- * compare with equals().
- */
- public static NSNull nullValue ()
- {
- return instance;
- }
+ /**
+ * Create a new instance of NSNull.
+ */
+ private NSNull() {
+ }
- /**
- * Returns a human-readable string representation.
- */
- public String toString()
- {
- return "[null]";
- }
-
- /**
- * Hashcode of all instances is zero.
- */
- public int hashCode()
- {
- return 0;
- }
-
- /**
- * Implemented to return true for any instance of NSNull.
- */
- public boolean equals( Object anObject )
- {
- return ( anObject instanceof NSNull );
- }
+ /**
+ * Returns the static instance of nullValue. Note that serialization may mean
+ * that more than one instance of NSNull exists, so be sure to compare with
+ * equals().
+ */
+ public static NSNull nullValue() {
+ return instance;
+ }
+
+ /**
+ * Returns a human-readable string representation.
+ */
+ public String toString() {
+ return "[null]";
+ }
+
+ /**
+ * Hashcode of all instances is zero.
+ */
+ public int hashCode() {
+ return 0;
+ }
+
+ /**
+ * Implemented to return true for any instance of NSNull.
+ */
+ public boolean equals(Object anObject) {
+ return (anObject instanceof NSNull);
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2001/03/01 20:36:09 mpowers
- * Implemented equals, hashcode, and serializable.
+ * Revision 1.2 2001/03/01 20:36:09 mpowers Implemented equals, hashcode, and
+ * serializable.
*
- * Revision 1.1 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.1 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java
index 064ee3c..7e6386d 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java
@@ -24,34 +24,29 @@ package net.wotonomy.foundation;
import java.text.DecimalFormat;
/**
-* A Format that accepts C-style number formatting syntax.
-* Not currently implemented, included for compile compatibility.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A Format that accepts C-style number formatting syntax. Not currently
+ * implemented, included for compile compatibility.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+
+public class NSNumberFormatter extends DecimalFormat {
+ public NSNumberFormatter() {
+ super();
+ }
-public class NSNumberFormatter extends DecimalFormat
-{
- public NSNumberFormatter()
- {
- super();
- }
-
- public NSNumberFormatter(String aPattern)
- {
- super( aPattern );
- }
+ public NSNumberFormatter(String aPattern) {
+ super(aPattern);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/17 14:40:50 mpowers
- * Adding files to fix build.
+ * Revision 1.1 2003/01/17 14:40:50 mpowers Adding files to fix build.
*
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
index 7f8bcc9..b52dc2d 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
@@ -3,273 +3,287 @@ package net.wotonomy.foundation;
public class NSPropertyListSerialization {
- public static final int PLIST_ARRAY = 0;
- public static final int PLIST_DICTIONARY = 1;
- public static final int PLIST_DATA = 2;
- public static final int PLIST_STRING = 3;
+ public static final int PLIST_ARRAY = 0;
+ public static final int PLIST_DICTIONARY = 1;
+ public static final int PLIST_DATA = 2;
+ public static final int PLIST_STRING = 3;
- public static final char[] TOKEN_BEGIN = new char[]{
- '(', '{', '<', '"'
- };
- public static final char[] TOKEN_END = new char[]{
- ')', '}', '>', '"'
- };
- public static final char[] QUOTING_CHARS = new char[]{
- ':', '/', '-', '.', '\\'
- };
+ public static final char[] TOKEN_BEGIN = new char[] { '(', '{', '<', '"' };
+ public static final char[] TOKEN_END = new char[] { ')', '}', '>', '"' };
+ public static final char[] QUOTING_CHARS = new char[] { ':', '/', '-', '.', '\\' };
- private NSPropertyListSerialization() {
- super();
- }
+ private NSPropertyListSerialization() {
+ super();
+ }
- /** Creates a NSArray object from a string representation.
- @s The string representation of a NSArray object. */
- public static NSArray arrayForString(String s) {
- s = s.trim();
- if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_ARRAY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_ARRAY]))
- return null;
- NSMutableArray arr = new NSMutableArray();
- int pos = 1;
- int valbegin = -1;
- while (pos < s.length()) {
- char c = s.charAt(pos);
- int tokenCount = 0;
- int what = 0;
- for (int i = 0 ; i < TOKEN_BEGIN.length; i++) {
- if (c == TOKEN_BEGIN[i]) {
- tokenCount = 1;
- what = i;
- break;
- }
- }
- if (tokenCount > 0) {
- //mark it
- int quote = pos;
- //find the closing token
- do {
- pos++;
+ /**
+ * Creates a NSArray object from a string representation.
+ *
+ * @s The string representation of a NSArray object.
+ */
+ public static NSArray arrayForString(String s) {
+ s = s.trim();
+ if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_ARRAY] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_ARRAY]))
+ return null;
+ NSMutableArray arr = new NSMutableArray();
+ int pos = 1;
+ int valbegin = -1;
+ while (pos < s.length()) {
+ char c = s.charAt(pos);
+ int tokenCount = 0;
+ int what = 0;
+ for (int i = 0; i < TOKEN_BEGIN.length; i++) {
+ if (c == TOKEN_BEGIN[i]) {
+ tokenCount = 1;
+ what = i;
+ break;
+ }
+ }
+ if (tokenCount > 0) {
+ // mark it
+ int quote = pos;
+ // find the closing token
+ do {
+ pos++;
try {
c = s.charAt(pos);
} catch (StringIndexOutOfBoundsException ex) {
- throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
+ throw new IllegalArgumentException(
+ "Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
}
if (c == '"' && what == PLIST_STRING) {
- if (pos > 0 && s.charAt(pos-1) != '\\') {
+ if (pos > 0 && s.charAt(pos - 1) != '\\') {
tokenCount--;
}
} else if (c == TOKEN_BEGIN[what])
- tokenCount++;
- else if (c == TOKEN_END[what])
- tokenCount--;
- } while (tokenCount > 0);
- arr.addObject(propertyListFromString(s.substring(quote, pos+1)));
- valbegin = -1;
- //advance to the next position
- do {
- pos++;
- c = s.charAt(pos);
- } while (Character.isWhitespace(c));
- }
- if (c == ',' || c ==')') {
- if (valbegin > 0) {
- arr.addObject(s.substring(valbegin, pos).trim());
- valbegin = -1;
- }
- } else if (!Character.isWhitespace(c)) {
- if (valbegin < 0) {
- valbegin = pos;
- }
- }
- pos++;
- }
- return arr;
- }
+ tokenCount++;
+ else if (c == TOKEN_END[what])
+ tokenCount--;
+ } while (tokenCount > 0);
+ arr.addObject(propertyListFromString(s.substring(quote, pos + 1)));
+ valbegin = -1;
+ // advance to the next position
+ do {
+ pos++;
+ c = s.charAt(pos);
+ } while (Character.isWhitespace(c));
+ }
+ if (c == ',' || c == ')') {
+ if (valbegin > 0) {
+ arr.addObject(s.substring(valbegin, pos).trim());
+ valbegin = -1;
+ }
+ } else if (!Character.isWhitespace(c)) {
+ if (valbegin < 0) {
+ valbegin = pos;
+ }
+ }
+ pos++;
+ }
+ return arr;
+ }
- /** Creates a NSDictionary instance from a string representation.
- @s The string representation of a NSDictionary. */
- public static NSDictionary dictionaryForString(String s) {
- s = s.trim();
- if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DICTIONARY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DICTIONARY]))
- return null;
- NSMutableDictionary d = new NSMutableDictionary();
- int pos = 1;
- boolean parsing = true;
- Object key = null;
- int valbegin = -1;
- while (pos < s.length()) {
- //look for an opening token
- char c = s.charAt(pos);
- int tokenCount = 0;
- int what = 0;
- for (int i = 0 ; i < TOKEN_BEGIN.length; i++) {
- if (c == TOKEN_BEGIN[i]) {
- tokenCount = 1;
- what = i;
- break;
- }
- }
- if (tokenCount > 0) {
- //mark it
- int quote = pos;
- //find the closing token
- do {
- pos++;
- try {
+ /**
+ * Creates a NSDictionary instance from a string representation.
+ *
+ * @s The string representation of a NSDictionary.
+ */
+ public static NSDictionary dictionaryForString(String s) {
+ s = s.trim();
+ if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DICTIONARY] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_DICTIONARY]))
+ return null;
+ NSMutableDictionary d = new NSMutableDictionary();
+ int pos = 1;
+ boolean parsing = true;
+ Object key = null;
+ int valbegin = -1;
+ while (pos < s.length()) {
+ // look for an opening token
+ char c = s.charAt(pos);
+ int tokenCount = 0;
+ int what = 0;
+ for (int i = 0; i < TOKEN_BEGIN.length; i++) {
+ if (c == TOKEN_BEGIN[i]) {
+ tokenCount = 1;
+ what = i;
+ break;
+ }
+ }
+ if (tokenCount > 0) {
+ // mark it
+ int quote = pos;
+ // find the closing token
+ do {
+ pos++;
+ try {
c = s.charAt(pos);
- } catch (StringIndexOutOfBoundsException ex) {
- throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
- }
- if (c == '"' && what == PLIST_STRING) {
- if (pos > 0 && s.charAt(pos-1) != '\\') {
- tokenCount--;
- }
- } else if (c == TOKEN_BEGIN[what])
- tokenCount++;
- else if (c == TOKEN_END[what])
- tokenCount--;
- } while (tokenCount > 0);
- if (key == null) {
- key = propertyListFromString(s.substring(quote, pos+1));
- } else {
- d.setObjectForKey(propertyListFromString(s.substring(quote, pos+1)), key);
- key = null;
- }
- valbegin = -1;
- //advance to the next position
- do {
- pos++;
- c = s.charAt(pos);
- } while (Character.isWhitespace(c));
- }
- if (c == ';' || c == '=' || c == '}') {
- if (valbegin > 0) {
- if (key == null) {
- key = s.substring(valbegin, pos).trim();
- } else {
- d.setObjectForKey(s.substring(valbegin, pos).trim(), key);
- key = null;
- }
- valbegin = -1;
- }
- } else if (!Character.isWhitespace(c)) {
- if (valbegin < 0) {
- valbegin = pos;
- }
- }
- pos++;
- }
- return d;
- }
+ } catch (StringIndexOutOfBoundsException ex) {
+ throw new IllegalArgumentException(
+ "Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'");
+ }
+ if (c == '"' && what == PLIST_STRING) {
+ if (pos > 0 && s.charAt(pos - 1) != '\\') {
+ tokenCount--;
+ }
+ } else if (c == TOKEN_BEGIN[what])
+ tokenCount++;
+ else if (c == TOKEN_END[what])
+ tokenCount--;
+ } while (tokenCount > 0);
+ if (key == null) {
+ key = propertyListFromString(s.substring(quote, pos + 1));
+ } else {
+ d.setObjectForKey(propertyListFromString(s.substring(quote, pos + 1)), key);
+ key = null;
+ }
+ valbegin = -1;
+ // advance to the next position
+ do {
+ pos++;
+ c = s.charAt(pos);
+ } while (Character.isWhitespace(c));
+ }
+ if (c == ';' || c == '=' || c == '}') {
+ if (valbegin > 0) {
+ if (key == null) {
+ key = s.substring(valbegin, pos).trim();
+ } else {
+ d.setObjectForKey(s.substring(valbegin, pos).trim(), key);
+ key = null;
+ }
+ valbegin = -1;
+ }
+ } else if (!Character.isWhitespace(c)) {
+ if (valbegin < 0) {
+ valbegin = pos;
+ }
+ }
+ pos++;
+ }
+ return d;
+ }
- public static boolean booleanForString(String s) {
- return s.trim().toLowerCase().equals("true");
- }
+ public static boolean booleanForString(String s) {
+ return s.trim().toLowerCase().equals("true");
+ }
- /** Creates a NSData instance from a string representation.
- @s The string representation of a NSData object. */
- public static NSData dataFromPropertyList(String s) {
- String hex = "0123456789ABCDEF";
- s = s.trim();
- if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DATA] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DATA]))
- return null;
- int pos = 1;
- java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
- while (pos < s.length()-1) {
- char c1 = s.charAt(pos);
- while (c1 == ' ') {
- pos++;
- if (pos == s.length()-1)
- return new NSData(bout.toByteArray());
- c1 = s.charAt(pos);
- }
- if (hex.indexOf(c1) < 0)
- throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ", pos " + pos + ")");
- pos++;
- char c2 = s.charAt(pos);
- if (hex.indexOf(c2) < 0)
- throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ")");
- int x = (hex.indexOf(c1) << 4) | hex.indexOf(c2);
- bout.write(x);
- pos++;
- }
- return new NSData(bout.toByteArray());
- }
+ /**
+ * Creates a NSData instance from a string representation.
+ *
+ * @s The string representation of a NSData object.
+ */
+ public static NSData dataFromPropertyList(String s) {
+ String hex = "0123456789ABCDEF";
+ s = s.trim();
+ if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DATA] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_DATA]))
+ return null;
+ int pos = 1;
+ java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
+ while (pos < s.length() - 1) {
+ char c1 = s.charAt(pos);
+ while (c1 == ' ') {
+ pos++;
+ if (pos == s.length() - 1)
+ return new NSData(bout.toByteArray());
+ c1 = s.charAt(pos);
+ }
+ if (hex.indexOf(c1) < 0)
+ throw new IllegalArgumentException(
+ "The string does not represent a NSData object (" + s + ", pos " + pos + ")");
+ pos++;
+ char c2 = s.charAt(pos);
+ if (hex.indexOf(c2) < 0)
+ throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ")");
+ int x = (hex.indexOf(c1) << 4) | hex.indexOf(c2);
+ bout.write(x);
+ pos++;
+ }
+ return new NSData(bout.toByteArray());
+ }
- public static int intForString(String s) {
- return Integer.parseInt(s);
- }
+ public static int intForString(String s) {
+ return Integer.parseInt(s);
+ }
- /** Returns the string representation of a property list.
- @plist The property list. It can be a String, NSData, NSArray, NSDictionary. */
- public static String stringForPropertyList(Object plist) {
- if (plist == null)
- return "";
- if (plist instanceof NSArray || plist instanceof NSDictionary || plist instanceof NSData)
- return plist.toString();
- String x = plist.toString();
- boolean quote = false;
- for (int i = 0; i < x.length(); i++) {
- char c = x.charAt(i);
- for (int z = 0; z < TOKEN_BEGIN.length; z++) {
- if (c == TOKEN_BEGIN[z] || c == TOKEN_END[z])
- quote = true;
- }
- if (!quote) {
- for (int z = 0; z < QUOTING_CHARS.length; z++) {
- if (c == QUOTING_CHARS[z])
- quote = true;
- }
- }
- if (!quote && Character.isWhitespace(c)) {
- quote = true;
- i = x.length();
- }
- }
- if (quote)
- return "\"" + x + "\"";
- return x;
- }
+ /**
+ * Returns the string representation of a property list.
+ *
+ * @plist The property list. It can be a String, NSData, NSArray, NSDictionary.
+ */
+ public static String stringForPropertyList(Object plist) {
+ if (plist == null)
+ return "";
+ if (plist instanceof NSArray || plist instanceof NSDictionary || plist instanceof NSData)
+ return plist.toString();
+ String x = plist.toString();
+ boolean quote = false;
+ for (int i = 0; i < x.length(); i++) {
+ char c = x.charAt(i);
+ for (int z = 0; z < TOKEN_BEGIN.length; z++) {
+ if (c == TOKEN_BEGIN[z] || c == TOKEN_END[z])
+ quote = true;
+ }
+ if (!quote) {
+ for (int z = 0; z < QUOTING_CHARS.length; z++) {
+ if (c == QUOTING_CHARS[z])
+ quote = true;
+ }
+ }
+ if (!quote && Character.isWhitespace(c)) {
+ quote = true;
+ i = x.length();
+ }
+ }
+ if (quote)
+ return "\"" + x + "\"";
+ return x;
+ }
- /** Returns an property list created from a string representation.
- @s The string with a representation of a property list.
- @returns A property list object; either a NSData, NSArray, NSDictionary, or a String. */
- public static Object propertyListFromString(String s) {
- s = s.trim();
- int type = -1;
- for (int i = 0; i < TOKEN_BEGIN.length; i++) {
- if (TOKEN_BEGIN[i] == s.charAt(0)) {
- if (TOKEN_END[i] == s.charAt(s.length()-1))
- type = i;
- }
- }
- switch (type) {
- case PLIST_DATA:
- return dataFromPropertyList(s);
- case PLIST_ARRAY:
- return arrayForString(s);
- case PLIST_DICTIONARY:
- return dictionaryForString(s);
- case PLIST_STRING:
- if (s.equals("\"\""))
- return "";
- return s.substring(1, s.length()-1);
- }
- return s;
- }
+ /**
+ * Returns an property list created from a string representation.
+ *
+ * @s The string with a representation of a property list.
+ * @returns A property list object; either a NSData, NSArray, NSDictionary, or a
+ * String.
+ */
+ public static Object propertyListFromString(String s) {
+ s = s.trim();
+ int type = -1;
+ for (int i = 0; i < TOKEN_BEGIN.length; i++) {
+ if (TOKEN_BEGIN[i] == s.charAt(0)) {
+ if (TOKEN_END[i] == s.charAt(s.length() - 1))
+ type = i;
+ }
+ }
+ switch (type) {
+ case PLIST_DATA:
+ return dataFromPropertyList(s);
+ case PLIST_ARRAY:
+ return arrayForString(s);
+ case PLIST_DICTIONARY:
+ return dictionaryForString(s);
+ case PLIST_STRING:
+ if (s.equals("\"\""))
+ return "";
+ return s.substring(1, s.length() - 1);
+ }
+ return s;
+ }
- /*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
- *
- * Revision 1.5 2003/08/11 18:18:08 chochos
- * improved encoding of strings, removed warnings
- *
- * Revision 1.4 2003/08/11 17:33:45 chochos
- * Implemented detection of escaped quotes (\"). improved quoting strings when converting property lists to strings.
- *
- * Revision 1.3 2003/08/04 23:50:55 chochos
- * propertyListForString() now works. dictionaryForString and arrayForString can parse complex structures with nested arrays and dictionaries.
- *
- */
+ /*
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.5 2003/08/11 18:18:08 chochos improved encoding of strings,
+ * removed warnings
+ *
+ * Revision 1.4 2003/08/11 17:33:45 chochos Implemented detection of escaped
+ * quotes (\"). improved quoting strings when converting property lists to
+ * strings.
+ *
+ * Revision 1.3 2003/08/04 23:50:55 chochos propertyListForString() now works.
+ * dictionaryForString and arrayForString can parse complex structures with
+ * nested arrays and dictionaries.
+ *
+ */
} \ No newline at end of file
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java
index 2de52f5..13dca2f 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java
@@ -19,333 +19,280 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation;
/**
-* A pure java implementation of NSRange.
-* An NSRange represents a range of numbers
-* having a starting location and spanning a
-* length.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 920 $
-*/
-public class NSRange implements Cloneable
-{
- /**
- * An empty range.
- */
- public static final NSRange ZeroRange = new NSRange();
-
- protected int loc;
- protected int len;
-
- /**
- * Default constructor produces an empty range.
- */
- public NSRange ()
- {
- this( 0, 0 );
- }
-
- /**
- * Produces a range with the specified location and length.
- */
- public NSRange (int location, int length)
- {
- loc = location;
- len = length;
- }
-
- /**
- * Produces a range that has the same location and length as
- * the specified range.
- */
- public NSRange (NSRange aRange)
- {
- this( aRange.location(), aRange.length() );
- }
-
- /**
- * Returns the location of this range.
- */
- public int location ()
- {
- return loc;
- }
-
- /**
- * Returns the length of this range.
- */
- public int length ()
- {
- return len;
- }
-
- /**
- * Returns the maximum extent of the range. This number is
- * one more than the last position in the range.
- */
- public int maxRange ()
- {
- return location() + length() -1;
- }
-
- /**
- * Returns whether this is an empty range, therefore
- * whether the length is zero.
- */
- public boolean isEmpty ()
- {
- return ( length() == 0 );
- }
-
- /**
- * Returns whether the specified location is contained
- * within this range.
- */
- public boolean locationInRange (int location)
- {
- if ( location < location() ) return false;
- if ( location >= maxRange() ) return false;
- return true;
- }
-
- /**
- * Returns whether the specified range is equal to this range.
- */
- public boolean isEqualToRange (NSRange aRange)
- {
- if ( aRange == null ) return false;
- return ( ( aRange.location() == location() )
- && ( aRange.length() == length() ) );
- }
-
- /**
- * Returns whether the specified object is equal to this range.
- */
- public boolean equals (Object anObject)
- {
- if ( anObject instanceof NSRange )
- return isEqualToRange( (NSRange) anObject );
+ * A pure java implementation of NSRange. An NSRange represents a range of
+ * numbers having a starting location and spanning a length.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 920 $
+ */
+public class NSRange implements Cloneable {
+ /**
+ * An empty range.
+ */
+ public static final NSRange ZeroRange = new NSRange();
+
+ protected int loc;
+ protected int len;
+
+ /**
+ * Default constructor produces an empty range.
+ */
+ public NSRange() {
+ this(0, 0);
+ }
+
+ /**
+ * Produces a range with the specified location and length.
+ */
+ public NSRange(int location, int length) {
+ loc = location;
+ len = length;
+ }
+
+ /**
+ * Produces a range that has the same location and length as the specified
+ * range.
+ */
+ public NSRange(NSRange aRange) {
+ this(aRange.location(), aRange.length());
+ }
+
+ /**
+ * Returns the location of this range.
+ */
+ public int location() {
+ return loc;
+ }
+
+ /**
+ * Returns the length of this range.
+ */
+ public int length() {
+ return len;
+ }
+
+ /**
+ * Returns the maximum extent of the range. This number is one more than the
+ * last position in the range.
+ */
+ public int maxRange() {
+ return location() + length() - 1;
+ }
+
+ /**
+ * Returns whether this is an empty range, therefore whether the length is zero.
+ */
+ public boolean isEmpty() {
+ return (length() == 0);
+ }
+
+ /**
+ * Returns whether the specified location is contained within this range.
+ */
+ public boolean locationInRange(int location) {
+ if (location < location())
+ return false;
+ if (location >= maxRange())
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns whether the specified range is equal to this range.
+ */
+ public boolean isEqualToRange(NSRange aRange) {
+ if (aRange == null)
+ return false;
+ return ((aRange.location() == location()) && (aRange.length() == length()));
+ }
+
+ /**
+ * Returns whether the specified object is equal to this range.
+ */
+ public boolean equals(Object anObject) {
+ if (anObject instanceof NSRange)
+ return isEqualToRange((NSRange) anObject);
return false;
- }
-
- /**
- * Returns a hashCode.
- */
- public int hashCode ()
- {
- // TODO: Test this logic.
- return ( location() << 2 ) & length(); // bitwise ops never my forte
- }
-
- /**
- * Returns a string representation of this range.
- */
- public String toString ()
- {
- return "[NSRange: location = " + location()
- + "; length = " + length() + "]";
- }
-
- /**
- * Returns the union of this range and the specified range, if any.
- * Gaps are filled, so the result is the smallest starting position
- * and the largest ending position.
- */
- public NSRange rangeByUnioningRange (NSRange aRange)
- {
- if ( aRange == null ) return this;
-
- // TODO: Test this logic.
- int resultLoc = Math.min( this.location(), aRange.location() );
- int resultLen = Math.max( this.location() + this.length(),
- aRange.location() + aRange.length() ) - resultLoc;
- return new NSRange( resultLoc, resultLen );
- }
-
- /**
- * Returns the intersection of this range and the specified range,
- * if any. If no intersection, returns an empty range.
- */
- public NSRange rangeByIntersectingRange (NSRange aRange)
- {
- // TODO: Test this logic.
- if ( ! intersectsRange( aRange ) ) return ZeroRange;
- int start = Math.max( this.location(), aRange.location() );
- int end = Math.min( this.location() + this.length(),
- aRange.location() + aRange.length() );
- return new NSRange( start, end - start );
- }
-
- /**
- * Returns whether the specified range overlaps
- * at any point with this range.
- */
- public boolean intersectsRange (NSRange aRange)
- {
- // TODO: Test this logic.
- if ( aRange == null ) return false;
- if ( ( this.location() >= aRange.location() )
- && ( this.location() < aRange.location() + aRange.length() ) )
+ }
+
+ /**
+ * Returns a hashCode.
+ */
+ public int hashCode() {
+ // TODO: Test this logic.
+ return (location() << 2) & length(); // bitwise ops never my forte
+ }
+
+ /**
+ * Returns a string representation of this range.
+ */
+ public String toString() {
+ return "[NSRange: location = " + location() + "; length = " + length() + "]";
+ }
+
+ /**
+ * Returns the union of this range and the specified range, if any. Gaps are
+ * filled, so the result is the smallest starting position and the largest
+ * ending position.
+ */
+ public NSRange rangeByUnioningRange(NSRange aRange) {
+ if (aRange == null)
+ return this;
+
+ // TODO: Test this logic.
+ int resultLoc = Math.min(this.location(), aRange.location());
+ int resultLen = Math.max(this.location() + this.length(), aRange.location() + aRange.length()) - resultLoc;
+ return new NSRange(resultLoc, resultLen);
+ }
+
+ /**
+ * Returns the intersection of this range and the specified range, if any. If no
+ * intersection, returns an empty range.
+ */
+ public NSRange rangeByIntersectingRange(NSRange aRange) {
+ // TODO: Test this logic.
+ if (!intersectsRange(aRange))
+ return ZeroRange;
+ int start = Math.max(this.location(), aRange.location());
+ int end = Math.min(this.location() + this.length(), aRange.location() + aRange.length());
+ return new NSRange(start, end - start);
+ }
+
+ /**
+ * Returns whether the specified range overlaps at any point with this range.
+ */
+ public boolean intersectsRange(NSRange aRange) {
+ // TODO: Test this logic.
+ if (aRange == null)
+ return false;
+ if ((this.location() >= aRange.location()) && (this.location() < aRange.location() + aRange.length()))
return true;
- if ( ( aRange.location() >= this.location() )
- && ( aRange.location() < this.location() + this.length() ) )
+ if ((aRange.location() >= this.location()) && (aRange.location() < this.location() + this.length()))
return true;
return false;
- }
-
- /**
- * Returns whether this range is completely
- * contained within the specified range.
- */
- public boolean isSubrangeOfRange (NSRange aRange)
- {
- // TODO: Test this logic.
- if ( aRange == null ) return false;
- if ( ( this.location() >= aRange.location() )
- && ( this.maxRange() <= aRange.maxRange() ) )
- return true;
+ }
+
+ /**
+ * Returns whether this range is completely contained within the specified
+ * range.
+ */
+ public boolean isSubrangeOfRange(NSRange aRange) {
+ // TODO: Test this logic.
+ if (aRange == null)
+ return false;
+ if ((this.location() >= aRange.location()) && (this.maxRange() <= aRange.maxRange()))
+ return true;
return false;
- }
-
- /**
- * Eliminates any intersections between this range and the specified
- * range. This produces two ranges, either of which may be empty.
- * These two ranges are returned by modifying the supplied second
- * and third parameters.
- */
- public void subtractRange (NSRange aRange,
- NSMutableRange firstResult, NSMutableRange secondResult)
- {
- if ( aRange == null ) return;
-
- // TODO: Test this logic.
- // no intersection: return this and aRange without calculation
- if ( ! intersectsRange( aRange ) )
- {
- if ( firstResult != null )
- {
- firstResult.setLocation( this.location() );
- firstResult.setLength( this.length() );
- }
- if ( secondResult != null )
- {
- secondResult.setLocation( aRange.location() );
- secondResult.setLength( aRange.location() );
- }
- return;
- }
-
- // TODO: Test this logic.
- // this range is completely contained by other range
- if ( isSubrangeOfRange( aRange ) )
- {
- if ( firstResult != null )
- {
- firstResult.setLocation( aRange.location() );
- firstResult.setLength( this.location() - aRange.location() );
- }
- if ( secondResult != null )
- {
- secondResult.setLocation( this.maxRange() );
- secondResult.setLength(
- aRange.maxRange() - this.maxRange() - 1 ); // test this
- }
- return;
- }
-
- // TODO: Test this logic.
- // other range is completely contained by this range
- if ( aRange.isSubrangeOfRange( this ) )
- {
- if ( firstResult != null )
- {
- firstResult.setLocation( this.location() );
- firstResult.setLength( aRange.location() - this.location() );
- }
- if ( secondResult != null )
- {
- secondResult.setLocation( aRange.maxRange() );
- secondResult.setLength(
- this.maxRange() - aRange.maxRange() - 1 ); // test this
- }
- return;
- }
-
- // TODO: Test this logic.
- // ranges intersect: remove only the intersection
-
- NSRange firstRange, secondRange;
- if ( this.location() <= aRange.location() )
- {
- firstRange = this;
- secondRange = aRange;
- }
- else
- {
- firstRange = aRange;
- secondRange = this;
- }
-
- if ( firstResult != null )
- {
- firstResult.setLocation( firstRange.location() );
- firstResult.setLength(
- secondRange.location() - firstRange.location() );
- }
- if ( secondResult != null )
- {
- secondResult.setLocation( firstRange.maxRange() );
- secondResult.setLength(
- secondRange.maxRange() - aRange.maxRange() - 1 ); // test this
- }
- return;
-
- }
-
- /**
- * Returns a copy of this range.
- */
- public Object clone ()
- {
- return new NSRange( location(), length() );
- }
-
- /**
- * Parses a range from a string of the form "{x,y}" where
- * x is the location and y is the length. If not parsable,
- * an IllegalArgumentException is thrown.
- */
- public static NSRange fromString (String aString)
- {
- // TODO: Test this logic.
- try
- {
- java.util.StringTokenizer tokens =
- new java.util.StringTokenizer( aString, "{,}" );
- int loc = Integer.parseInt( tokens.nextToken() );
- int len = Integer.parseInt( tokens.nextToken() );
- return new NSRange( loc, len );
- }
- catch ( Exception exc )
- {
- throw new IllegalArgumentException( exc.toString() );
- }
- }
-
+ }
+
+ /**
+ * Eliminates any intersections between this range and the specified range. This
+ * produces two ranges, either of which may be empty. These two ranges are
+ * returned by modifying the supplied second and third parameters.
+ */
+ public void subtractRange(NSRange aRange, NSMutableRange firstResult, NSMutableRange secondResult) {
+ if (aRange == null)
+ return;
+
+ // TODO: Test this logic.
+ // no intersection: return this and aRange without calculation
+ if (!intersectsRange(aRange)) {
+ if (firstResult != null) {
+ firstResult.setLocation(this.location());
+ firstResult.setLength(this.length());
+ }
+ if (secondResult != null) {
+ secondResult.setLocation(aRange.location());
+ secondResult.setLength(aRange.location());
+ }
+ return;
+ }
+
+ // TODO: Test this logic.
+ // this range is completely contained by other range
+ if (isSubrangeOfRange(aRange)) {
+ if (firstResult != null) {
+ firstResult.setLocation(aRange.location());
+ firstResult.setLength(this.location() - aRange.location());
+ }
+ if (secondResult != null) {
+ secondResult.setLocation(this.maxRange());
+ secondResult.setLength(aRange.maxRange() - this.maxRange() - 1); // test this
+ }
+ return;
+ }
+
+ // TODO: Test this logic.
+ // other range is completely contained by this range
+ if (aRange.isSubrangeOfRange(this)) {
+ if (firstResult != null) {
+ firstResult.setLocation(this.location());
+ firstResult.setLength(aRange.location() - this.location());
+ }
+ if (secondResult != null) {
+ secondResult.setLocation(aRange.maxRange());
+ secondResult.setLength(this.maxRange() - aRange.maxRange() - 1); // test this
+ }
+ return;
+ }
+
+ // TODO: Test this logic.
+ // ranges intersect: remove only the intersection
+
+ NSRange firstRange, secondRange;
+ if (this.location() <= aRange.location()) {
+ firstRange = this;
+ secondRange = aRange;
+ } else {
+ firstRange = aRange;
+ secondRange = this;
+ }
+
+ if (firstResult != null) {
+ firstResult.setLocation(firstRange.location());
+ firstResult.setLength(secondRange.location() - firstRange.location());
+ }
+ if (secondResult != null) {
+ secondResult.setLocation(firstRange.maxRange());
+ secondResult.setLength(secondRange.maxRange() - aRange.maxRange() - 1); // test this
+ }
+ return;
+
+ }
+
+ /**
+ * Returns a copy of this range.
+ */
+ public Object clone() {
+ return new NSRange(location(), length());
+ }
+
+ /**
+ * Parses a range from a string of the form "{x,y}" where x is the location and
+ * y is the length. If not parsable, an IllegalArgumentException is thrown.
+ */
+ public static NSRange fromString(String aString) {
+ // TODO: Test this logic.
+ try {
+ java.util.StringTokenizer tokens = new java.util.StringTokenizer(aString, "{,}");
+ int loc = Integer.parseInt(tokens.nextToken());
+ int len = Integer.parseInt(tokens.nextToken());
+ return new NSRange(loc, len);
+ } catch (Exception exc) {
+ throw new IllegalArgumentException(exc.toString());
+ }
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:42 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:42 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:38 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java
index 65f58db..999af6c 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java
@@ -24,125 +24,129 @@ package net.wotonomy.foundation;
import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;
/**
-* A lock class that allows a thread to re-acquire it's lock
-* recursively. Currently an API-compliance wrapper around Doug Lea's
-* ReentrantLock, conforming to the API and behavior of
-* com.webobjects.foundation.NSRecursiveLock.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A lock class that allows a thread to re-acquire it's lock recursively.
+ * Currently an API-compliance wrapper around Doug Lea's ReentrantLock,
+ * conforming to the API and behavior of
+ * com.webobjects.foundation.NSRecursiveLock.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class NSRecursiveLock extends ReentrantLock implements NSLocking {
- public NSRecursiveLock() {
- }
- /** Acquire the lock, catching the thrown exception to mirror the
- * behavior of com.webobjects.foundation.NSRecursiveLock. Note that
- * ReentrantLock.acquire() performs a notify() when it's interrupted.
- *
- * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire()
- */
- public void lock() {
- try {
- acquire();
- } catch (InterruptedException interruptedexception) {
- // Null behavior, as notify() is already called
- // by acquire();
- // We may want to log here.
- }
- }
-
- /** Pass the buck to tryLock(long), passing zero time as the parameter.
- *
- * @see #tryLock(long)
- */
- public boolean tryLock() {
- return tryLock(1);
- }
-
- /** Attempt to acquire the lock, catching the thrown exception to mirror
- * the behavior of com.webobjects.foundation.NSRecursiveLock. Note that
- * ReentrantLock.attempt(*) performs a notify() when it's interrupted.
- * Fail gracefully after the given milliseconds
- *
- * @param (long)
- * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire()
- */
- public boolean tryLock(long milliseconds) {
- try {
- return attempt(milliseconds);
- } catch (InterruptedException interruptedexception) {
- // notify() is already called by attempt();
- // We may want to log here.
- return false;
- }
- }
- /**
- * Attempt to acquire a lock until the timestamp is reached. Add
- * 1 to the recursion count if the calling thread already owns the
- * lock. Otherwise block until free or until the given timestamp
- * is reached.
- *
- * @see Timestamp
- * @see ReentrantLock.attempt(long);
- */
- public boolean tryLock(NSTimestamp nstimestamp) {
- return tryLock(nstimestamp.getTime() - System.currentTimeMillis());
- }
-
- /** Unlock the current lock precisely once.
- */
- public synchronized void unlock() {
- unlock(1);
- }
-
- /** Unlock the current lock count times.
- */
- public synchronized void unlock(long count) {
- if (owner_ != null && Thread.currentThread() != owner_)
- throw new IllegalStateException("Illegal Lock usage: unlocking thread not owner.");
- if (owner_ == null || holds_ == 0L)
- throw new IllegalStateException("Illegal Lock usage: unlock() called without a lock().");
+ public NSRecursiveLock() {
+ }
+
+ /**
+ * Acquire the lock, catching the thrown exception to mirror the behavior of
+ * com.webobjects.foundation.NSRecursiveLock. Note that ReentrantLock.acquire()
+ * performs a notify() when it's interrupted.
+ *
+ * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire()
+ */
+ public void lock() {
+ try {
+ acquire();
+ } catch (InterruptedException interruptedexception) {
+ // Null behavior, as notify() is already called
+ // by acquire();
+ // We may want to log here.
+ }
+ }
+
+ /**
+ * Pass the buck to tryLock(long), passing zero time as the parameter.
+ *
+ * @see #tryLock(long)
+ */
+ public boolean tryLock() {
+ return tryLock(1);
+ }
+
+ /**
+ * Attempt to acquire the lock, catching the thrown exception to mirror the
+ * behavior of com.webobjects.foundation.NSRecursiveLock. Note that
+ * ReentrantLock.attempt(*) performs a notify() when it's interrupted. Fail
+ * gracefully after the given milliseconds
+ *
+ * @param (long)
+ * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire()
+ */
+ public boolean tryLock(long milliseconds) {
+ try {
+ return attempt(milliseconds);
+ } catch (InterruptedException interruptedexception) {
+ // notify() is already called by attempt();
+ // We may want to log here.
+ return false;
+ }
+ }
+
+ /**
+ * Attempt to acquire a lock until the timestamp is reached. Add 1 to the
+ * recursion count if the calling thread already owns the lock. Otherwise block
+ * until free or until the given timestamp is reached.
+ *
+ * @see Timestamp
+ * @see ReentrantLock.attempt(long);
+ */
+ public boolean tryLock(NSTimestamp nstimestamp) {
+ return tryLock(nstimestamp.getTime() - System.currentTimeMillis());
+ }
+
+ /**
+ * Unlock the current lock precisely once.
+ */
+ public synchronized void unlock() {
+ unlock(1);
+ }
+
+ /**
+ * Unlock the current lock count times.
+ */
+ public synchronized void unlock(long count) {
+ if (owner_ != null && Thread.currentThread() != owner_)
+ throw new IllegalStateException("Illegal Lock usage: unlocking thread not owner.");
+ if (owner_ == null || holds_ == 0L)
+ throw new IllegalStateException("Illegal Lock usage: unlock() called without a lock().");
release(count);
- }
+ }
- public synchronized long recursionCount() {
+ public synchronized long recursionCount() {
return holds();
- }
+ }
- public String toString() {
- long holds = holds();
- boolean oneHold = (holds == 1);
- boolean noHolds = (holds < 1 || owner_ == null);
- return getClass().getName() + " <" +
- ((noHolds) ? "Unlocked" : ( "Locked " + holds + " time" + (oneHold ? "" : "s") + " by " + owner_ ) ) + ">";
- }
+ public String toString() {
+ long holds = holds();
+ boolean oneHold = (holds == 1);
+ boolean noHolds = (holds < 1 || owner_ == null);
+ return getClass().getName() + " <"
+ + ((noHolds) ? "Unlocked" : ("Locked " + holds + " time" + (oneHold ? "" : "s") + " by " + owner_))
+ + ">";
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.5 2002/06/25 19:02:19 cgruber
- * I'm a dumbass.
+ * Revision 1.5 2002/06/25 19:02:19 cgruber I'm a dumbass.
*
- * Revision 1.4 2002/06/25 18:52:56 cgruber
- * Fix javadocs that resulted from bad cut-and-paste of the boilerplate.
+ * Revision 1.4 2002/06/25 18:52:56 cgruber Fix javadocs that resulted from bad
+ * cut-and-paste of the boilerplate.
*
- * Revision 1.3 2002/06/25 18:45:27 cgruber
- * Add some javadocs.
+ * Revision 1.3 2002/06/25 18:45:27 cgruber Add some javadocs.
*
- * Revision 1.2 2002/06/25 18:06:48 cgruber
- * Add implementation of NSRecursiveLock using Doug Lea's concurrent programming APIs.
- * Specifically inherit from ReentrantLock, which magically does the exact job we want!
+ * Revision 1.2 2002/06/25 18:06:48 cgruber Add implementation of
+ * NSRecursiveLock using Doug Lea's concurrent programming APIs. Specifically
+ * inherit from ReentrantLock, which magically does the exact job we want!
*
- * Revision 1.1 2002/06/25 07:52:56 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java
index 2d122aa..c72cd23 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java
@@ -28,495 +28,421 @@ import java.util.List;
import java.util.ListIterator;
/**
-* NSRunLoop is provided specifically for EODelayedObserverQueue
-* and EOEditingContext, which assume the existence of a
-* prioritized event queue that Java does not provide. <br><br>
-*
-* This extends java.awt.EventQueue and does not conform to the
-* NSRunLoop specifications. The only supported methods are
-* NSRunLoop.currentRunLoop, performSelectorWithOrder, and
-* cancelSelectorWithOrder. Note that in Swing there is only
-* one AWT thread and one event queue; newly created threads
-* will not get their own run loop as in OpenStep.<br><br>
-*
-* That said, this event queue is servicable as a replacement
-* for the default event queue and will provide prioritized
-* execution of selectors before and after normal AWT events.
-* <br><br>
-*
-* Each run loop dispatches the lowest order event from
-* the queue. When queued events have the same ordering,
-* they are dispatched as first-in, first-out (FIFO). Because
-* all AWT events have the same ordering (AWTEventsRunLoopOrdering),
-* they are processed FIFO, just like the default event queue. <br><br>
-*
-* Note that because EventQueue is not well-factored for
-* subclassing, pushing a new event queue onto the stack
-* on top of this one will only copy the existing AWT events
-* to the new queue. For this reason, pushing new event
-* queues onto the stack is not supported and will throw
-* an exception.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSRunLoop extends EventQueue
-{
- /**
- * This is the ordering at which the conventional AWT event
- * queue will be executed. Selectors with this ordering
- * or less will be executed before AWT events, and
- * selectors with ordering greater than this ordering will be
- * be executed after AWT events.
- */
- public static final int AWTEventsRunLoopOrdering = 500000;
-
- /**
- * The singleton instance.
- */
- protected static NSRunLoop instance;
-
- private LinkedList earlyQueue;
- private LinkedList lateQueue;
-
- /**
- * Needed because JDK1.4 made our lives more difficult.
- */
- private static Toolkit toolkit;
-
- /**
- * Because SunToolkit.flushPendingEvents was changed
- * to a static method in 1.4, you can't compile the library
- * in such a way that it works with both 1.3 and 1.4.
- * So we have to rely on dynamic method invocation,
- * which is slower, but we try to make it as fast as
- * humanly possible.
- */
- private static NSSelector flushPendingEvents;
-
- /**
- * Create a new instance of NSRunLoop.
- */
- protected NSRunLoop ()
- {
- earlyQueue = new LinkedList();
- lateQueue = new LinkedList();
- }
-
- /**
- * Returns the singleton instance of NSRunLoop.
- * This returns the same instance no matter what
- * thread calls it, which is different from OpenStep.
- * NSRunLoop is limited to a singleton instance
- * because there is no way of obtaining the stack
- * of event queues from EventQueue because it is
- * private state.
- */
- public synchronized static NSRunLoop currentRunLoop ()
- {
- if ( instance == null )
- {
- // create and initialize
- flushPendingEvents = new NSSelector( "flushPendingEvents" );
- toolkit = Toolkit.getDefaultToolkit();
- instance = new NSRunLoop();
-
- toolkit.getSystemEventQueue().push( instance );
- }
-
- return instance;
- }
-
- /**
- * Post a 1.1-style event to the EventQueue. If there is an
- * existing event on the queue with the same ID and event source,
- * the source Component's coalesceEvents method will be called.
- *
- * @param theEvent an instance of java.awt.AWTEvent, or a
- * subclass of it.
- */
- public void postEvent(AWTEvent theEvent)
- {
- if ( theEvent instanceof OrderedInvocationEvent )
- {
- OrderedInvocationEvent event = (OrderedInvocationEvent) theEvent;
- if ( event.getOrdering() > AWTEventsRunLoopOrdering )
- {
- insertEventIntoQueue( event, lateQueue );
- }
- else
- {
- insertEventIntoQueue( event, earlyQueue );
- }
- }
- else
- {
- super.postEvent( theEvent );
- }
- }
-
- private synchronized void insertEventIntoQueue( OrderedInvocationEvent e, LinkedList q )
- {
- OrderedInvocationEvent o;
- int ordering = e.getOrdering();
- ListIterator iterator =
- q.listIterator();
-
- // iterate forwards until we find a priority
- // greater than our priority,
- // then insert ourself before that element.
- while ( iterator.hasNext() )
- {
- o = (OrderedInvocationEvent) iterator.next();
- if ( o.getOrdering() > ordering )
- {
- // back up one
- iterator.previous();
- break;
- }
- }
- // add after the current element
- iterator.add( e );
- }
-
- /**
- * Useful method, but not in the spec.
- * Dispatches the next AWT event in the queue.
- * Returns whether a selector or an event was executed:
- * if the event queue is empty, returns false.
- */
- public boolean dispatchNextEvent()
- {
- // check for empty queue to avoid blocking
- if ( peekEvent() == null )
- {
- return false;
- }
-
- // queue not empty: dispatch the next event
- try
- {
- dispatchEvent( getNextEvent() );
- }
- catch ( InterruptedException exc )
- {
- System.out.println( "NSRunLoop: error while dispatching event: " );
- exc.printStackTrace();
- }
- return true;
- }
-
- /**
- * Useful method, but not in the spec.
- * Dispatches all events in the queue before returning.
- */
- public void dispatchAllEvents()
- {
- while ( dispatchNextEvent() );
- }
-
- /**
- * Remove an event from the EventQueue and return it.
- * This override will dispatch all selectors up to 5000,
- * and then check if there are AWT events on the queue.
- * If the queue is empty, all remaining selectors
- * are dispatched. Then, this method calls the
- * super class' implementation.
- * @return the next AWTEvent
- * @exception InterruptedException
- * if another thread has interrupted this thread.
- */
- public AWTEvent getNextEvent() throws InterruptedException
- {
- //NOTE: it's currently unclear to me whether we should
- // be operating as a run loop or as a priority queue.
- // I'm opting for priority queue now, but that means that
- // selectors that requeue themselves could hang the application.
- // In the future, we could fake a run loop by putting a marker
- // event on the AWT queue to mark the boundary between loops.
-
- AWTEvent result;
-
- while ( true )
- {
- //NOTE: as of java 1.4, we have to flush pending events
- // using this cheesy undocumented method on suntoolkit.
- // Unsurprisingly, java.awt.EventQueue got worse, not better.
- // See notes above about our use of an NSSelector.
- try
- {
- flushPendingEvents.invoke( toolkit );
- }
- catch ( Throwable t )
- {
- System.out.println( "NSRunLoop.getNextEvent: " + Thread.currentThread() );
- System.err.println( "Unexpected error while flushing pending events: " );
- t.printStackTrace();
- };
-
- synchronized( this )
- {
- result = popNextEarlyEvent();
- if ( result != null )
- {
+ * NSRunLoop is provided specifically for EODelayedObserverQueue and
+ * EOEditingContext, which assume the existence of a prioritized event queue
+ * that Java does not provide. <br>
+ * <br>
+ *
+ * This extends java.awt.EventQueue and does not conform to the NSRunLoop
+ * specifications. The only supported methods are NSRunLoop.currentRunLoop,
+ * performSelectorWithOrder, and cancelSelectorWithOrder. Note that in Swing
+ * there is only one AWT thread and one event queue; newly created threads will
+ * not get their own run loop as in OpenStep.<br>
+ * <br>
+ *
+ * That said, this event queue is servicable as a replacement for the default
+ * event queue and will provide prioritized execution of selectors before and
+ * after normal AWT events. <br>
+ * <br>
+ *
+ * Each run loop dispatches the lowest order event from the queue. When queued
+ * events have the same ordering, they are dispatched as first-in, first-out
+ * (FIFO). Because all AWT events have the same ordering
+ * (AWTEventsRunLoopOrdering), they are processed FIFO, just like the default
+ * event queue. <br>
+ * <br>
+ *
+ * Note that because EventQueue is not well-factored for subclassing, pushing a
+ * new event queue onto the stack on top of this one will only copy the existing
+ * AWT events to the new queue. For this reason, pushing new event queues onto
+ * the stack is not supported and will throw an exception.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSRunLoop extends EventQueue {
+ /**
+ * This is the ordering at which the conventional AWT event queue will be
+ * executed. Selectors with this ordering or less will be executed before AWT
+ * events, and selectors with ordering greater than this ordering will be be
+ * executed after AWT events.
+ */
+ public static final int AWTEventsRunLoopOrdering = 500000;
+
+ /**
+ * The singleton instance.
+ */
+ protected static NSRunLoop instance;
+
+ private LinkedList earlyQueue;
+ private LinkedList lateQueue;
+
+ /**
+ * Needed because JDK1.4 made our lives more difficult.
+ */
+ private static Toolkit toolkit;
+
+ /**
+ * Because SunToolkit.flushPendingEvents was changed to a static method in 1.4,
+ * you can't compile the library in such a way that it works with both 1.3 and
+ * 1.4. So we have to rely on dynamic method invocation, which is slower, but we
+ * try to make it as fast as humanly possible.
+ */
+ private static NSSelector flushPendingEvents;
+
+ /**
+ * Create a new instance of NSRunLoop.
+ */
+ protected NSRunLoop() {
+ earlyQueue = new LinkedList();
+ lateQueue = new LinkedList();
+ }
+
+ /**
+ * Returns the singleton instance of NSRunLoop. This returns the same instance
+ * no matter what thread calls it, which is different from OpenStep. NSRunLoop
+ * is limited to a singleton instance because there is no way of obtaining the
+ * stack of event queues from EventQueue because it is private state.
+ */
+ public synchronized static NSRunLoop currentRunLoop() {
+ if (instance == null) {
+ // create and initialize
+ flushPendingEvents = new NSSelector("flushPendingEvents");
+ toolkit = Toolkit.getDefaultToolkit();
+ instance = new NSRunLoop();
+
+ toolkit.getSystemEventQueue().push(instance);
+ }
+
+ return instance;
+ }
+
+ /**
+ * Post a 1.1-style event to the EventQueue. If there is an existing event on
+ * the queue with the same ID and event source, the source Component's
+ * coalesceEvents method will be called.
+ *
+ * @param theEvent an instance of java.awt.AWTEvent, or a subclass of it.
+ */
+ public void postEvent(AWTEvent theEvent) {
+ if (theEvent instanceof OrderedInvocationEvent) {
+ OrderedInvocationEvent event = (OrderedInvocationEvent) theEvent;
+ if (event.getOrdering() > AWTEventsRunLoopOrdering) {
+ insertEventIntoQueue(event, lateQueue);
+ } else {
+ insertEventIntoQueue(event, earlyQueue);
+ }
+ } else {
+ super.postEvent(theEvent);
+ }
+ }
+
+ private synchronized void insertEventIntoQueue(OrderedInvocationEvent e, LinkedList q) {
+ OrderedInvocationEvent o;
+ int ordering = e.getOrdering();
+ ListIterator iterator = q.listIterator();
+
+ // iterate forwards until we find a priority
+ // greater than our priority,
+ // then insert ourself before that element.
+ while (iterator.hasNext()) {
+ o = (OrderedInvocationEvent) iterator.next();
+ if (o.getOrdering() > ordering) {
+ // back up one
+ iterator.previous();
+ break;
+ }
+ }
+ // add after the current element
+ iterator.add(e);
+ }
+
+ /**
+ * Useful method, but not in the spec. Dispatches the next AWT event in the
+ * queue. Returns whether a selector or an event was executed: if the event
+ * queue is empty, returns false.
+ */
+ public boolean dispatchNextEvent() {
+ // check for empty queue to avoid blocking
+ if (peekEvent() == null) {
+ return false;
+ }
+
+ // queue not empty: dispatch the next event
+ try {
+ dispatchEvent(getNextEvent());
+ } catch (InterruptedException exc) {
+ System.out.println("NSRunLoop: error while dispatching event: ");
+ exc.printStackTrace();
+ }
+ return true;
+ }
+
+ /**
+ * Useful method, but not in the spec. Dispatches all events in the queue before
+ * returning.
+ */
+ public void dispatchAllEvents() {
+ while (dispatchNextEvent())
+ ;
+ }
+
+ /**
+ * Remove an event from the EventQueue and return it. This override will
+ * dispatch all selectors up to 5000, and then check if there are AWT events on
+ * the queue. If the queue is empty, all remaining selectors are dispatched.
+ * Then, this method calls the super class' implementation.
+ *
+ * @return the next AWTEvent
+ * @exception InterruptedException if another thread has interrupted this
+ * thread.
+ */
+ public AWTEvent getNextEvent() throws InterruptedException {
+ // NOTE: it's currently unclear to me whether we should
+ // be operating as a run loop or as a priority queue.
+ // I'm opting for priority queue now, but that means that
+ // selectors that requeue themselves could hang the application.
+ // In the future, we could fake a run loop by putting a marker
+ // event on the AWT queue to mark the boundary between loops.
+
+ AWTEvent result;
+
+ while (true) {
+ // NOTE: as of java 1.4, we have to flush pending events
+ // using this cheesy undocumented method on suntoolkit.
+ // Unsurprisingly, java.awt.EventQueue got worse, not better.
+ // See notes above about our use of an NSSelector.
+ try {
+ flushPendingEvents.invoke(toolkit);
+ } catch (Throwable t) {
+ System.out.println("NSRunLoop.getNextEvent: " + Thread.currentThread());
+ System.err.println("Unexpected error while flushing pending events: ");
+ t.printStackTrace();
+ }
+ ;
+
+ synchronized (this) {
+ result = popNextEarlyEvent();
+ if (result != null) {
//System.out.println( "getNextEvent: early : " + result );
- return result;
- }
- }
-
- if ( ( result = peekEvent() ) != null )
- {
+ return result;
+ }
+ }
+
+ if ((result = peekEvent()) != null) {
//System.out.println( "getNextEvent: AWT : " + result );
- return super.getNextEvent();
- }
-
- synchronized( this )
- {
- result = popNextLateEvent();
- if ( result != null )
- {
+ return super.getNextEvent();
+ }
+
+ synchronized (this) {
+ result = popNextLateEvent();
+ if (result != null) {
//System.out.println( "getNextEvent: late : " + result );
- return result;
- }
-
- // yield
+ return result;
+ }
+
+ // yield
//System.out.println( "getNextEvent: wait" );
- wait();
+ wait();
//System.out.println( "getNextEvent: notified" );
- }
- }
- }
-
- private AWTEvent popNextEarlyEvent()
- {
- if ( earlyQueue == null ) return null; // shouldn't be necessary, but is
- if ( earlyQueue.isEmpty() ) return null;
- return (AWTEvent) earlyQueue.removeFirst();
- }
-
- private AWTEvent popNextLateEvent()
- {
- if ( lateQueue == null ) return null; // shouldn't be necessary, but is
- if ( lateQueue.isEmpty() ) return null;
- return (AWTEvent) lateQueue.removeFirst();
- }
-
- /**
- * This implementation calls super and then throws an
- * UnsupportedOperationException. Catch that exception
- * and ignore it if you know what you are doing.
- */
- public synchronized void push(EventQueue newEventQueue)
- {
- super.push( newEventQueue );
- throw new UnsupportedOperationException(
- "NSRunLoop may not function properly with push()" );
- }
-
- /**
- * This implementation calls super and then throws an
- * UnsupportedOperationException. Catch that exception
- * and ignore it if you know what you are doing.
- */
- protected void pop() throws EmptyStackException
- {
- super.pop();
- throw new UnsupportedOperationException(
- "NSRunLoop may not function properly with pop()" );
- }
-
- /**
- * Schedules the specified selector with the specified target and parameter
- * to be invoked on the next event loop with the specified ordering.
- * The selector must be able to be invoked on the target and the target method
- * must accept the parameter. aModeList is currently ignored.
- */
- public void performSelectorWithOrder(
- NSSelector aSelector, Object aTarget, Object aParameter, int anOrdering, List aModeList )
- {
- postEvent( new OrderedInvocationEvent( aSelector, aTarget, aParameter, anOrdering, aModeList ) );
- }
-
- /**
- * Cancels the next scheduled invocation of the specified selector, target, and parameter.
- * If no such invocation is scheduled, does nothing.
- */
- public synchronized void cancelPerformSelectorWithOrder(
- NSSelector aSelector, Object aTarget, Object aParameter )
- {
- ListIterator i;
- i = earlyQueue.listIterator();
- while ( i.hasNext() )
- {
- if ( ((OrderedInvocationEvent)i.next()).compareTo(
- aSelector, aTarget, aParameter ) )
- {
- i.remove();
- return;
- }
- }
- i = lateQueue.listIterator();
- while ( i.hasNext() )
- {
- if ( ((OrderedInvocationEvent)i.next()).compareTo(
- aSelector, aTarget, aParameter ) )
- {
- i.remove();
- return;
- }
- }
- }
-
- /**
- * Causes runnable to have its run() method on the next
- * event loop with the specified priority ordering.
- */
- public static void invokeLaterWithOrder(Runnable aRunnable, int anOrdering) {
- currentRunLoop().postEvent(
- new OrderedInvocationEvent( Toolkit.getDefaultToolkit(), aRunnable, anOrdering ) );
- }
-
- /**
- * An invocation event that can specify a priority for execution.
- * The prioritization only works if the current event queue is an
- * NSRunLoop; otherwise, performs as a normal invocation event.
- */
- private static class OrderedInvocationEvent extends InvocationEvent
- {
- int ordering;
- NSSelector selector = null;
- Object target = null;
- Object parameter = null;
-
- /**
- * Constructs an InvocationEvent with the specified source which will
- * execute the runnable's run() method when dispatched at the specified ordering.
- */
- public OrderedInvocationEvent(Object source,
- Runnable runnable, int anOrdering)
- {
- super( source, runnable );
- ordering = anOrdering;
- }
-
- /**
- * Constructs an InvocationEvent with the specified source which will
- * execute the runnable's run() method when dispatched at the specified ordering.
- * If notifier is non-null, notifyAll() will be called on it immediately after run() returns.
- */
- public OrderedInvocationEvent(Object source,
- Runnable runnable,
- Object notifier,
- boolean catchExceptions, int anOrdering)
- {
- super( source, runnable, notifier, catchExceptions );
- ordering = anOrdering;
- }
-
- OrderedInvocationEvent(
- final NSSelector aSelector,
- final Object aTarget,
- final Object aParameter,
- int anOrdering, List aModeList)
- {
- this( Toolkit.getDefaultToolkit(), new Runnable()
- {
- public void run()
- {
- try
- {
- aSelector.invoke( aTarget, aParameter );
- }
- catch ( Exception exc )
- {
- System.out.println( "NSRunLoop: error invoking selector: " );
- exc.printStackTrace();
- }
- }
- }, anOrdering );
-
- selector = aSelector;
- target = aTarget;
- parameter = aParameter;
- }
-
- /**
- * Called by cancelPerformSelectorWithOrder.
- * Compares against the specified arguments.
- */
- boolean compareTo( NSSelector aSelector, Object aTarget, Object aParameter )
- {
- return (
- compareByValue( selector, aSelector ) &&
- compareByValue( target, aTarget ) &&
- compareByValue( parameter, aParameter ) );
- }
-
- private boolean compareByValue( Object first, Object second )
- {
- if ( first == second ) return true;
- if ( first == null ) return second.equals( first );
- return first.equals( second );
-
- }
-
- /**
- * Returns the ordering for this event in the run loop.
- */
- public int getOrdering()
- {
- return ordering;
- }
-
- }
-
+ }
+ }
+ }
+
+ private AWTEvent popNextEarlyEvent() {
+ if (earlyQueue == null)
+ return null; // shouldn't be necessary, but is
+ if (earlyQueue.isEmpty())
+ return null;
+ return (AWTEvent) earlyQueue.removeFirst();
+ }
+
+ private AWTEvent popNextLateEvent() {
+ if (lateQueue == null)
+ return null; // shouldn't be necessary, but is
+ if (lateQueue.isEmpty())
+ return null;
+ return (AWTEvent) lateQueue.removeFirst();
+ }
+
+ /**
+ * This implementation calls super and then throws an
+ * UnsupportedOperationException. Catch that exception and ignore it if you know
+ * what you are doing.
+ */
+ public synchronized void push(EventQueue newEventQueue) {
+ super.push(newEventQueue);
+ throw new UnsupportedOperationException("NSRunLoop may not function properly with push()");
+ }
+
+ /**
+ * This implementation calls super and then throws an
+ * UnsupportedOperationException. Catch that exception and ignore it if you know
+ * what you are doing.
+ */
+ protected void pop() throws EmptyStackException {
+ super.pop();
+ throw new UnsupportedOperationException("NSRunLoop may not function properly with pop()");
+ }
+
+ /**
+ * Schedules the specified selector with the specified target and parameter to
+ * be invoked on the next event loop with the specified ordering. The selector
+ * must be able to be invoked on the target and the target method must accept
+ * the parameter. aModeList is currently ignored.
+ */
+ public void performSelectorWithOrder(NSSelector aSelector, Object aTarget, Object aParameter, int anOrdering,
+ List aModeList) {
+ postEvent(new OrderedInvocationEvent(aSelector, aTarget, aParameter, anOrdering, aModeList));
+ }
+
+ /**
+ * Cancels the next scheduled invocation of the specified selector, target, and
+ * parameter. If no such invocation is scheduled, does nothing.
+ */
+ public synchronized void cancelPerformSelectorWithOrder(NSSelector aSelector, Object aTarget, Object aParameter) {
+ ListIterator i;
+ i = earlyQueue.listIterator();
+ while (i.hasNext()) {
+ if (((OrderedInvocationEvent) i.next()).compareTo(aSelector, aTarget, aParameter)) {
+ i.remove();
+ return;
+ }
+ }
+ i = lateQueue.listIterator();
+ while (i.hasNext()) {
+ if (((OrderedInvocationEvent) i.next()).compareTo(aSelector, aTarget, aParameter)) {
+ i.remove();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Causes runnable to have its run() method on the next event loop with the
+ * specified priority ordering.
+ */
+ public static void invokeLaterWithOrder(Runnable aRunnable, int anOrdering) {
+ currentRunLoop().postEvent(new OrderedInvocationEvent(Toolkit.getDefaultToolkit(), aRunnable, anOrdering));
+ }
+
+ /**
+ * An invocation event that can specify a priority for execution. The
+ * prioritization only works if the current event queue is an NSRunLoop;
+ * otherwise, performs as a normal invocation event.
+ */
+ private static class OrderedInvocationEvent extends InvocationEvent {
+ int ordering;
+ NSSelector selector = null;
+ Object target = null;
+ Object parameter = null;
+
+ /**
+ * Constructs an InvocationEvent with the specified source which will execute
+ * the runnable's run() method when dispatched at the specified ordering.
+ */
+ public OrderedInvocationEvent(Object source, Runnable runnable, int anOrdering) {
+ super(source, runnable);
+ ordering = anOrdering;
+ }
+
+ /**
+ * Constructs an InvocationEvent with the specified source which will execute
+ * the runnable's run() method when dispatched at the specified ordering. If
+ * notifier is non-null, notifyAll() will be called on it immediately after
+ * run() returns.
+ */
+ public OrderedInvocationEvent(Object source, Runnable runnable, Object notifier, boolean catchExceptions,
+ int anOrdering) {
+ super(source, runnable, notifier, catchExceptions);
+ ordering = anOrdering;
+ }
+
+ OrderedInvocationEvent(final NSSelector aSelector, final Object aTarget, final Object aParameter,
+ int anOrdering, List aModeList) {
+ this(Toolkit.getDefaultToolkit(), new Runnable() {
+ public void run() {
+ try {
+ aSelector.invoke(aTarget, aParameter);
+ } catch (Exception exc) {
+ System.out.println("NSRunLoop: error invoking selector: ");
+ exc.printStackTrace();
+ }
+ }
+ }, anOrdering);
+
+ selector = aSelector;
+ target = aTarget;
+ parameter = aParameter;
+ }
+
+ /**
+ * Called by cancelPerformSelectorWithOrder. Compares against the specified
+ * arguments.
+ */
+ boolean compareTo(NSSelector aSelector, Object aTarget, Object aParameter) {
+ return (compareByValue(selector, aSelector) && compareByValue(target, aTarget)
+ && compareByValue(parameter, aParameter));
+ }
+
+ private boolean compareByValue(Object first, Object second) {
+ if (first == second)
+ return true;
+ if (first == null)
+ return second.equals(first);
+ return first.equals(second);
+
+ }
+
+ /**
+ * Returns the ordering for this event in the run loop.
+ */
+ public int getOrdering() {
+ return ordering;
+ }
+
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.13 2003/06/06 20:48:19 mpowers
- * Fixed race condition when run loop is started from main thread.
- * That was causing the dispatch thread to call getNextEvent before the
- * static fields had been initialized.
+ * Revision 1.13 2003/06/06 20:48:19 mpowers Fixed race condition when run loop
+ * is started from main thread. That was causing the dispatch thread to call
+ * getNextEvent before the static fields had been initialized.
*
- * Revision 1.12 2003/06/03 14:52:11 mpowers
- * Super constructor was calling getNextEvent before selector was created.
+ * Revision 1.12 2003/06/03 14:52:11 mpowers Super constructor was calling
+ * getNextEvent before selector was created.
*
- * Revision 1.10 2002/05/28 21:59:19 mpowers
- * We now can compile against 1.3 and 1.4, as well as run against both too.
+ * Revision 1.10 2002/05/28 21:59:19 mpowers We now can compile against 1.3 and
+ * 1.4, as well as run against both too.
*
- * Revision 1.9 2002/04/09 18:10:45 mpowers
- * Fixes for 1.4. Commented out until we start building on 1.4.
+ * Revision 1.9 2002/04/09 18:10:45 mpowers Fixes for 1.4. Commented out until
+ * we start building on 1.4.
*
- * Revision 1.8 2002/02/13 21:20:15 mpowers
- * Updated comments.
+ * Revision 1.8 2002/02/13 21:20:15 mpowers Updated comments.
*
- * Revision 1.7 2001/11/01 15:48:49 mpowers
- * Additional debug code.
+ * Revision 1.7 2001/11/01 15:48:49 mpowers Additional debug code.
*
- * Revision 1.6 2001/10/30 22:14:35 mpowers
- * Constructor is now protected, not private.
+ * Revision 1.6 2001/10/30 22:14:35 mpowers Constructor is now protected, not
+ * private.
*
- * Revision 1.5 2001/10/29 20:41:49 mpowers
- * Improved docs, better support for potential subclassing, invokeLater.
+ * Revision 1.5 2001/10/29 20:41:49 mpowers Improved docs, better support for
+ * potential subclassing, invokeLater.
*
- * Revision 1.4 2001/10/26 18:46:30 mpowers
- * Now running AWT events with the appropriate ordering.
- * Added invokeLaterWithOrder for java compatibility.
+ * Revision 1.4 2001/10/26 18:46:30 mpowers Now running AWT events with the
+ * appropriate ordering. Added invokeLaterWithOrder for java compatibility.
*
- * Revision 1.3 2001/10/26 14:39:46 mpowers
- * Completed implementation.
+ * Revision 1.3 2001/10/26 14:39:46 mpowers Completed implementation.
*
- * Revision 1.2 2001/10/25 22:20:21 mpowers
- * Got to check in an interim version - this will briefly break the build.
+ * Revision 1.2 2001/10/25 22:20:21 mpowers Got to check in an interim version -
+ * this will briefly break the build.
*
- * Revision 1.1 2001/10/24 19:30:38 mpowers
- * Initial check-in: incomplete implementation.
+ * Revision 1.1 2001/10/24 19:30:38 mpowers Initial check-in: incomplete
+ * implementation.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java
index 965606b..8f5969a 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java
@@ -26,366 +26,298 @@ import java.util.Comparator;
import net.wotonomy.foundation.internal.PropertyComparator;
/**
-* A pure java implementation of NSSelector.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
-public class NSSelector implements Comparator, Serializable
-{
+ * A pure java implementation of NSSelector.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
+public class NSSelector implements Comparator, Serializable {
protected NSMutableDictionary methodMap; // map of classes to methods
protected String methodName;
protected Class[] parameterTypes;
/**
- * A marker to indicate object not found.
- */
+ * A marker to indicate object not found.
+ */
protected static final String NOT_FOUND = "NOT_FOUND";
-
+
/**
- * Saves creating a new class array for parameterless method invocation.
- */
+ * Saves creating a new class array for parameterless method invocation.
+ */
protected static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
-
+
/**
- * Saves creating a new object array for parameterless method invocation.
- */
+ * Saves creating a new object array for parameterless method invocation.
+ */
protected static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
-
- /**
- * Constructor specifying a method name and an array of parameter types.
- */
- public NSSelector (String aMethodName, Class[] aParameterTypeArray)
- {
- methodName = aMethodName;
- parameterTypes = aParameterTypeArray;
- methodMap = new NSMutableDictionary();
- }
-
- /**
- * Constructor specifying a method name with no parameters.
- */
- public NSSelector (String aMethodName)
- {
- this( aMethodName, EMPTY_CLASS_ARRAY );
- }
-
- /**
- * Constructor for custom subclasses that implement specific operators
- * and that do not use dynamic method invocation.
- */
- protected NSSelector()
- {
- }
-
- /**
- * Returns the name of the method.
- */
- public String name ()
- {
- return methodName;
- }
-
- /**
- * Returns the array of parameter types.
- */
- public Class[] parameterTypes ()
- {
- return parameterTypes;
- }
-
- /**
- * A String description of this selector.
- */
- public String toString ()
- {
- StringBuffer result = new StringBuffer();
- result.append( "[" + getClass().getName() + ": name = " + name() + ", parameter types = [" );
- if ( parameterTypes != null )
- {
- if ( parameterTypes.length > 0 )
- {
- result.append( parameterTypes[0].toString() );
- }
- for ( int i = 1; i < parameterTypes.length; i++ )
- {
- result.append( ", " );
- result.append( parameterTypes[i].toString() );
- }
- }
- result.append( "] ]" );
- return result.toString();
- }
-
- /**
- * Returns the appropriate method for the specified class.
- */
- public Method methodOnClass (Class aClass)
- throws NoSuchMethodException
- {
- Object result = methodMap.objectForKey( aClass );
-
- if ( result == null )
- {
- result = getMethodForClass( aClass );
- if ( result == null )
- {
- result = NOT_FOUND;
- }
- methodMap.setObjectForKey( result, aClass );
+
+ /**
+ * Constructor specifying a method name and an array of parameter types.
+ */
+ public NSSelector(String aMethodName, Class[] aParameterTypeArray) {
+ methodName = aMethodName;
+ parameterTypes = aParameterTypeArray;
+ methodMap = new NSMutableDictionary();
+ }
+
+ /**
+ * Constructor specifying a method name with no parameters.
+ */
+ public NSSelector(String aMethodName) {
+ this(aMethodName, EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Constructor for custom subclasses that implement specific operators and that
+ * do not use dynamic method invocation.
+ */
+ protected NSSelector() {
+ }
+
+ /**
+ * Returns the name of the method.
+ */
+ public String name() {
+ return methodName;
+ }
+
+ /**
+ * Returns the array of parameter types.
+ */
+ public Class[] parameterTypes() {
+ return parameterTypes;
+ }
+
+ /**
+ * A String description of this selector.
+ */
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append("[" + getClass().getName() + ": name = " + name() + ", parameter types = [");
+ if (parameterTypes != null) {
+ if (parameterTypes.length > 0) {
+ result.append(parameterTypes[0].toString());
+ }
+ for (int i = 1; i < parameterTypes.length; i++) {
+ result.append(", ");
+ result.append(parameterTypes[i].toString());
+ }
+ }
+ result.append("] ]");
+ return result.toString();
+ }
+
+ /**
+ * Returns the appropriate method for the specified class.
+ */
+ public Method methodOnClass(Class aClass) throws NoSuchMethodException {
+ Object result = methodMap.objectForKey(aClass);
+
+ if (result == null) {
+ result = getMethodForClass(aClass);
+ if (result == null) {
+ result = NOT_FOUND;
+ }
+ methodMap.setObjectForKey(result, aClass);
}
-
- if ( result == NOT_FOUND )
- {
+
+ if (result == NOT_FOUND) {
throw new NoSuchMethodException();
}
return (Method) result;
}
-
- /**
- * Returns the appropriate method, or null if not found.
- */
- private Method getMethodForClass( Class aClass )
- {
+
+ /**
+ * Returns the appropriate method, or null if not found.
+ */
+ private Method getMethodForClass(Class aClass) {
Method[] methods = aClass.getMethods();
- for ( int i = 0; i < methods.length; i++ )
- {
- if ( methods[i].getName().equals( name() ) )
- {
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().equals(name())) {
Class[] params = methods[i].getParameterTypes();
- if ( params.length == parameterTypes.length )
- {
+ if (params.length == parameterTypes.length) {
boolean pass = true;
- for ( int j = 0; j < params.length; j++ )
- {
- if ( ! params[j].isAssignableFrom( parameterTypes[j] ) )
- {
+ for (int j = 0; j < params.length; j++) {
+ if (!params[j].isAssignableFrom(parameterTypes[j])) {
pass = false;
}
- }
- if ( pass ) return methods[i];
+ }
+ if (pass)
+ return methods[i];
}
}
}
return null;
}
- /**
- * Convenience to get a method for an object.
- */
- public Method methodOnObject (Object anObject)
- throws NoSuchMethodException
- {
- Method m = methodOnClass( anObject.getClass() );
- if ( m == null ) throw new NoSuchMethodException( name() );
- return m;
+ /**
+ * Convenience to get a method for an object.
+ */
+ public Method methodOnObject(Object anObject) throws NoSuchMethodException {
+ Method m = methodOnClass(anObject.getClass());
+ if (m == null)
+ throw new NoSuchMethodException(name());
+ return m;
}
- /**
- * Returns whether the class implements the method for this selector.
- */
- public boolean implementedByClass (Class aClass)
- {
- try
- {
- methodOnClass( aClass );
+ /**
+ * Returns whether the class implements the method for this selector.
+ */
+ public boolean implementedByClass(Class aClass) {
+ try {
+ methodOnClass(aClass);
return true;
- }
- catch ( NoSuchMethodException exc )
- {
- }
- return false;
- }
-
- /**
- * Returns whether the object's class implements the method
- * for this selector.
- */
- public boolean implementedByObject (Object anObject)
- {
- try
- {
- methodOnObject( anObject );
+ } catch (NoSuchMethodException exc) {
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the object's class implements the method for this selector.
+ */
+ public boolean implementedByObject(Object anObject) {
+ try {
+ methodOnObject(anObject);
return true;
- }
- catch ( NoSuchMethodException exc )
- {
- }
- return false;
- }
-
- /**
- * Invokes this selector's method on the specified object
- * using the specified parameters.
- */
- public Object invoke (Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return methodOnObject( anObject ).invoke( anObject, parameters );
+ } catch (NoSuchMethodException exc) {
+ }
+ return false;
+ }
+
+ /**
+ * Invokes this selector's method on the specified object using the specified
+ * parameters.
+ */
+ public Object invoke(Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return methodOnObject(anObject).invoke(anObject, parameters);
+ }
+
+ /**
+ * Invokes this selector's method on the specified object with no parameters.
+ */
+ public Object invoke(Object anObject)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return invoke(anObject, EMPTY_OBJECT_ARRAY);
+ }
+
+ /**
+ * Invokes this selector's method on the specified object with the specified
+ * parameter.
+ */
+ public Object invoke(Object anObject, Object aParameter)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return invoke(anObject, new Object[] { aParameter });
}
- /**
- * Invokes this selector's method on the specified object
- * with no parameters.
- */
- public Object invoke (Object anObject)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return invoke( anObject, EMPTY_OBJECT_ARRAY );
+ /**
+ * Invokes this selector's method on the specified object using the specified
+ * two parameters.
+ */
+ public Object invoke(Object anObject, Object p1, Object p2)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return invoke(anObject, new Object[] { p1, p2 });
+ }
+
+ /**
+ * Invokes the method with the specified signature on the specified object using
+ * the specified parameters.
+ */
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return new NSSelector(methodName, parameterTypes).invoke(anObject, parameters);
}
- /**
- * Invokes this selector's method on the specified object
- * with the specified parameter.
- */
- public Object invoke (Object anObject, Object aParameter)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return invoke( anObject, new Object[] { aParameter } );
+ /**
+ * Invokes the method with the specified signature on the specified object with
+ * no parameters.
+ */
+ public static Object invoke(String methodName, Object anObject)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return NSSelector.invoke(methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY);
}
- /**
- * Invokes this selector's method on the specified object
- * using the specified two parameters.
- */
- public Object invoke (Object anObject, Object p1, Object p2)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return invoke( anObject, new Object[] { p1, p2 } );
+ /**
+ * Invokes the method with the specified signature on the specified object using
+ * the specified parameter.
+ */
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object aParameter)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return NSSelector.invoke(methodName, parameterTypes, anObject, new Object[] { aParameter });
}
-
- /**
- * Invokes the method with the specified signature on the specified
- * object using the specified parameters.
- */
- public static Object invoke
- (String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return new NSSelector( methodName, parameterTypes ).invoke( anObject, parameters );
+
+ /**
+ * Invokes the method with the specified signature on the specified object using
+ * the specified two parameters.
+ */
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object p1, Object p2)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return NSSelector.invoke(methodName, parameterTypes, anObject, new Object[] { p1, p2 });
}
- /**
- * Invokes the method with the specified signature on the specified object
- * with no parameters.
- */
- public static Object invoke
- (String methodName, Object anObject)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return NSSelector.invoke(
- methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY );
+ // interface Comparator
+
+ private Comparator comparator;
+
+ /**
+ * Constructor specifying a method name and a comparator. This is not in the
+ * spec.
+ */
+ public NSSelector(String aMethodName, Comparator aComparator) {
+ this(aMethodName, EMPTY_CLASS_ARRAY);
+ comparator = aComparator;
}
- /**
- * Invokes the method with the specified signature on the specified
- * object using the specified parameter.
- */
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object aParameter)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return NSSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { aParameter } );
+ /**
+ * Returns the Comparator used for this selector. This is not in the spec.
+ */
+ public Comparator comparator() {
+ if (comparator == null) {
+ comparator = new PropertyComparator(methodName);
+ }
+ return comparator;
}
- /**
- * Invokes the method with the specified signature on the specified
- * object using the specified two parameters.
- */
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object p1, Object p2)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return NSSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { p1, p2 } );
+ public int compare(Object o1, Object o2) {
+ if (comparator == null) {
+ comparator = new PropertyComparator(methodName);
+ }
+ return comparator.compare(o1, o2);
}
- // interface Comparator
-
- private Comparator comparator;
-
- /**
- * Constructor specifying a method name and a comparator.
- * This is not in the spec.
- */
- public NSSelector (String aMethodName, Comparator aComparator)
- {
- this( aMethodName, EMPTY_CLASS_ARRAY );
- comparator = aComparator;
- }
-
- /**
- * Returns the Comparator used for this selector.
- * This is not in the spec.
- */
- public Comparator comparator()
- {
- if ( comparator == null )
- {
- comparator = new PropertyComparator( methodName );
- }
- return comparator;
- }
-
- public int compare(Object o1, Object o2)
- {
- if ( comparator == null )
- {
- comparator = new PropertyComparator( methodName );
- }
- return comparator.compare( o1, o2 );
- }
-
- public boolean equals(Object obj)
- {
- return ( obj == this );
- }
+ public boolean equals(Object obj) {
+ return (obj == this);
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2003/02/12 19:34:35 mpowers
- * Added accessor for comparator.
+ * Revision 1.9 2003/02/12 19:34:35 mpowers Added accessor for comparator.
*
- * Revision 1.8 2003/02/07 20:23:41 mpowers
- * Provided backwards compatibility for comparators.
+ * Revision 1.8 2003/02/07 20:23:41 mpowers Provided backwards compatibility for
+ * comparators.
*
- * Revision 1.7 2003/01/22 23:02:25 mpowers
- * Fixed a null pointer error in NSSelector.toString.
+ * Revision 1.7 2003/01/22 23:02:25 mpowers Fixed a null pointer error in
+ * NSSelector.toString.
*
- * Revision 1.6 2003/01/18 23:46:58 mpowers
- * EOSortOrdering is now correctly using NSSelectors.
+ * Revision 1.6 2003/01/18 23:46:58 mpowers EOSortOrdering is now correctly
+ * using NSSelectors.
*
- * Revision 1.4 2001/10/31 15:24:45 mpowers
- * Implicit constructor is now protected.
+ * Revision 1.4 2001/10/31 15:24:45 mpowers Implicit constructor is now
+ * protected.
*
- * Revision 1.3 2001/02/07 19:25:51 mpowers
- * Fixed: method matching uses isAssignableFrom rather than ==.
+ * Revision 1.3 2001/02/07 19:25:51 mpowers Fixed: method matching uses
+ * isAssignableFrom rather than ==.
*
- * Revision 1.2 2001/01/08 23:30:16 mpowers
- * Fixed major bug - selectors were not supposed to share a method map.
+ * Revision 1.2 2001/01/08 23:30:16 mpowers Fixed major bug - selectors were not
+ * supposed to share a method map.
*
- * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:39 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java
index 5318fe8..38a7ec6 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java
@@ -26,187 +26,154 @@ import java.util.Set;
import java.util.Vector;
/**
-* A pure java implementation of NSSet that
-* implements Set for greater java interoperability.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NSSet extends HashSet
-{
- /**
- * Default constructor.
- */
- public NSSet ()
- {
- super();
- }
-
- /**
- * Constructs a NSSet containing the objects
- * in the specified collection.
- */
- public NSSet ( Collection aCollection )
- {
- super( aCollection );
- }
-
- /**
- * Constructs a NSSet containing only
- * the specified object.
- */
- public NSSet ( Object anObject )
- {
- super();
- add( anObject );
- }
-
- /**
- * Constructs a NSSet containing the objects
- * in the specified array.
- */
- public NSSet ( Object[] anObjectArray )
- {
- super();
- for ( int i = 0; i < anObjectArray.length; i++ )
- {
- add( anObjectArray[i] );
- }
- }
-
- /**
- * Returns an NSArray containing all objects in the set.
- */
- public NSArray allObjects ()
- {
- return new NSArray( this );
- }
-
- /**
- *
- */
- public Object anyObject ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this set contains the
- * specified object.
- */
- public boolean containsObject ( Object anObject )
- {
- return contains( anObject );
- }
-
- /**
- * Returns the number of elements in this set.
- */
- public int count ()
- {
- return size();
- }
-
- /**
- * Returns whether this set has one or more
- * elements in common with the specified set.
- */
- public boolean intersectsSet ( Set aSet )
- {
- Iterator it = aSet.iterator();
- while ( it.hasNext() )
- {
- if ( this.containsObject( it.next() ) )
- {
- return true;
- }
- }
- return false;
-
- }
-
- /**
- * Returns whether this set contains the
- * same object as the specified set.
- */
- public boolean isEqualToSet ( Set aSet )
- {
- return equals( aSet );
- }
-
- /**
- * Returns whether this set is a subset
- * of the specified set.
- */
- public boolean isSubsetOfSet ( Set aSet )
- {
- return aSet.containsAll( this );
- }
-
- /**
- *
- */
- public Object member ( Object anObject )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns an enumerator over the objects
- * in this set.
- */
- public Enumeration objectEnumerator ()
- {
- return new Vector( this ).elements();
- }
-
- /**
- * Returns a set that is the intersection
- * of this set and the specified set.
- */
- public NSSet setByIntersectingSet ( Set aSet )
- {
- NSSet result = new NSSet( this );
- result.retainAll( aSet );
- return result;
- }
-
- /**
- * Returns a set that contains all elements
- * in this set that are not in the specified set.
- */
- public NSSet setBySubtractingSet ( Set aSet )
- {
- NSSet result = new NSSet( this );
- result.removeAll( aSet );
- return result;
- }
-
- /**
- * Returns a set that is the union
- * of this set and the specified set.
- */
- public NSSet setByUnioningSet ( Set aSet )
- {
- NSSet result = new NSSet( this );
- result.addAll( aSet );
- return result;
- }
-
+ * A pure java implementation of NSSet that implements Set for greater java
+ * interoperability.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NSSet extends HashSet {
+ /**
+ * Default constructor.
+ */
+ public NSSet() {
+ super();
+ }
+
+ /**
+ * Constructs a NSSet containing the objects in the specified collection.
+ */
+ public NSSet(Collection aCollection) {
+ super(aCollection);
+ }
+
+ /**
+ * Constructs a NSSet containing only the specified object.
+ */
+ public NSSet(Object anObject) {
+ super();
+ add(anObject);
+ }
+
+ /**
+ * Constructs a NSSet containing the objects in the specified array.
+ */
+ public NSSet(Object[] anObjectArray) {
+ super();
+ for (int i = 0; i < anObjectArray.length; i++) {
+ add(anObjectArray[i]);
+ }
+ }
+
+ /**
+ * Returns an NSArray containing all objects in the set.
+ */
+ public NSArray allObjects() {
+ return new NSArray(this);
+ }
+
+ /**
+ *
+ */
+ public Object anyObject() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this set contains the specified object.
+ */
+ public boolean containsObject(Object anObject) {
+ return contains(anObject);
+ }
+
+ /**
+ * Returns the number of elements in this set.
+ */
+ public int count() {
+ return size();
+ }
+
+ /**
+ * Returns whether this set has one or more elements in common with the
+ * specified set.
+ */
+ public boolean intersectsSet(Set aSet) {
+ Iterator it = aSet.iterator();
+ while (it.hasNext()) {
+ if (this.containsObject(it.next())) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Returns whether this set contains the same object as the specified set.
+ */
+ public boolean isEqualToSet(Set aSet) {
+ return equals(aSet);
+ }
+
+ /**
+ * Returns whether this set is a subset of the specified set.
+ */
+ public boolean isSubsetOfSet(Set aSet) {
+ return aSet.containsAll(this);
+ }
+
+ /**
+ *
+ */
+ public Object member(Object anObject) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns an enumerator over the objects in this set.
+ */
+ public Enumeration objectEnumerator() {
+ return new Vector(this).elements();
+ }
+
+ /**
+ * Returns a set that is the intersection of this set and the specified set.
+ */
+ public NSSet setByIntersectingSet(Set aSet) {
+ NSSet result = new NSSet(this);
+ result.retainAll(aSet);
+ return result;
+ }
+
+ /**
+ * Returns a set that contains all elements in this set that are not in the
+ * specified set.
+ */
+ public NSSet setBySubtractingSet(Set aSet) {
+ NSSet result = new NSSet(this);
+ result.removeAll(aSet);
+ return result;
+ }
+
+ /**
+ * Returns a set that is the union of this set and the specified set.
+ */
+ public NSSet setByUnioningSet(Set aSet) {
+ NSSet result = new NSSet(this);
+ result.addAll(aSet);
+ return result;
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:39 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java
index 171e756..7c7b4da 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java
@@ -26,247 +26,245 @@ import java.io.Serializable;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
+
/**
-* A channel to the database, representing a communication
-* stream within a context of an adaptor.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
+ * A channel to the database, representing a communication stream within a
+ * context of an adaptor.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
-public class NSTimeZone extends TimeZone
- implements Cloneable, Serializable, NSCoding {
- protected static class __NSTZPeriodComparator extends NSComparator {
+public class NSTimeZone extends TimeZone implements Cloneable, Serializable, NSCoding {
+ protected static class __NSTZPeriodComparator extends NSComparator {
- protected boolean _ascending = false;
+ protected boolean _ascending = false;
- public int compare(Object obj, Object obj1) throws NSComparator.ComparisonException {
+ public int compare(Object obj, Object obj1) throws NSComparator.ComparisonException {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public __NSTZPeriodComparator() {
+ public __NSTZPeriodComparator() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public __NSTZPeriodComparator(boolean flag) {
+ public __NSTZPeriodComparator(boolean flag) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
- }
+ }
+ }
- protected static class __NSTZPeriod {
+ protected static class __NSTZPeriod {
- protected String _abbreviation = null;
- protected int _isdst = 0;
- protected int _offset = 0;
- protected double _startTime = 0;
+ protected String _abbreviation = null;
+ protected int _isdst = 0;
+ protected int _offset = 0;
+ protected double _startTime = 0;
- protected boolean before(__NSTZPeriod _p_nstzperiod) {
+ protected boolean before(__NSTZPeriod _p_nstzperiod) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- protected boolean equals(__NSTZPeriod _p_nstzperiod) {
+ protected boolean equals(__NSTZPeriod _p_nstzperiod) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- protected __NSTZPeriod() {
+ protected __NSTZPeriod() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
- }
-
+ }
+ }
- public static final String SystemTimeZoneDidChangeNotification = "NSSystemTimeZoneDidChangeNotification";
- protected NSData _data = null;
- protected transient int _hashCode = 0;
- protected transient boolean _initialized = false;
- protected transient TimeZone _jdkTimeZone = null;
- protected String _name = null;
- protected transient int _rawOffset = 0;
- protected transient NSMutableArray _timeZonePeriods = null;
- protected transient int _timeZonePeriodsCount = 0;
- protected transient boolean _useDaylightTime = false;
+ public static final String SystemTimeZoneDidChangeNotification = "NSSystemTimeZoneDidChangeNotification";
+ protected NSData _data = null;
+ protected transient int _hashCode = 0;
+ protected transient boolean _initialized = false;
+ protected transient TimeZone _jdkTimeZone = null;
+ protected String _name = null;
+ protected transient int _rawOffset = 0;
+ protected transient NSMutableArray _timeZonePeriods = null;
+ protected transient int _timeZonePeriodsCount = 0;
+ protected transient boolean _useDaylightTime = false;
- public NSTimeZone() {
+ public NSTimeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- protected NSTimeZone(String s, NSData nsdata) {
+ protected NSTimeZone(String s, NSData nsdata) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static NSDictionary abbreviationDictionary() {
+ public static NSDictionary abbreviationDictionary() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public Class classForCoder() {
- return getClass();
- }
+ public Class classForCoder() {
+ return getClass();
+ }
- public Object clone() {
+ public Object clone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static Object decodeObject(NSCoder nscoder) {
+ public static Object decodeObject(NSCoder nscoder) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void encodeWithCoder(NSCoder nscoder) {
+ public void encodeWithCoder(NSCoder nscoder) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized NSTimeZone defaultTimeZone() {
+ public static synchronized NSTimeZone defaultTimeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static String[] getAvailableIDs() {
+ public static String[] getAvailableIDs() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static TimeZone getDefault() {
+ public static TimeZone getDefault() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static NSArray knownTimeZoneNames() {
+ public static NSArray knownTimeZoneNames() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static NSTimeZone localTimeZone() {
+ public static NSTimeZone localTimeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized void resetSystemTimeZone() {
+ public static synchronized void resetSystemTimeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized void setDefault(TimeZone timezone) {
+ public static synchronized void setDefault(TimeZone timezone) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized void setDefaultTimeZone(NSTimeZone nstimezone) {
+ public static synchronized void setDefaultTimeZone(NSTimeZone nstimezone) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void setID(String s) {
- throw new IllegalStateException(getClass().getName() + " is immutable.");
- }
+ public void setID(String s) {
+ throw new IllegalStateException(getClass().getName() + " is immutable.");
+ }
- public void setRawOffset(int i) {
- throw new IllegalStateException(getClass().getName() + " is immutable.");
- }
+ public void setRawOffset(int i) {
+ throw new IllegalStateException(getClass().getName() + " is immutable.");
+ }
- public static synchronized NSTimeZone systemTimeZone() {
+ public static synchronized NSTimeZone systemTimeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized NSTimeZone timeZoneForSecondsFromGMT(int i) {
+ public static synchronized NSTimeZone timeZoneForSecondsFromGMT(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized NSTimeZone timeZoneWithName(String s, boolean flag) {
+ public static synchronized NSTimeZone timeZoneWithName(String s, boolean flag) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static synchronized NSTimeZone timeZoneWithNameAndData(String s, NSData nsdata) {
+ public static synchronized NSTimeZone timeZoneWithNameAndData(String s, NSData nsdata) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public static NSTimeZone _nstimeZoneWithTimeZone(TimeZone timezone) {
+ public static NSTimeZone _nstimeZoneWithTimeZone(TimeZone timezone) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String abbreviation() {
+ public String abbreviation() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String abbreviationForTimestamp(NSTimestamp nstimestamp) {
+ public String abbreviationForTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSData data() {
+ public NSData data() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean equals(Object obj) {
+ public boolean equals(Object obj) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String getDisplayName(boolean flag, int i, Locale locale) {
+ public String getDisplayName(boolean flag, int i, Locale locale) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String getID() {
+ public String getID() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int getOffset(int i, int j, int k, int l, int i1, int j1) {
+ public int getOffset(int i, int j, int k, int l, int i1, int j1) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int getRawOffset() {
+ public int getRawOffset() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public synchronized int hashCode() {
+ public synchronized int hashCode() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean hasSameRules(TimeZone timezone) {
+ public boolean hasSameRules(TimeZone timezone) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean inDaylightTime(Date date) {
+ public boolean inDaylightTime(Date date) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean isDaylightSavingTime() {
+ public boolean isDaylightSavingTime() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean isDaylightSavingTimeForTimestamp(NSTimestamp nstimestamp) {
+ public boolean isDaylightSavingTimeForTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean isEqualToTimeZone(NSTimeZone nstimezone) {
+ public boolean isEqualToTimeZone(NSTimeZone nstimezone) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String name() {
+ public String name() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int secondsFromGMT() {
+ public int secondsFromGMT() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int secondsFromGMTForTimestamp(NSTimestamp nstimestamp) {
+ public int secondsFromGMTForTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String toString() {
+ public String toString() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public boolean useDaylightTime() {
+ public boolean useDaylightTime() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- protected Object readResolve() throws ObjectStreamException {
+ protected Object readResolve() throws ObjectStreamException {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.1 2002/06/25 07:52:57 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java
index bd246e0..03590f2 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java
@@ -26,260 +26,255 @@ import java.util.Date;
import java.util.TimeZone;
/**
-* A channel to the database, representing a communication
-* stream within a context of an adaptor.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 892 $
-*/
+ * A channel to the database, representing a communication stream within a
+ * context of an adaptor.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 892 $
+ */
-public class NSTimestamp extends Timestamp
- implements NSCoding {
+public class NSTimestamp extends Timestamp implements NSCoding {
- public static class IntRef {
+ public static class IntRef {
- public int value = 0;
+ public int value = 0;
- public String toString() {
- return getClass().getName() + " < value = " + value + " >";
- }
+ public String toString() {
+ return getClass().getName() + " < value = " + value + " >";
+ }
- public IntRef() {
- }
- }
+ public IntRef() {
+ }
+ }
+ public static final NSTimestamp DistantPast = new NSTimestamp(0xffffc77f2e9b6800L);
+ public static final NSTimestamp DistantFuture = new NSTimestamp(0x7fffffffffffffffL);
- public static final NSTimestamp DistantPast = new NSTimestamp(0xffffc77f2e9b6800L);
- public static final NSTimestamp DistantFuture = new NSTimestamp(0x7fffffffffffffffL);
- public static long currentTimeIntervalSinceReferenceDate() {
- return System.currentTimeMillis() / 1000L;
- }
+ public static long currentTimeIntervalSinceReferenceDate() {
+ return System.currentTimeMillis() / 1000L;
+ }
- public static NSTimestamp distantFuture() {
- return DistantFuture;
- }
+ public static NSTimestamp distantFuture() {
+ return DistantFuture;
+ }
- public static NSTimestamp distantPast() {
- return DistantPast;
- }
+ public static NSTimestamp distantPast() {
+ return DistantPast;
+ }
- public static long millisecondsToTimeInterval(long l) {
- return l / 1000L;
- }
+ public static long millisecondsToTimeInterval(long l) {
+ return l / 1000L;
+ }
- public static long timeIntervalToMilliseconds(long l) {
- return l * 1000L;
- }
+ public static long timeIntervalToMilliseconds(long l) {
+ return l * 1000L;
+ }
- public Class classForCoder() {
- return getClass();
- }
+ public Class classForCoder() {
+ return getClass();
+ }
- public static Object decodeObject(NSCoder nscoder) {
+ public static Object decodeObject(NSCoder nscoder) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void encodeWithCoder(NSCoder nscoder) {
+ public void encodeWithCoder(NSCoder nscoder) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp() {
- super(0);
+ public NSTimestamp() {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(long l) {
- super(l);
+ public NSTimestamp(long l) {
+ super(l);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(long l, int i) {
- super(0);
+ public NSTimestamp(long l, int i) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(long l, NSTimestamp nstimestamp) {
- super(0);
+ public NSTimestamp(long l, NSTimestamp nstimestamp) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(long l, TimeZone timezone) {
- super(0);
+ public NSTimestamp(long l, TimeZone timezone) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(long l, int i, TimeZone timezone) {
- super(0);
+ public NSTimestamp(long l, int i, TimeZone timezone) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(int i, int j, int k, int l, int i1, int j1, TimeZone timezone) {
- super(0);
+ public NSTimestamp(int i, int j, int k, int l, int i1, int j1, TimeZone timezone) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(Date date) {
- super(0);
+ public NSTimestamp(Date date) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp(Timestamp timestamp) {
- super(0);
+ public NSTimestamp(Timestamp timestamp) {
+ super(0);
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp timestampByAddingGregorianUnits(int i, int j, int k, int l, int i1, int j1) {
+ public NSTimestamp timestampByAddingGregorianUnits(int i, int j, int k, int l, int i1, int j1) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp timestampByAddingTimeInterval(long l) {
+ public NSTimestamp timestampByAddingTimeInterval(long l) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long dayOfCommonEra() {
+ public long dayOfCommonEra() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int dayOfMonth() {
+ public int dayOfMonth() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int dayOfWeek() {
+ public int dayOfWeek() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int dayOfYear() {
+ public int dayOfYear() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int hourOfDay() {
+ public int hourOfDay() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int microsecondOfSecond() {
+ public int microsecondOfSecond() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int minuteOfHour() {
+ public int minuteOfHour() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int monthOfYear() {
+ public int monthOfYear() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int secondOfMinute() {
+ public int secondOfMinute() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int yearOfCommonEra() {
+ public int yearOfCommonEra() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void gregorianUnitsSinceTimestamp(IntRef intref, IntRef intref1, IntRef intref2, IntRef intref3, IntRef intref4, IntRef intref5, NSTimestamp nstimestamp) {
+ public void gregorianUnitsSinceTimestamp(IntRef intref, IntRef intref1, IntRef intref2, IntRef intref3,
+ IntRef intref4, IntRef intref5, NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long timeIntervalSinceTimestamp(NSTimestamp nstimestamp) {
+ public long timeIntervalSinceTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long timeIntervalSinceNow() {
+ public long timeIntervalSinceNow() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long timeIntervalSinceReferenceDate() {
+ public long timeIntervalSinceReferenceDate() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public int compare(NSTimestamp nstimestamp) {
+ public int compare(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp earlierTimestamp(NSTimestamp nstimestamp) {
+ public NSTimestamp earlierTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimestamp laterTimestamp(NSTimestamp nstimestamp) {
+ public NSTimestamp laterTimestamp(NSTimestamp nstimestamp) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public String toString() {
+ public String toString() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public NSTimeZone timeZone() {
+ public NSTimeZone timeZone() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long _getTimeInMillis() {
+ public long _getTimeInMillis() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void setNanos(int i) {
+ public void setNanos(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setDate(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setDate(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setHours(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setHours(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setMinutes(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setMinutes(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setMonth(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setMonth(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setSeconds(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setSeconds(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public void setTime(long l) {
+ public void setTime(long l) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- public long getTime() {
+ public long getTime() {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
- /** @deprecated This method deprecated in parent java.util.Date */
- public void setYear(int i) {
+ /** @deprecated This method deprecated in parent java.util.Date */
+ public void setYear(int i) {
throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 12:47:16 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2002/07/14 21:56:16 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber.
*
- * Revision 1.3 2002/06/25 19:06:13 cgruber
- * Comment fix.
+ * Revision 1.3 2002/06/25 19:06:13 cgruber Comment fix.
*
- * Revision 1.2 2002/06/25 19:05:27 cgruber
- * Add deprecation statements to remove warnings
- * about java.util.Date's deprecated APIs.
+ * Revision 1.2 2002/06/25 19:05:27 cgruber Add deprecation statements to remove
+ * warnings about java.util.Date's deprecated APIs.
*
- * Revision 1.1 2002/06/25 07:52:56 cgruber
- * Add quite a few abstract classes, interfaces, and classes. All
- * API consistent with WebObjects, but with no implementation, nor
- * any private or package access members from the original.
+ * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes,
+ * interfaces, and classes. All API consistent with WebObjects, but with no
+ * implementation, nor any private or package access members from the original.
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java
index ecc67ca..c8fbc44 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java
@@ -25,41 +25,34 @@ import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
/**
-* A Format that accepts C-style date formatting syntax.
-* Not currently implemented, included for compile compatibility.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A Format that accepts C-style date formatting syntax. Not currently
+ * implemented, included for compile compatibility.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+
+public class NSTimestampFormatter extends SimpleDateFormat {
+ public NSTimestampFormatter() {
+ super();
+ }
+
+ public NSTimestampFormatter(String aPattern) {
+ super(aPattern);
+ }
-public class NSTimestampFormatter extends SimpleDateFormat
-{
- public NSTimestampFormatter()
- {
- super();
- }
-
- public NSTimestampFormatter(String aPattern)
- {
- super( aPattern );
- }
+ public NSTimestampFormatter(String aPattern, DateFormatSymbols symbols) {
+ super(aPattern, symbols);
+ }
- public NSTimestampFormatter(String aPattern,
- DateFormatSymbols symbols)
- {
- super( aPattern, symbols );
- }
-
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:15:00 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/17 14:40:51 mpowers
- * Adding files to fix build.
+ * Revision 1.1 2003/01/17 14:40:51 mpowers Adding files to fix build.
*
*
*/
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java
index ddf347d..16ef393 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java
@@ -26,274 +26,219 @@ import java.io.*;
import java.util.*; //collections
/**
-* Duplicator makes use of Introspector to duplicate objects,
-* either by shallow copy, deep copy, or by copying properties
-* from one object to apply to another object. You may find this
-* class useful because java.lang.Object.clone() only supports
-* shallow copying.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 895 $
-*/
+ * Duplicator makes use of Introspector to duplicate objects, either by shallow
+ * copy, deep copy, or by copying properties from one object to apply to another
+ * object. You may find this class useful because java.lang.Object.clone() only
+ * supports shallow copying.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 895 $
+ */
+
+public class Duplicator {
+ /**
+ * Used to represent null values for properties in the maps returned by
+ * readProperties and cloneProperties and in the parameter to writeProperties.
+ * This actually references the NSNull instance.
+ */
+ public static final Object NULL = NSNull.nullValue();
+ private static NSSelector clone = new NSSelector("clone");
+
+ /**
+ * Returns a list of properties for the specified class that are both readable
+ * and writable.
+ */
+ static public List editablePropertiesForObject(Object anObject) {
+ List readProperties = new ArrayList();
+ String[] read = Introspector.getReadPropertiesForObject(anObject);
+ for (int i = 0; i < read.length; i++) {
+ readProperties.add(read[i]);
+ }
+
+ List properties = new ArrayList();
+ String[] write = Introspector.getWritePropertiesForObject(anObject);
+ for (int i = 0; i < write.length; i++) {
+ properties.add(write[i]);
+ }
+
+ // only use properties on both lists: read/write
+ properties.retainAll(readProperties);
+
+ return properties;
+ }
-public class Duplicator
-{
- /**
- * Used to represent null values for properties in the
- * maps returned by readProperties and cloneProperties
- * and in the parameter to writeProperties.
- * This actually references the NSNull instance.
- */
- public static final Object NULL = NSNull.nullValue();
- private static NSSelector clone = new NSSelector( "clone" );
+ /**
+ * Returns a Map containing only the mutable properties for the specified object
+ * and their values. Any null values for properties will be represented with the
+ * NULL object.
+ */
+ static public Map readPropertiesForObject(Object anObject) {
+ NSMutableDictionary result = new NSMutableDictionary();
- /**
- * Returns a list of properties for the specified class
- * that are both readable and writable.
- */
- static public List editablePropertiesForObject(
- Object anObject )
- {
- List readProperties = new ArrayList();
- String[] read = Introspector.getReadPropertiesForObject( anObject );
- for ( int i = 0; i < read.length; i++ )
- {
- readProperties.add( read[i] );
- }
+ String key;
+ Object value;
+ Iterator it = editablePropertiesForObject(anObject).iterator();
+ while (it.hasNext()) {
+ key = it.next().toString();
+ value = Introspector.get(anObject, key);
+ if (value == null)
+ value = NULL;
+ result.setObjectForKey(value, key);
+ }
+ return result;
+ }
- List properties = new ArrayList();
- String[] write = Introspector.getWritePropertiesForObject( anObject );
- for ( int i = 0; i < write.length; i++ )
- {
- properties.add( write[i] );
- }
-
- // only use properties on both lists: read/write
- properties.retainAll( readProperties );
+ /**
+ * Returns a Map containing only the mutable properties for the specified object
+ * and deep clones of their values. Nulls are represented by the NULL object.
+ */
+ static public Map clonePropertiesForObject(Object anObject) {
+ Object key, value;
+ Map result = readPropertiesForObject(anObject);
+ Iterator it = result.keySet().iterator();
+ while (it.hasNext()) {
+ key = it.next();
+ value = result.get(key);
+ value = deepClone(value);
+ result.put(key, value);
+ }
+ return result;
+ }
- return properties;
- }
-
- /**
- * Returns a Map containing only the mutable properties
- * for the specified object and their values.
- * Any null values for properties will be represented with
- * the NULL object.
- */
- static public Map readPropertiesForObject(
- Object anObject )
- {
- NSMutableDictionary result = new NSMutableDictionary();
-
- String key;
- Object value;
- Iterator it = editablePropertiesForObject( anObject ).iterator();
- while ( it.hasNext() )
- {
- key = it.next().toString();
- value = Introspector.get( anObject, key );
- if ( value == null ) value = NULL;
- result.setObjectForKey( value, key );
- }
- return result;
- }
-
- /**
- * Returns a Map containing only the mutable properties
- * for the specified object and deep clones of their values.
- * Nulls are represented by the NULL object.
- */
- static public Map clonePropertiesForObject(
- Object anObject )
- {
- Object key, value;
- Map result = readPropertiesForObject( anObject );
- Iterator it = result.keySet().iterator();
- while ( it.hasNext() )
- {
- key = it.next();
- value = result.get( key );
- value = deepClone( value );
- result.put( key, value );
- }
- return result;
- }
-
- /**
- * Applies the map of properties and values to the
- * specified object. Null values for properties must
- * be represented by the NULL object.
- */
- static public void writePropertiesForObject(
- Map aMap, Object anObject )
- {
- String key;
- Object value;
- Iterator it = aMap.keySet().iterator();
- while ( it.hasNext() )
- {
- key = it.next().toString();
- value = aMap.get( key );
- if ( NULL.equals( value ) ) value = null;
- Introspector.set( anObject, key, value );
- }
- }
-
- /**
- * Creates a new copy of the specified object.
- * This implementation tries to call clone(),
- * and failing that, calls newInstance
- * and then calls copy() to transfer the values.
- * @throws WotonomyException if any operation fails.
- */
- static public Object clone(
- Object aSource )
- {
- Object result = null;
- if ( clone.implementedByObject( aSource ) )
- {
- try
- {
- result = clone.invoke( aSource );
- return result;
- }
- catch ( Exception exc )
- {
- // fall back on newInstance()
- }
- }
-
- Class c = aSource.getClass();
- try
- {
- result = c.newInstance();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- return copy( aSource, result );
- }
+ /**
+ * Applies the map of properties and values to the specified object. Null values
+ * for properties must be represented by the NULL object.
+ */
+ static public void writePropertiesForObject(Map aMap, Object anObject) {
+ String key;
+ Object value;
+ Iterator it = aMap.keySet().iterator();
+ while (it.hasNext()) {
+ key = it.next().toString();
+ value = aMap.get(key);
+ if (NULL.equals(value))
+ value = null;
+ Introspector.set(anObject, key, value);
+ }
+ }
- /**
- * Creates a deep copy of the specified object.
- * Every object in this objects graph will be
- * duplicated with new instances.
- * @throws WotonomyException if any operation fails.
- */
- static public Object deepClone(
- Object aSource )
- {
- // the only known way to deep copy in
- // java without native code is serialization
-
- try
- {
- ByteArrayOutputStream byteOutput =
- new ByteArrayOutputStream();
- ObjectOutputStream objectOutput =
- new ObjectOutputStream( byteOutput );
-
- objectOutput.writeObject( aSource );
- objectOutput.flush();
- objectOutput.close();
-
- ByteArrayInputStream byteInput =
- new ByteArrayInputStream( byteOutput.toByteArray() );
- ObjectInputStream objectInput =
- new ObjectInputStream( byteInput );
- return objectInput.readObject();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( "Error cloning object: " + aSource, exc );
- }
- }
+ /**
+ * Creates a new copy of the specified object. This implementation tries to call
+ * clone(), and failing that, calls newInstance and then calls copy() to
+ * transfer the values.
+ *
+ * @throws WotonomyException if any operation fails.
+ */
+ static public Object clone(Object aSource) {
+ Object result = null;
+ if (clone.implementedByObject(aSource)) {
+ try {
+ result = clone.invoke(aSource);
+ return result;
+ } catch (Exception exc) {
+ // fall back on newInstance()
+ }
+ }
- /**
- * Copies values from one object to another.
- * Returns the destination object.
- * @throws WotonomyException if any operation fails.
- */
- static public Object copy(
- Object aSource, Object aDestination )
- {
- try
- {
- writePropertiesForObject(
- readPropertiesForObject( aSource ), aDestination );
- }
- catch ( RuntimeException exc )
- {
- throw new WotonomyException( exc );
- }
- return aDestination;
- }
-
- /**
- * Deeply clones the values from one object and applies them
- * to another object.
- * Returns the destination object.
- * @throws WotonomyException if any operation fails.
- */
- static public Object deepCopy(
- Object aSource, Object aDestination )
- {
- try
- {
- writePropertiesForObject(
- clonePropertiesForObject( aSource ), aDestination );
- }
- catch ( RuntimeException exc )
- {
- throw new WotonomyException( exc );
- }
- return aDestination;
- }
+ Class c = aSource.getClass();
+ try {
+ result = c.newInstance();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ return copy(aSource, result);
+ }
+
+ /**
+ * Creates a deep copy of the specified object. Every object in this objects
+ * graph will be duplicated with new instances.
+ *
+ * @throws WotonomyException if any operation fails.
+ */
+ static public Object deepClone(Object aSource) {
+ // the only known way to deep copy in
+ // java without native code is serialization
+
+ try {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutput = new ObjectOutputStream(byteOutput);
+
+ objectOutput.writeObject(aSource);
+ objectOutput.flush();
+ objectOutput.close();
+
+ ByteArrayInputStream byteInput = new ByteArrayInputStream(byteOutput.toByteArray());
+ ObjectInputStream objectInput = new ObjectInputStream(byteInput);
+ return objectInput.readObject();
+ } catch (Exception exc) {
+ throw new WotonomyException("Error cloning object: " + aSource, exc);
+ }
+ }
+
+ /**
+ * Copies values from one object to another. Returns the destination object.
+ *
+ * @throws WotonomyException if any operation fails.
+ */
+ static public Object copy(Object aSource, Object aDestination) {
+ try {
+ writePropertiesForObject(readPropertiesForObject(aSource), aDestination);
+ } catch (RuntimeException exc) {
+ throw new WotonomyException(exc);
+ }
+ return aDestination;
+ }
+
+ /**
+ * Deeply clones the values from one object and applies them to another object.
+ * Returns the destination object.
+ *
+ * @throws WotonomyException if any operation fails.
+ */
+ static public Object deepCopy(Object aSource, Object aDestination) {
+ try {
+ writePropertiesForObject(clonePropertiesForObject(aSource), aDestination);
+ } catch (RuntimeException exc) {
+ throw new WotonomyException(exc);
+ }
+ return aDestination;
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 16:52:12 cgruber
- * Add cvsignore crap to find off checking in binary crap.
+ * $Log$ Revision 1.1 2006/02/16 16:52:12 cgruber Add cvsignore crap to find off
+ * checking in binary crap.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.11 2001/08/22 19:24:26 mpowers
- * Providing a more helpful error message for cloning exceptions.
+ * Revision 1.11 2001/08/22 19:24:26 mpowers Providing a more helpful error
+ * message for cloning exceptions.
*
- * Revision 1.10 2001/03/29 03:30:36 mpowers
- * Refactored duplicator a bit.
+ * Revision 1.10 2001/03/29 03:30:36 mpowers Refactored duplicator a bit.
* Disabled MissingPropertyExceptions for now.
*
- * Revision 1.9 2001/03/28 14:11:23 mpowers
- * Removed debugging printlns.
+ * Revision 1.9 2001/03/28 14:11:23 mpowers Removed debugging printlns.
*
- * Revision 1.8 2001/03/27 23:25:48 mpowers
- * Basically reverting to the previous version.
+ * Revision 1.8 2001/03/27 23:25:48 mpowers Basically reverting to the previous
+ * version.
*
- * Revision 1.7 2001/03/06 23:18:13 mpowers
- * Clarified some comments.
+ * Revision 1.7 2001/03/06 23:18:13 mpowers Clarified some comments.
*
- * Revision 1.6 2001/03/01 20:36:35 mpowers
- * Better error handling and better handling of nulls.
+ * Revision 1.6 2001/03/01 20:36:35 mpowers Better error handling and better
+ * handling of nulls.
*
- * Revision 1.5 2001/02/27 21:43:40 mpowers
- * Removed NullMarker class in favor of NSNull.
+ * Revision 1.5 2001/02/27 21:43:40 mpowers Removed NullMarker class in favor of
+ * NSNull.
*
- * Revision 1.4 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.4 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.3 2001/02/23 21:07:46 mpowers
- * Documented the NULL object.
+ * Revision 1.3 2001/02/23 21:07:46 mpowers Documented the NULL object.
*
- * Revision 1.1 2001/02/16 22:51:29 mpowers
- * Now deep-cloning objects passed between editing contexts.
+ * Revision 1.1 2001/02/16 22:51:29 mpowers Now deep-cloning objects passed
+ * between editing contexts.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java
index 2b313d0..09687e2 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java
@@ -30,912 +30,750 @@ import java.util.Map;
import java.util.Set;
/**
-* This Introspector is a static utility class written to work
-* around limitations in PropertyDescriptor and Introspector.<br><br>
-*
-* Of particular note are the get() and set() methods, which will attempt
-* to get and set artibrary values on arbitrary objects to the best of its
-* ability, converting values as appropriate. Properties of the form
-* "property.nestedproperty.anotherproperty" are supported to get and set
-* values on property values directly.<br><br>
-*
-* Note that for naming getter methods, this class supports "get", "is",
-* and also the property name itself, which supports NeXT-style properties.
-* Introspector supports Maps by treating the keys a property names,
-* supports Lists by treating the indexes as property names. <br><br>
-*
-* Numeric and boolean types can be inverted by prepending a "!" before
-* the name of the property, like "manager.!active" or "task.!lag".
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * This Introspector is a static utility class written to work around
+ * limitations in PropertyDescriptor and Introspector.<br>
+ * <br>
+ *
+ * Of particular note are the get() and set() methods, which will attempt to get
+ * and set artibrary values on arbitrary objects to the best of its ability,
+ * converting values as appropriate. Properties of the form
+ * "property.nestedproperty.anotherproperty" are supported to get and set values
+ * on property values directly.<br>
+ * <br>
+ *
+ * Note that for naming getter methods, this class supports "get", "is", and
+ * also the property name itself, which supports NeXT-style properties.
+ * Introspector supports Maps by treating the keys a property names, supports
+ * Lists by treating the indexes as property names. <br>
+ * <br>
+ *
+ * Numeric and boolean types can be inverted by prepending a "!" before the name
+ * of the property, like "manager.!active" or "task.!lag".
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+
+public class Introspector {
+ // allows "hasProperty" or "property" forms
+ public static boolean strict = false;
-public class Introspector
-{
- // allows "hasProperty" or "property" forms
- public static boolean strict = false;
-
// print exception stack traces
private static boolean debug = true;
-
+
// path separator
public static final String SEPARATOR = ".";
- // method cache - use hashtables for thread safety
- private static Map getterMethods = new Hashtable();
- private static Map setterMethods = new Hashtable();
-
- // wildcard value - using this class to represent a "wildcard" generic class.
- // we have to do this when matching methods by parameter types and a
- // null value is passed in - can't tell what class the null should be.
- public static Class WILD = Introspector.class;
-
- // empty class array - prevents having to create one every time
- private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
-
- // use OGNL for property access
- private static boolean useOGNL;
-
- static
- {
- try
- {
- useOGNL = ( Class.forName( "ognl.Ognl" ) != null );
- }
- catch ( ClassNotFoundException t )
- {
- useOGNL = false;
- }
- }
+ // method cache - use hashtables for thread safety
+ private static Map getterMethods = new Hashtable();
+ private static Map setterMethods = new Hashtable();
-/**
-* Utility method to get the read method for a property belonging to a class.
-* Will search for methods in the form of "getProperty" and failing that
-* "isProperty" (to handle booleans).
-* @param objectClass the class whose property methods will be retrieved.
-* @param aProperty The property whose method will be retrieved.
-* @param paramTypes An array of class objects representing the types of parameters.
-* @return The appropriate method for the class, or null if not found.
-*/
- static public Method getPropertyReadMethod(
- Class objectClass, String aProperty, Class[] paramTypes )
- {
- Method result = null;
-
- result = getMethodFromClass( objectClass, aProperty, paramTypes, true );
+ // wildcard value - using this class to represent a "wildcard" generic class.
+ // we have to do this when matching methods by parameter types and a
+ // null value is passed in - can't tell what class the null should be.
+ public static Class WILD = Introspector.class;
- return result;
- }
+ // empty class array - prevents having to create one every time
+ private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
-/**
-* Utility method to get the write method for a property belonging to a class.
-* Will search for methods in the form of "setProperty".
-* @param objectClass the class whose property methods will be retrieved.
-* @param aProperty The property whose method will be retrieved.
-* @param paramTypes An array of class objects representing the types of parameters.
-* @return The appropriate method for the class, or null if not found.
-*/
- static public Method getPropertyWriteMethod(
- Class objectClass, String aProperty, Class[] paramTypes )
- {
- Method result = null;
-
- result = getMethodFromClass( objectClass, aProperty, paramTypes, false );
+ // use OGNL for property access
+ private static boolean useOGNL;
- return result;
- }
+ static {
+ try {
+ useOGNL = (Class.forName("ognl.Ognl") != null);
+ } catch (ClassNotFoundException t) {
+ useOGNL = false;
+ }
+ }
-/**
-* Gets a named method from a class. Using this method is preferred because
-* the results are cached and should be faster than calling Class.getMethod().
-* Note that if an object has a "get" getter method and an "is" getter method
-* with the same signature defined for a given property. The "get" method
-* is called.
-* @param objectClass the Class whose property methods will be retrieved.
-* @param aMethodName A String containing the name of the desired method.
-* @param paramTypes An array of class objects representing the types of parameters.
-* @return The appropriate Method from the Class, or null if not found.
-*/
- static private Method getMethodFromClass(
- Class objectClass, String aProperty, Class[] paramTypes, boolean doGetter)
- { // System.out.print( "Introspector.getMethodFromClass: " + aMethodName + " : " );
-
- Map classesToMethods = (doGetter ?
- getterMethods :
- setterMethods);
-
- Map allMethods = (Map) classesToMethods.get( objectClass );
- if (allMethods == null)
- {
- // need to build maps for this class
- mapPropertiesForClass( objectClass );
- // now the map should exist
- allMethods = (Map) classesToMethods.get( objectClass );
- }
-
- Method[] methods = (Method[]) allMethods.get( aProperty );
- if ( methods == null )
- {
- return null; // property doesn't exist
- }
-
- methods_loop: // walks through all methods for name
- for ( int i = 0; i < methods.length; i++ )
- {
- Class[] types = methods[i].getParameterTypes();
-
- // if parameter lengths don't match
- if ( types.length != paramTypes.length )
- {
- // System.out.println( aMethodName + " : " + types.length + " != " + paramTypes.length );
- continue methods_loop; // continue with outer loop
- }
-
- // match up each parameter
- for ( int j = 0; j < types.length; j++ )
- {
- // convert primitives so they'll match - ugly
- // (would have thought isAssignableFrom() would catch this)
- if ( types[j].isPrimitive() )
- {
- if ( types[j] == Boolean.TYPE )
- {
- types[j] = Boolean.class;
- }
- else
- if ( types[j] == Character.TYPE )
- {
- types[j] = Character.class;
- }
- else
- if ( types[j] == Byte.TYPE )
- {
- types[j] = Byte.class;
- }
- else
- if ( types[j] == Short.TYPE )
- {
- types[j] = Short.class;
- }
- else
- if ( types[j] == Integer.TYPE )
- {
- types[j] = Integer.class;
- }
- else
- if ( types[j] == Long.TYPE )
- {
- types[j] = Long.class;
- }
- else
- if ( types[j] == Float.TYPE )
- {
- types[j] = Float.class;
- }
- else
- if ( types[j] == Double.TYPE )
- {
- types[j] = Double.class;
- }
- }
-
- // if parameters don't match
- if ( ( paramTypes[j] != WILD ) && ( ! types[j].isAssignableFrom( paramTypes[j] ) ) )
- {
+ /**
+ * Utility method to get the read method for a property belonging to a class.
+ * Will search for methods in the form of "getProperty" and failing that
+ * "isProperty" (to handle booleans).
+ *
+ * @param objectClass the class whose property methods will be retrieved.
+ * @param aProperty The property whose method will be retrieved.
+ * @param paramTypes An array of class objects representing the types of
+ * parameters.
+ * @return The appropriate method for the class, or null if not found.
+ */
+ static public Method getPropertyReadMethod(Class objectClass, String aProperty, Class[] paramTypes) {
+ Method result = null;
+
+ result = getMethodFromClass(objectClass, aProperty, paramTypes, true);
+
+ return result;
+ }
+
+ /**
+ * Utility method to get the write method for a property belonging to a class.
+ * Will search for methods in the form of "setProperty".
+ *
+ * @param objectClass the class whose property methods will be retrieved.
+ * @param aProperty The property whose method will be retrieved.
+ * @param paramTypes An array of class objects representing the types of
+ * parameters.
+ * @return The appropriate method for the class, or null if not found.
+ */
+ static public Method getPropertyWriteMethod(Class objectClass, String aProperty, Class[] paramTypes) {
+ Method result = null;
+
+ result = getMethodFromClass(objectClass, aProperty, paramTypes, false);
+
+ return result;
+ }
+
+ /**
+ * Gets a named method from a class. Using this method is preferred because the
+ * results are cached and should be faster than calling Class.getMethod(). Note
+ * that if an object has a "get" getter method and an "is" getter method with
+ * the same signature defined for a given property. The "get" method is called.
+ *
+ * @param objectClass the Class whose property methods will be retrieved.
+ * @param aMethodName A String containing the name of the desired method.
+ * @param paramTypes An array of class objects representing the types of
+ * parameters.
+ * @return The appropriate Method from the Class, or null if not found.
+ */
+ static private Method getMethodFromClass(Class objectClass, String aProperty, Class[] paramTypes,
+ boolean doGetter) { // System.out.print( "Introspector.getMethodFromClass: " + aMethodName + " : "
+ // );
+
+ Map classesToMethods = (doGetter ? getterMethods : setterMethods);
+
+ Map allMethods = (Map) classesToMethods.get(objectClass);
+ if (allMethods == null) {
+ // need to build maps for this class
+ mapPropertiesForClass(objectClass);
+ // now the map should exist
+ allMethods = (Map) classesToMethods.get(objectClass);
+ }
+
+ Method[] methods = (Method[]) allMethods.get(aProperty);
+ if (methods == null) {
+ return null; // property doesn't exist
+ }
+
+ methods_loop: // walks through all methods for name
+ for (int i = 0; i < methods.length; i++) {
+ Class[] types = methods[i].getParameterTypes();
+
+ // if parameter lengths don't match
+ if (types.length != paramTypes.length) {
+ // System.out.println( aMethodName + " : " + types.length + " != " +
+ // paramTypes.length );
+ continue methods_loop; // continue with outer loop
+ }
+
+ // match up each parameter
+ for (int j = 0; j < types.length; j++) {
+ // convert primitives so they'll match - ugly
+ // (would have thought isAssignableFrom() would catch this)
+ if (types[j].isPrimitive()) {
+ if (types[j] == Boolean.TYPE) {
+ types[j] = Boolean.class;
+ } else if (types[j] == Character.TYPE) {
+ types[j] = Character.class;
+ } else if (types[j] == Byte.TYPE) {
+ types[j] = Byte.class;
+ } else if (types[j] == Short.TYPE) {
+ types[j] = Short.class;
+ } else if (types[j] == Integer.TYPE) {
+ types[j] = Integer.class;
+ } else if (types[j] == Long.TYPE) {
+ types[j] = Long.class;
+ } else if (types[j] == Float.TYPE) {
+ types[j] = Float.class;
+ } else if (types[j] == Double.TYPE) {
+ types[j] = Double.class;
+ }
+ }
+
+ // if parameters don't match
+ if ((paramTypes[j] != WILD) && (!types[j].isAssignableFrom(paramTypes[j]))) {
// System.out.println( "Introspector.getMethodFromClass: " +
// aProperty + " : " + types[j] + " != " + paramTypes[j] );
- continue methods_loop; // continue with outer loop
- }
- }
-
- // all params match
- return methods[i];
- }
-
- // no match
- return null;
- }
-
- static private final Method[] getAllMethodsForClass( Class aClass )
- {
- Method[] local = aClass.getDeclaredMethods(); // only local
- Method[] all = aClass.getMethods(); // all public
- Method[] result = new Method[ local.length + all.length ];
- System.arraycopy( local, 0, result, 0, local.length );
- System.arraycopy( all, 0, result, local.length, all.length );
- return result;
- }
-
- /**
- * Generates a map of properties to both getter or setter methods for the given class.
- * Then assigned those maps into the appropriate getterMethods and setterMethods maps
- * keyed by the specified class. Even on error, this method will at least place empty
- * property maps into each of the methods maps.
- */
- static private void mapPropertiesForClass( Class objectClass )
- {
- try
- {
- Map readProperties = new HashMap();
- getterMethods.put( objectClass, readProperties );
- Map writeProperties = new HashMap();
- setterMethods.put( objectClass, writeProperties );
-
- String name, property;
- Method[] methods = getAllMethodsForClass( objectClass ); // throws SecurityException
- for ( int i = 0; i < methods.length; i++ )
- {
- name = methods[i].getName();
- methods[i].setAccessible( true ); // throws SecurityException
- if ( name.startsWith( "set" ) )
- {
- name = name.substring( 3 );
- if ( ! "".equals( name ) ) // excludes "set()"
- {
- putMethodIntoPropertyMap( name, methods[i], writeProperties );
- }
- }
- else
- if ( methods[i].getReturnType() != void.class )
- {
- String fullname = name;
- if ( name.startsWith( "get" ) )
- {
- name = name.substring( 3 );
- }
- else
- if ( name.startsWith( "is" ) )
- {
- name = name.substring( 2 );
- }
- else
- if ( name.startsWith( "has" ) && ( !strict ) ) // what about hashCode()?
- {
- name = name.substring( 3 );
- }
-
- if ( ! "".equals( name ) && ( !strict ) ) // excludes "get()", "has()", and "is()"
- {
- putMethodIntoPropertyMap( name, methods[i], readProperties );
- if ( fullname != name )
- { // allows us to match properties that include the get/set prefix as well
- putMethodIntoPropertyMap( fullname, methods[i], readProperties );
- }
- }
- }
- }
- }
- catch ( SecurityException se )
- {
- System.out.println( "Introspector.getMethodFromClass: " + se );
- // this class will show up with empty getter/setter maps
- }
- }
-
- /**
- * Places a property-method pair into one of the properties maps.
- * This in effect maps a property to an array of methods.
- */
- private static void putMethodIntoPropertyMap( String aProperty, Method aMethod, Map aMap )
- {
- // ensure first character is lower case
- StringBuffer buffer = new StringBuffer( aProperty );
- buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));
- String key = buffer.toString();
-
- // build array of methods for property
- Method[] result = (Method[]) aMap.get( key );
- if ( result == null )
- {
- result = new Method[] { aMethod };
- }
- else
- {
- // create new array that's larger by one and copy
- int i;
- Method[] enlarged = new Method[ result.length + 1 ];
- for ( i = 0; i < result.length; i ++ )
- {
- enlarged[i] = result[i];
- }
- // add the new method to end
- enlarged[i] = aMethod;
- result = enlarged;
- }
- aMap.put( key, result );
- }
+ continue methods_loop; // continue with outer loop
+ }
+ }
-/**
-* Utility method to get a method for a property belonging to a class.
-* Use this if you don't feel like making the Class array from the parameters
-* you will be using - pass in the parameters themselves.
-* @param objectClass the Class whose property methods will be retrieved.
-* @param aProperty The property whose method will be retrieved.
-* @param params An array of parameters to be used.
-* @return The appropriate method for the class, or null if not found.
-*/
- static public Method getPropertyReadMethod(
- Class objectClass, String aProperty, Object[] params )
- {
- // optimization: avoid allocating class array for common case
- if ( params.length == 0 )
- {
- return getPropertyReadMethod(
- objectClass, aProperty, EMPTY_CLASS_ARRAY );
- }
-
- Class[] paramList = new Class[ params.length ];
- for ( int i = 0; i < params.length; i++ )
- {
- if ( params[i] != null )
- {
- paramList[i] = params[i].getClass();
- }
- else
- {
- paramList[i] = WILD;
- }
- }
- return getPropertyReadMethod( objectClass, aProperty, paramList );
- }
+ // all params match
+ return methods[i];
+ }
-/**
-* Utility method to get a method for a property belonging to a class.
-* Use this if you don't feel like making the Class array from the parameters
-* you will be using - pass in the parameters themselves.
-* @param objectClass the Class whose property methods will be retrieved.
-* @param aProperty The property whose method will be retrieved.
-* @param params An array of parameters to be used.
-* @return The appropriate method for the class, or null if not found.
-*/
- static public Method getPropertyWriteMethod(
- Class objectClass, String aProperty, Object[] params )
- {
- Class[] paramList = new Class[ params.length ];
- for ( int i = 0; i < params.length; i++ )
- {
- if ( params[i] != null )
- {
- paramList[i] = params[i].getClass();
- }
- else
- {
- paramList[i] = WILD;
- }
- }
- return getPropertyWriteMethod( objectClass, aProperty, paramList );
- }
-
- /**
- * Gets a list of the readable properties for the given class.
- * Note that readable properties may not be writable - see getWriteProperties().
- * @return An array of property names in no particular order
- * where each name is a string with the first character in lower case.
- */
- public static String[] getReadPropertiesForClass( Class objectClass )
- {
- Map properties = (Map) getterMethods.get( objectClass );
- if ( properties == null )
- {
- // need to build maps for this class
- mapPropertiesForClass( objectClass );
- // now the map should exist
- properties = (Map) getterMethods.get( objectClass );
- }
-
- // put property names into string array
- Set keys = properties.keySet();
- Iterator it = keys.iterator();
- int len = keys.size();
- String[] result = new String[ len ];
- for ( int i = 0; i < len; i++ )
- {
- result[i] = (String) it.next();
- }
- return result;
- }
-
- /**
- * Gets a list of the writable properties for the given class.
- * Note that writable properties may not be writable - see getReadProperties().
- * @return An array of property names in no particular order
- * where each name is a string with the first character in lower case.
- */
- public static String[] getWritePropertiesForClass( Class objectClass )
- {
- Map properties = (Map) setterMethods.get( objectClass );
- if ( properties == null )
- {
- // need to build maps for this class
- mapPropertiesForClass( objectClass );
- // now the map should exist
- properties = (Map) setterMethods.get( objectClass );
- }
-
- // put property names into string array
- Set keys = properties.keySet();
- Iterator it = keys.iterator();
- int len = keys.size();
- String[] result = new String[ len ];
- for ( int i = 0; i < len; i++ )
- {
- result[i] = (String) it.next();
- }
- return result;
- }
-
- /**
- * Gets a list of the readable properties for the given object, which may
- * not be null. This method is more useful than getReadPropertiesForClass
- * in that Maps will return their keys as properties and Lists will return
- * their element indices as properties.
- * Note that readable properties may not be writable - see getWriteProperties().
- * @return An array of property names in no particular order
- * where each name is a string with the first character in lower case.
- */
- public static String[] getReadPropertiesForObject( Object anObject )
- {
- List properties = new ArrayList();
- String[] classProperties =
- getReadPropertiesForClass( anObject.getClass() );
- if ( anObject instanceof List )
- {
- properties.addAll( getPropertiesForList( (List) anObject ) );
- }
- if ( anObject instanceof Map )
- {
- properties.addAll( getPropertiesForMap( (Map) anObject ) );
- }
- int i;
- int len = classProperties.length + properties.size();
- String[] result = new String[ len ];
- for ( i = 0; i < classProperties.length; i++ )
- {
- result[i] = classProperties[i];
- }
- Iterator it = properties.iterator();
- while ( it.hasNext() )
- {
- result[i++] = it.next().toString();
- }
- return result;
- }
-
- /**
- * Gets a list of the writable properties for the given object, which may
- * not be null. This method is more useful than getWritePropertiesForClass
- * in that Maps will return their keys as properties and Lists will return
- * their element indices as properties.
- * Note that writable properties may not be writable - see getReadProperties().
- * @return An array of property names in no particular order
- * where each name is a string with the first character in lower case.
- */
- public static String[] getWritePropertiesForObject( Object anObject )
- {
- List properties = new ArrayList();
- String[] classProperties =
- getWritePropertiesForClass( anObject.getClass() );
- if ( anObject instanceof List )
- {
- properties.addAll( getPropertiesForList( (List) anObject ) );
- }
- if ( anObject instanceof Map )
- {
- properties.addAll( getPropertiesForMap( (Map) anObject ) );
- }
-
- int i;
- int len = classProperties.length + properties.size();
- String[] result = new String[ len ];
- for ( i = 0; i < classProperties.length; i++ )
- {
- result[i] = classProperties[i];
- }
- Iterator it = properties.iterator();
- while ( it.hasNext() )
- {
- result[i++] = it.next().toString();
- }
- return result;
- }
-
- private static List getPropertiesForList( List aList )
- {
- List result = new ArrayList();
- int len = aList.size();
- for ( int i = 0; i < len; i++ )
- {
- result.add( new Integer( i ).toString() );
- }
- return result;
- }
-
- private static List getPropertiesForMap( Map aMap )
- {
- List result = new ArrayList();
- Iterator it = ((Map)aMap).keySet().iterator();
- while ( it.hasNext() )
- {
- result.add( it.next().toString() );
- }
- return result;
- }
-
- private static Object[] EMPTY_ARRAY = new Object[0];
-
- /**
- * Convenience to get a value for a property from an object.
- * An empty property string is considered the identity property
- * and simply returns the object.
- * @throws MissingPropertyException if the property cannot be
- * found on the object.
- */
- public static Object getValueForObject( Object anObject, String aProperty )
- {
- if ( ( aProperty == null ) || ( "".equals( aProperty ) ) )
- {
- return anObject;
- }
-
- if ( useOGNL && aProperty.startsWith( "ognl:" ) )
- {
- try
- {
- return ognl.Ognl.getValue( aProperty, anObject );
- }
- catch ( Throwable t )
- {
- if ( debug )
- {
- System.err.println(
- "Introspector.getValueForObject: "
- + anObject + "' ( " + anObject.getClass() + " )"
- + ", ognl:" + aProperty );
- System.err.println( t );
- }
- return null;
- }
- }
-
- boolean invert = false;
- if ( aProperty.startsWith( "!" ) )
- {
- aProperty = aProperty.substring(1);
- invert = true;
- }
-
- Object result = null;
- try
- {
- Method m = Introspector.getPropertyReadMethod(
- anObject.getClass(), aProperty, EMPTY_ARRAY );
- if ( m != null )
- {
- result = m.invoke( anObject, EMPTY_ARRAY );
+ // no match
+ return null;
+ }
+
+ static private final Method[] getAllMethodsForClass(Class aClass) {
+ Method[] local = aClass.getDeclaredMethods(); // only local
+ Method[] all = aClass.getMethods(); // all public
+ Method[] result = new Method[local.length + all.length];
+ System.arraycopy(local, 0, result, 0, local.length);
+ System.arraycopy(all, 0, result, local.length, all.length);
+ return result;
+ }
+
+ /**
+ * Generates a map of properties to both getter or setter methods for the given
+ * class. Then assigned those maps into the appropriate getterMethods and
+ * setterMethods maps keyed by the specified class. Even on error, this method
+ * will at least place empty property maps into each of the methods maps.
+ */
+ static private void mapPropertiesForClass(Class objectClass) {
+ try {
+ Map readProperties = new HashMap();
+ getterMethods.put(objectClass, readProperties);
+ Map writeProperties = new HashMap();
+ setterMethods.put(objectClass, writeProperties);
+
+ String name, property;
+ Method[] methods = getAllMethodsForClass(objectClass); // throws SecurityException
+ for (int i = 0; i < methods.length; i++) {
+ name = methods[i].getName();
+ methods[i].setAccessible(true); // throws SecurityException
+ if (name.startsWith("set")) {
+ name = name.substring(3);
+ if (!"".equals(name)) // excludes "set()"
+ {
+ putMethodIntoPropertyMap(name, methods[i], writeProperties);
+ }
+ } else if (methods[i].getReturnType() != void.class) {
+ String fullname = name;
+ if (name.startsWith("get")) {
+ name = name.substring(3);
+ } else if (name.startsWith("is")) {
+ name = name.substring(2);
+ } else if (name.startsWith("has") && (!strict)) // what about hashCode()?
+ {
+ name = name.substring(3);
+ }
+
+ if (!"".equals(name) && (!strict)) // excludes "get()", "has()", and "is()"
+ {
+ putMethodIntoPropertyMap(name, methods[i], readProperties);
+ if (fullname != name) { // allows us to match properties that include the get/set prefix as well
+ putMethodIntoPropertyMap(fullname, methods[i], readProperties);
+ }
+ }
+ }
}
- else // no method, try for field
- {
- try
- {
- Field field = anObject.getClass().getDeclaredField( aProperty );
- if ( field != null )
- {
- field.setAccessible( true ); // throws SecurityException
- result = field.get( anObject );
- }
- }
- catch ( Throwable t )
- {
- // ignore for now
- }
- }
-
- if ( result == null )
- {
- if ( anObject instanceof Map )
- {
- result = ((Map)anObject).get( aProperty );
- }
- else
- if ( anObject instanceof List )
- {
- result = ((List)anObject).get( Integer.parseInt( aProperty ) );
- }
- }
-
- if ( invert )
- {
- Object inverted = ValueConverter.invert( result );
- if ( inverted != null ) result = inverted;
- }
- //System.out.println( "getValueForObject: " + anObject + " : " + aProperty + " : " + result );
- return result;
- }
- catch ( Throwable exc )
- {
- if ( exc instanceof InvocationTargetException )
- {
- exc = ((InvocationTargetException)exc).getTargetException();
- }
- if ( exc instanceof RuntimeException )
- {
- throw (RuntimeException)exc;
- }
- if ( debug )
+ } catch (SecurityException se) {
+ System.out.println("Introspector.getMethodFromClass: " + se);
+ // this class will show up with empty getter/setter maps
+ }
+ }
+
+ /**
+ * Places a property-method pair into one of the properties maps. This in effect
+ * maps a property to an array of methods.
+ */
+ private static void putMethodIntoPropertyMap(String aProperty, Method aMethod, Map aMap) {
+ // ensure first character is lower case
+ StringBuffer buffer = new StringBuffer(aProperty);
+ buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));
+ String key = buffer.toString();
+
+ // build array of methods for property
+ Method[] result = (Method[]) aMap.get(key);
+ if (result == null) {
+ result = new Method[] { aMethod };
+ } else {
+ // create new array that's larger by one and copy
+ int i;
+ Method[] enlarged = new Method[result.length + 1];
+ for (i = 0; i < result.length; i++) {
+ enlarged[i] = result[i];
+ }
+ // add the new method to end
+ enlarged[i] = aMethod;
+ result = enlarged;
+ }
+ aMap.put(key, result);
+ }
+
+ /**
+ * Utility method to get a method for a property belonging to a class. Use this
+ * if you don't feel like making the Class array from the parameters you will be
+ * using - pass in the parameters themselves.
+ *
+ * @param objectClass the Class whose property methods will be retrieved.
+ * @param aProperty The property whose method will be retrieved.
+ * @param params An array of parameters to be used.
+ * @return The appropriate method for the class, or null if not found.
+ */
+ static public Method getPropertyReadMethod(Class objectClass, String aProperty, Object[] params) {
+ // optimization: avoid allocating class array for common case
+ if (params.length == 0) {
+ return getPropertyReadMethod(objectClass, aProperty, EMPTY_CLASS_ARRAY);
+ }
+
+ Class[] paramList = new Class[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] != null) {
+ paramList[i] = params[i].getClass();
+ } else {
+ paramList[i] = WILD;
+ }
+ }
+ return getPropertyReadMethod(objectClass, aProperty, paramList);
+ }
+
+ /**
+ * Utility method to get a method for a property belonging to a class. Use this
+ * if you don't feel like making the Class array from the parameters you will be
+ * using - pass in the parameters themselves.
+ *
+ * @param objectClass the Class whose property methods will be retrieved.
+ * @param aProperty The property whose method will be retrieved.
+ * @param params An array of parameters to be used.
+ * @return The appropriate method for the class, or null if not found.
+ */
+ static public Method getPropertyWriteMethod(Class objectClass, String aProperty, Object[] params) {
+ Class[] paramList = new Class[params.length];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] != null) {
+ paramList[i] = params[i].getClass();
+ } else {
+ paramList[i] = WILD;
+ }
+ }
+ return getPropertyWriteMethod(objectClass, aProperty, paramList);
+ }
+
+ /**
+ * Gets a list of the readable properties for the given class. Note that
+ * readable properties may not be writable - see getWriteProperties().
+ *
+ * @return An array of property names in no particular order where each name is
+ * a string with the first character in lower case.
+ */
+ public static String[] getReadPropertiesForClass(Class objectClass) {
+ Map properties = (Map) getterMethods.get(objectClass);
+ if (properties == null) {
+ // need to build maps for this class
+ mapPropertiesForClass(objectClass);
+ // now the map should exist
+ properties = (Map) getterMethods.get(objectClass);
+ }
+
+ // put property names into string array
+ Set keys = properties.keySet();
+ Iterator it = keys.iterator();
+ int len = keys.size();
+ String[] result = new String[len];
+ for (int i = 0; i < len; i++) {
+ result[i] = (String) it.next();
+ }
+ return result;
+ }
+
+ /**
+ * Gets a list of the writable properties for the given class. Note that
+ * writable properties may not be writable - see getReadProperties().
+ *
+ * @return An array of property names in no particular order where each name is
+ * a string with the first character in lower case.
+ */
+ public static String[] getWritePropertiesForClass(Class objectClass) {
+ Map properties = (Map) setterMethods.get(objectClass);
+ if (properties == null) {
+ // need to build maps for this class
+ mapPropertiesForClass(objectClass);
+ // now the map should exist
+ properties = (Map) setterMethods.get(objectClass);
+ }
+
+ // put property names into string array
+ Set keys = properties.keySet();
+ Iterator it = keys.iterator();
+ int len = keys.size();
+ String[] result = new String[len];
+ for (int i = 0; i < len; i++) {
+ result[i] = (String) it.next();
+ }
+ return result;
+ }
+
+ /**
+ * Gets a list of the readable properties for the given object, which may not be
+ * null. This method is more useful than getReadPropertiesForClass in that Maps
+ * will return their keys as properties and Lists will return their element
+ * indices as properties. Note that readable properties may not be writable -
+ * see getWriteProperties().
+ *
+ * @return An array of property names in no particular order where each name is
+ * a string with the first character in lower case.
+ */
+ public static String[] getReadPropertiesForObject(Object anObject) {
+ List properties = new ArrayList();
+ String[] classProperties = getReadPropertiesForClass(anObject.getClass());
+ if (anObject instanceof List) {
+ properties.addAll(getPropertiesForList((List) anObject));
+ }
+ if (anObject instanceof Map) {
+ properties.addAll(getPropertiesForMap((Map) anObject));
+ }
+ int i;
+ int len = classProperties.length + properties.size();
+ String[] result = new String[len];
+ for (i = 0; i < classProperties.length; i++) {
+ result[i] = classProperties[i];
+ }
+ Iterator it = properties.iterator();
+ while (it.hasNext()) {
+ result[i++] = it.next().toString();
+ }
+ return result;
+ }
+
+ /**
+ * Gets a list of the writable properties for the given object, which may not be
+ * null. This method is more useful than getWritePropertiesForClass in that Maps
+ * will return their keys as properties and Lists will return their element
+ * indices as properties. Note that writable properties may not be writable -
+ * see getReadProperties().
+ *
+ * @return An array of property names in no particular order where each name is
+ * a string with the first character in lower case.
+ */
+ public static String[] getWritePropertiesForObject(Object anObject) {
+ List properties = new ArrayList();
+ String[] classProperties = getWritePropertiesForClass(anObject.getClass());
+ if (anObject instanceof List) {
+ properties.addAll(getPropertiesForList((List) anObject));
+ }
+ if (anObject instanceof Map) {
+ properties.addAll(getPropertiesForMap((Map) anObject));
+ }
+
+ int i;
+ int len = classProperties.length + properties.size();
+ String[] result = new String[len];
+ for (i = 0; i < classProperties.length; i++) {
+ result[i] = classProperties[i];
+ }
+ Iterator it = properties.iterator();
+ while (it.hasNext()) {
+ result[i++] = it.next().toString();
+ }
+ return result;
+ }
+
+ private static List getPropertiesForList(List aList) {
+ List result = new ArrayList();
+ int len = aList.size();
+ for (int i = 0; i < len; i++) {
+ result.add(new Integer(i).toString());
+ }
+ return result;
+ }
+
+ private static List getPropertiesForMap(Map aMap) {
+ List result = new ArrayList();
+ Iterator it = ((Map) aMap).keySet().iterator();
+ while (it.hasNext()) {
+ result.add(it.next().toString());
+ }
+ return result;
+ }
+
+ private static Object[] EMPTY_ARRAY = new Object[0];
+
+ /**
+ * Convenience to get a value for a property from an object. An empty property
+ * string is considered the identity property and simply returns the object.
+ *
+ * @throws MissingPropertyException if the property cannot be found on the
+ * object.
+ */
+ public static Object getValueForObject(Object anObject, String aProperty) {
+ if ((aProperty == null) || ("".equals(aProperty))) {
+ return anObject;
+ }
+
+ if (useOGNL && aProperty.startsWith("ognl:")) {
+ try {
+ return ognl.Ognl.getValue(aProperty, anObject);
+ } catch (Throwable t) {
+ if (debug) {
+ System.err.println("Introspector.getValueForObject: " + anObject + "' ( " + anObject.getClass()
+ + " )" + ", ognl:" + aProperty);
+ System.err.println(t);
+ }
+ return null;
+ }
+ }
+
+ boolean invert = false;
+ if (aProperty.startsWith("!")) {
+ aProperty = aProperty.substring(1);
+ invert = true;
+ }
+
+ Object result = null;
+ try {
+ Method m = Introspector.getPropertyReadMethod(anObject.getClass(), aProperty, EMPTY_ARRAY);
+ if (m != null) {
+ result = m.invoke(anObject, EMPTY_ARRAY);
+ } else // no method, try for field
{
- System.out.println(
- "Introspector.getValueForObject: "
- + anObject + "' ( " + anObject.getClass() + " )"
- + ", " + aProperty + ": " );
- }
- throw new WotonomyException( exc );
- }
+ try {
+ Field field = anObject.getClass().getDeclaredField(aProperty);
+ if (field != null) {
+ field.setAccessible(true); // throws SecurityException
+ result = field.get(anObject);
+ }
+ } catch (Throwable t) {
+ // ignore for now
+ }
+ }
+
+ if (result == null) {
+ if (anObject instanceof Map) {
+ result = ((Map) anObject).get(aProperty);
+ } else if (anObject instanceof List) {
+ result = ((List) anObject).get(Integer.parseInt(aProperty));
+ }
+ }
+
+ if (invert) {
+ Object inverted = ValueConverter.invert(result);
+ if (inverted != null)
+ result = inverted;
+ }
+ // System.out.println( "getValueForObject: " + anObject + " : " + aProperty + "
+ // : " + result );
+ return result;
+ } catch (Throwable exc) {
+ if (exc instanceof InvocationTargetException) {
+ exc = ((InvocationTargetException) exc).getTargetException();
+ }
+ if (exc instanceof RuntimeException) {
+ throw (RuntimeException) exc;
+ }
+ if (debug) {
+ System.out.println("Introspector.getValueForObject: " + anObject + "' ( " + anObject.getClass() + " )"
+ + ", " + aProperty + ": ");
+ }
+ throw new WotonomyException(exc);
+ }
//! throw new MissingPropertyException();
- }
-
- /**
- * Convenience to set a value for a property from an object.
- * Returns the return value from executing the specified method,
- * or null if the method returns type void.
- * @throws MissingPropertyException if the property cannot be
- * found on the object.
- * @throws NullPrimitiveException if the property is of primitive
- * type and the value is null.
- */
- public static Object setValueForObject(
- Object anObject, String aProperty, Object aValue )
- {
- if ( useOGNL && aProperty.startsWith( "ognl:" ) )
- {
- try
- {
- ognl.Ognl.setValue( aProperty, anObject, aValue );
- }
- catch ( Throwable t )
- {
- if ( debug )
- {
- System.err.println(
- "Introspector.setValueForObject: "
- + anObject + "' ( " + anObject.getClass() + " )"
- + ", ognl:" + aProperty + " : " + aValue );
- System.err.println( t );
- }
- }
- return null;
- }
-
- try
- {
- if ( aProperty.startsWith( "!" ) )
- {
- aProperty = aProperty.substring(1);
- Object inverted = ValueConverter.invert( aValue );
- if ( inverted != null ) aValue = inverted;
- }
-
- Method m = null;
- if ( aValue != null )
- {
- m = Introspector.getPropertyWriteMethod(
- anObject.getClass(), aProperty, new Class[] { aValue.getClass() } );
- }
- if ( m == null )
- {
- m = Introspector.getPropertyWriteMethod(
- anObject.getClass(), aProperty, new Class[] { WILD } );
- if ( ( m != null ) && ( aValue != null ) )
- {
- // check for null primitive
- if ( ( aValue == null ) &&
- ( m.getParameterTypes()[0].isPrimitive() ) )
- {
- throw new NullPrimitiveException();
- }
-
- // convert if possible
- Object o = ValueConverter.convertObjectToClass(
- aValue, m.getParameterTypes()[0] );
- if ( o != null )
- {
- aValue = o;
- }
- }
- }
- if ( m != null )
- {
- return m.invoke( anObject, new Object[] { aValue } );
+ }
+
+ /**
+ * Convenience to set a value for a property from an object. Returns the return
+ * value from executing the specified method, or null if the method returns type
+ * void.
+ *
+ * @throws MissingPropertyException if the property cannot be found on the
+ * object.
+ * @throws NullPrimitiveException if the property is of primitive type and the
+ * value is null.
+ */
+ public static Object setValueForObject(Object anObject, String aProperty, Object aValue) {
+ if (useOGNL && aProperty.startsWith("ognl:")) {
+ try {
+ ognl.Ognl.setValue(aProperty, anObject, aValue);
+ } catch (Throwable t) {
+ if (debug) {
+ System.err.println("Introspector.setValueForObject: " + anObject + "' ( " + anObject.getClass()
+ + " )" + ", ognl:" + aProperty + " : " + aValue);
+ System.err.println(t);
+ }
}
- else // no method, try for field
- {
- try
- {
- Field field = anObject.getClass().getDeclaredField( aProperty );
- if ( field != null )
- {
- field.setAccessible( true ); // throws SecurityException
- field.set( anObject, aValue );
- return null;
- }
- }
- catch ( Throwable t )
- {
- // ignore for now
- }
- }
-
- if ( anObject instanceof Map )
- {
- return ((Map)anObject).put( aProperty, aValue );
+ return null;
+ }
+
+ try {
+ if (aProperty.startsWith("!")) {
+ aProperty = aProperty.substring(1);
+ Object inverted = ValueConverter.invert(aValue);
+ if (inverted != null)
+ aValue = inverted;
+ }
+
+ Method m = null;
+ if (aValue != null) {
+ m = Introspector.getPropertyWriteMethod(anObject.getClass(), aProperty,
+ new Class[] { aValue.getClass() });
}
- if ( anObject instanceof List )
+ if (m == null) {
+ m = Introspector.getPropertyWriteMethod(anObject.getClass(), aProperty, new Class[] { WILD });
+ if ((m != null) && (aValue != null)) {
+ // check for null primitive
+ if ((aValue == null) && (m.getParameterTypes()[0].isPrimitive())) {
+ throw new NullPrimitiveException();
+ }
+
+ // convert if possible
+ Object o = ValueConverter.convertObjectToClass(aValue, m.getParameterTypes()[0]);
+ if (o != null) {
+ aValue = o;
+ }
+ }
+ }
+ if (m != null) {
+ return m.invoke(anObject, new Object[] { aValue });
+ } else // no method, try for field
{
- List list = (List) anObject;
- int i = Integer.parseInt( aProperty );
- if ( list.size() < i+1 )
- {
- // expand list as necessary
- for ( int j = list.size(); j <= i; j++ )
- {
- list.add( new Object() ); // placeholder
- }
- }
- return list.set( i, aValue );
+ try {
+ Field field = anObject.getClass().getDeclaredField(aProperty);
+ if (field != null) {
+ field.setAccessible(true); // throws SecurityException
+ field.set(anObject, aValue);
+ return null;
+ }
+ } catch (Throwable t) {
+ // ignore for now
+ }
+ }
+
+ if (anObject instanceof Map) {
+ return ((Map) anObject).put(aProperty, aValue);
+ }
+ if (anObject instanceof List) {
+ List list = (List) anObject;
+ int i = Integer.parseInt(aProperty);
+ if (list.size() < i + 1) {
+ // expand list as necessary
+ for (int j = list.size(); j <= i; j++) {
+ list.add(new Object()); // placeholder
+ }
+ }
+ return list.set(i, aValue);
}
- }
- catch ( Throwable exc )
- {
- if ( exc instanceof IllegalArgumentException )
- {
+ } catch (Throwable exc) {
+ if (exc instanceof IllegalArgumentException) {
System.out.println(
- "Introspector.setValueForObject: "
- + anObject + " , " + aProperty + " , '"
- + aValue + "' ):" );
- System.out.println( exc );
- }
- else
- if ( exc instanceof InvocationTargetException )
- {
- exc = ((InvocationTargetException)exc).getTargetException();
- }
- if ( exc instanceof RuntimeException )
- {
- throw (RuntimeException)exc;
- }
- if ( debug )
- {
+ "Introspector.setValueForObject: " + anObject + " , " + aProperty + " , '" + aValue + "' ):");
+ System.out.println(exc);
+ } else if (exc instanceof InvocationTargetException) {
+ exc = ((InvocationTargetException) exc).getTargetException();
+ }
+ if (exc instanceof RuntimeException) {
+ throw (RuntimeException) exc;
+ }
+ if (debug) {
System.out.println(
- "Introspector.setValueForObject: "
- + anObject + " , " + aProperty + " , '"
- + aValue + "' ):" );
+ "Introspector.setValueForObject: " + anObject + " , " + aProperty + " , '" + aValue + "' ):");
}
- throw new WotonomyException( exc );
- }
- return null;
+ throw new WotonomyException(exc);
+ }
+ return null;
//! throw new MissingPropertyException();
- }
-
- /**
- * Gets a value from an object or any of its child objects.
- * This will parse the property string for "."'s and get
- * values for each successive object's property in the path.
- * An empty property string is considered the identity property
- * and simply returns the object.
- */
- public static Object get( Object anObject, String aProperty )
- {
- int i = aProperty.indexOf( SEPARATOR );
- if ( i == -1 ) return getValueForObject( anObject, aProperty );
-
- String pathElement = aProperty.substring( 0, i );
- String remainder = aProperty.substring( i+1 );
-
- Object result = getValueForObject( anObject, pathElement );
- if ( result == null ) return null;
- return get( result, remainder );
- }
-
- /**
- * Sets a value in an object or any of its child objects.
- * This will parse the property string for "."'s and set
- * values for each successive object's property in the path.<br><br>
- *
- * If a property is not found, this method will try to
- * implicitly create hash maps (if possible) to fill out the path.
- * This is useful when dealing with trees of nested maps.
- */
- public static Object set( Object anObject, String aProperty, Object aValue )
- {
- int i = aProperty.indexOf( SEPARATOR );
- if ( i == -1 ) return setValueForObject( anObject, aProperty, aValue );
-
- String pathElement = aProperty.substring( 0, i );
- String remainder = aProperty.substring( i+1 );
-
- Object result = getValueForObject( anObject, pathElement );
- if ( result == null )
- {
+ }
+
+ /**
+ * Gets a value from an object or any of its child objects. This will parse the
+ * property string for "."'s and get values for each successive object's
+ * property in the path. An empty property string is considered the identity
+ * property and simply returns the object.
+ */
+ public static Object get(Object anObject, String aProperty) {
+ int i = aProperty.indexOf(SEPARATOR);
+ if (i == -1)
+ return getValueForObject(anObject, aProperty);
+
+ String pathElement = aProperty.substring(0, i);
+ String remainder = aProperty.substring(i + 1);
+
+ Object result = getValueForObject(anObject, pathElement);
+ if (result == null)
+ return null;
+ return get(result, remainder);
+ }
+
+ /**
+ * Sets a value in an object or any of its child objects. This will parse the
+ * property string for "."'s and set values for each successive object's
+ * property in the path.<br>
+ * <br>
+ *
+ * If a property is not found, this method will try to implicitly create hash
+ * maps (if possible) to fill out the path. This is useful when dealing with
+ * trees of nested maps.
+ */
+ public static Object set(Object anObject, String aProperty, Object aValue) {
+ int i = aProperty.indexOf(SEPARATOR);
+ if (i == -1)
+ return setValueForObject(anObject, aProperty, aValue);
+
+ String pathElement = aProperty.substring(0, i);
+ String remainder = aProperty.substring(i + 1);
+
+ Object result = getValueForObject(anObject, pathElement);
+ if (result == null) {
result = new HashMap(2);
- setValueForObject( anObject, pathElement, result );
+ setValueForObject(anObject, pathElement, result);
}
- return set( result, remainder, aValue );
- }
-
+ return set(result, remainder, aValue);
+ }
+
/**
- * If set to true, exceptions printed to System.out.println.
- * Defaults to true.
- */
- public void setDebug( boolean isDebug )
- {
+ * If set to true, exceptions printed to System.out.println. Defaults to true.
+ */
+ public void setDebug(boolean isDebug) {
debug = isDebug;
- }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:11:47 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.19 2004/02/05 02:20:34 mpowers
- * Added experimental ognl support (if ognl is present).
+ * Revision 1.19 2004/02/05 02:20:34 mpowers Added experimental ognl support (if
+ * ognl is present).
*
- * Revision 1.18 2003/03/26 16:44:35 mpowers
- * Now correctly reflecting on all methods, not just locally declared ones.
+ * Revision 1.18 2003/03/26 16:44:35 mpowers Now correctly reflecting on all
+ * methods, not just locally declared ones.
*
- * Revision 1.17 2003/02/21 21:10:51 mpowers
- * Now reaching package, protected, and private methods and fields.
+ * Revision 1.17 2003/02/21 21:10:51 mpowers Now reaching package, protected,
+ * and private methods and fields.
*
- * Revision 1.16 2003/01/28 22:11:59 mpowers
- * Now more lenient in resolving properties starting with "is" "get" or "has".
+ * Revision 1.16 2003/01/28 22:11:59 mpowers Now more lenient in resolving
+ * properties starting with "is" "get" or "has".
*
- * Revision 1.15 2003/01/27 15:10:54 mpowers
- * Better handling for illegal argument exceptions.
+ * Revision 1.15 2003/01/27 15:10:54 mpowers Better handling for illegal
+ * argument exceptions.
*
- * Revision 1.14 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.14 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.13 2002/10/11 15:35:12 mpowers
- * Removed printlns.
+ * Revision 1.13 2002/10/11 15:35:12 mpowers Removed printlns.
*
- * Revision 1.11 2001/05/02 17:58:41 mpowers
- * Removed debugging code, added comments.
+ * Revision 1.11 2001/05/02 17:58:41 mpowers Removed debugging code, added
+ * comments.
*
- * Revision 1.10 2001/04/08 21:00:54 mpowers
- * Changes to support new objectsForFetchSpecification scheme.
+ * Revision 1.10 2001/04/08 21:00:54 mpowers Changes to support new
+ * objectsForFetchSpecification scheme.
*
- * Revision 1.9 2001/03/29 03:30:36 mpowers
- * Refactored duplicator a bit.
+ * Revision 1.9 2001/03/29 03:30:36 mpowers Refactored duplicator a bit.
* Disabled MissingPropertyExceptions for now.
*
- * Revision 1.8 2001/03/28 17:52:45 mpowers
- * Corrected the throws in the docs.
+ * Revision 1.8 2001/03/28 17:52:45 mpowers Corrected the throws in the docs.
*
- * Revision 1.7 2001/03/28 17:49:13 mpowers
- * Better exception handling in Introspector.
+ * Revision 1.7 2001/03/28 17:49:13 mpowers Better exception handling in
+ * Introspector.
*
- * Revision 1.6 2001/03/13 21:40:20 mpowers
- * Improved handling of runtime exceptions.
+ * Revision 1.6 2001/03/13 21:40:20 mpowers Improved handling of runtime
+ * exceptions.
*
- * Revision 1.5 2001/03/09 22:06:35 mpowers
- * Now extracting the wrapped exception from InvocationTargetExceptions.
+ * Revision 1.5 2001/03/09 22:06:35 mpowers Now extracting the wrapped exception
+ * from InvocationTargetExceptions.
*
- * Revision 1.4 2001/03/01 20:36:35 mpowers
- * Better error handling and better handling of nulls.
+ * Revision 1.4 2001/03/01 20:36:35 mpowers Better error handling and better
+ * handling of nulls.
*
- * Revision 1.3 2001/01/17 16:20:57 mpowers
- * Introspector now handles the identity property.
+ * Revision 1.3 2001/01/17 16:20:57 mpowers Introspector now handles the
+ * identity property.
*
- * Revision 1.2 2001/01/09 20:08:17 mpowers
- * Slight optimization.
+ * Revision 1.2 2001/01/09 20:08:17 mpowers Slight optimization.
*
- * Revision 1.1.1.1 2000/12/21 15:52:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:04 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:46 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:46 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java
index b1ad824..45080a2 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java
@@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation.internal;
/**
-* A WotonomyException that is thrown by Introspector.
-* This class serves as a base class for other exceptions.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A WotonomyException that is thrown by Introspector. This class serves as a
+ * base class for other exceptions.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
-public class IntrospectorException extends WotonomyException
-{
+public class IntrospectorException extends WotonomyException {
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java
index c1e30d3..c89742f 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java
@@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation.internal;
/**
-* A IntrospectorException that is thrown by Introspector when
-* a property does not exist for an object.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A IntrospectorException that is thrown by Introspector when a property does
+ * not exist for an object.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
-public class MissingPropertyException extends IntrospectorException
-{
+public class MissingPropertyException extends IntrospectorException {
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java
index 43c14a5..7761876 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java
@@ -47,7 +47,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
- */
+ */
package net.wotonomy.foundation.internal;
@@ -59,310 +59,284 @@ import java.util.Enumeration;
import java.util.Hashtable;
/**
- * The correct name for this class should be URLClassLoader.
- * But there is already a class by that name in JDK1.2.
+ * The correct name for this class should be URLClassLoader. But there is
+ * already a class by that name in JDK1.2.
*
- * I have had quite a few problems with URLClassLoader in
- * past, so I ended up writing this ClassLoader. I found that
- * the Java 2's URLClassLoader, does not close the Jar file once
- * opened. It is a pretty good optimization step, but if you
- * modify the class in the jar file, it does not pick it up. Some
- * operating systems may not let you modify the jar file while it is
- * still open. IMHO, it does make sense to close the jar file
- * after you are done reading the class data. But this approach may not
- * get you the performance of the URLClassLoader, but it works in all
- * cases and also runs on JDK1.1. I have enhanced this class loader
- * to read all the zip/jar entries once & cache the data, so that
- * there is no overhead of opening/closing jar file to pick up
+ * I have had quite a few problems with URLClassLoader in past, so I ended up
+ * writing this ClassLoader. I found that the Java 2's URLClassLoader, does not
+ * close the Jar file once opened. It is a pretty good optimization step, but if
+ * you modify the class in the jar file, it does not pick it up. Some operating
+ * systems may not let you modify the jar file while it is still open. IMHO, it
+ * does make sense to close the jar file after you are done reading the class
+ * data. But this approach may not get you the performance of the
+ * URLClassLoader, but it works in all cases and also runs on JDK1.1. I have
+ * enhanced this class loader to read all the zip/jar entries once & cache the
+ * data, so that there is no overhead of opening/closing jar file to pick up
* each entry.
*
*
* @author Harish Prabandham
*/
public class NetworkClassLoader extends ClassLoader {
- private ClassLoader parent = null; // parent classloader
- private Hashtable classCache = new Hashtable();
- private Hashtable urlset = new Hashtable();
-
- /**
- * Creates a new instance of the class loader.
- * @param delegate/parent class loader.
- */
- public NetworkClassLoader(ClassLoader parent) {
- setParent(parent);
- }
-
- /**
- * Sets the parent/delegate class loader.
- * @param delegate/parent class loader.
- */
- protected final void setParent(ClassLoader parent) {
- this.parent = parent;
- }
-
- /**
- * Adds the given URL to this class loader. If the URL
- * ends with "/", then it is assumed to be a directory
- * otherwise, it is assumed to be a zip/jar file. If the
- * same URL is added again, the URL is re-opened and this
- * zip/jar file is used for serving any future class requests.
- * @param URL where to look for the classes.
- */
- public synchronized void addURL(URL url) {
- // System.out.println("Adding url: " + url);
- if(!urlset.containsKey(url)) {
- try {
- urlset.put(url, new URLResourceReader(url));
- }catch(IOException ioe){
- // Probably a bad url...
- }
- } else {
- // remove the old one & add a new one...
- try{
- URLResourceReader newu = new URLResourceReader(url);
- URLResourceReader oldu = (URLResourceReader) urlset.get(url);
- oldu.close();
- urlset.remove(url);
- urlset.put(url, newu);
- } catch (IOException ioe) {
- }
- }
- }
-
- /**
- * @return An enumeration of URLs where this class loader
- * looks for classes.
- */
- public Enumeration getURLs() {
- return urlset.keys();
- }
-
- /**
- * Call this to bypass the implementation of loadClass.
- */
- public Class findClass(String name) {
- byte[] b = loadClassData(name);
- if ( b == null ) return null;
- return defineClass(name, b, 0, b.length);
- }
-
- protected byte[] loadResource(URL url, String resourceName)
- throws IOException {
- URLResourceReader urr = (URLResourceReader) urlset.get(url);
- // System.out.println("Loading from " + urr + " " + resourceName);
- if(urr != null) {
- return urr.getResource(resourceName);
- }
-
- return null;
- }
-
- protected byte[] loadResource(String resource) {
- byte[] barray = null;
- for(Enumeration e = urlset.keys(); e.hasMoreElements();) {
- URL url = (URL) e.nextElement();
-
- try {
- barray = loadResource(url, resource);
- } catch(Exception ex) {
- } finally {
- if(barray != null)
- break;
- }
- }
-
- return barray;
- }
-
- protected byte[] loadClassData(String classname) {
- String resourceName = classname.replace('.', '/') + ".class";
- return loadResource(resourceName);
- }
-
- /**
- * Overridden to search for a resource and return
- * a "jar"-style URL or normal "file" URL as necessary.
- */
- protected URL findResource(String name)
- { //System.out.println( "findResource: " + name );
- URL url;
- byte[] barray = null;
-
- for ( Enumeration e = urlset.keys(); e.hasMoreElements(); )
- {
- url = (URL) e.nextElement();
- try
- {
- barray = loadResource(url, name); // loads fully: wasteful
- }
- catch(Exception ex)
- {
- // do nothing
- }
- if( barray != null )
- {
- try
- {
- String ref = url.toString();
- if ( ref.endsWith( ".jar" ) )
- {
- //System.out.println( "jar:" + ref + "!/" + name );
- return new URL( "jar:" + ref + "!/" + name );
- }
- else
- {
- //System.out.println( new URL( url, name ).toString() );
- return new URL( url, name );
- }
- }
- catch ( Throwable t )
- {
- t.printStackTrace();
- }
- }
- }
-
- return null;
- }
-
- /**
- * @return The resource as the input stream if such a resource
- * exists, otherwise returns null.
- */
- public InputStream getResourceAsStream(String name) {
- //System.out.println( "getResourceAsStream: " + name );
- InputStream istream = null;
-
- // Algorithm:
- //
- // 1. first check the system path for the resource
- // 2. next check the delegate/parent class loader for the resource
- // 3. then attempt to get the resource from the url set.
- //
-
- // Lets check the system path for the resource.
- istream = getSystemResourceAsStream(name);
- if(istream != null)
- return istream;
-
- // Lets check the parent/delegate class loader for the resource.
- if(parent != null) {
- istream = parent.getResourceAsStream(name);
- if(istream != null)
- return istream;
- }
-
- // Lets load it ourselves.
- byte[] data = loadResource(name);
- if(data != null) {
- istream = new ByteArrayInputStream(data);
- }
-
- return istream;
- }
-
- /**
- * java.lang.ClassLoader's defineClass method is final, so the
- * its subclasses cannot override this method. But, this class
- * calls this method in the loadClass() instead.
- * @param The name of the class without ".class" extension.
- * @param The class data bytes.
- * @return The class object.
- */
- protected Class defineClass(String classname, byte[] classdata) {
- return defineClass(classname, classdata, 0, classdata.length);
- }
-
- public synchronized Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class c = null;
-
- // Algorithm: (Please do not change the order; unless you
- // have a good reason to do so).
- //
- // 1. first check the system class loader.
- // 2. next check the delegate/parent class loader.
- // 3. next check the class cache
- // 4. then attempt to load classes from the URL set.
- //
-
- // Lets see if the class is in system class loader.
- try {
- c = findSystemClass(name);
- }catch(ClassNotFoundException cnfe) {
- }finally {
- if(c != null)
- return c;
- }
-
- // Lets see if the class is in parent class loader.
- try {
- if(parent != null)
- c = parent.loadClass(name);
- }catch(ClassNotFoundException cnfe) {
- }finally {
- if(c != null)
- return c;
- }
-
- // Lets see if the class is in the cache..
- c = (Class) classCache.get(name);
-
- if(c != null)
- return c;
-
-
- // Lets see if we find the class all by ourselves.
- byte[] data = loadClassData(name);
-
- if(data != null) {
- // we did !!
- c = defineClass(name, data);
- classCache.put(name, c);
- if(resolve)
- resolveClass(c);
- } else {
- // We are out of luck at this point...
- throw new ClassNotFoundException(name);
- }
-
- return c;
- }
-
- /**
- * This method resets this ClassLoader's state. It completely
- * removes all the URLs and classes in this class loader cache.
- */
- public final void clear() {
- urlset.clear();
- classCache.clear();
- }
-
- /**
- * This method resets this ClassLoader's state and resets the
- * references for garbage collection.
- */
- protected void finalize() throws Throwable {
- // Cleanup real well. Otherwise, this can be
- // a major source of memory leaks...
-
- // remove all the urls & class entries.
- clear();
-
- parent = null;
- urlset = null;
- classCache = null;
- }
+ private ClassLoader parent = null; // parent classloader
+ private Hashtable classCache = new Hashtable();
+ private Hashtable urlset = new Hashtable();
+
+ /**
+ * Creates a new instance of the class loader.
+ *
+ * @param delegate/parent class loader.
+ */
+ public NetworkClassLoader(ClassLoader parent) {
+ setParent(parent);
+ }
+
+ /**
+ * Sets the parent/delegate class loader.
+ *
+ * @param delegate/parent class loader.
+ */
+ protected final void setParent(ClassLoader parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Adds the given URL to this class loader. If the URL ends with "/", then it is
+ * assumed to be a directory otherwise, it is assumed to be a zip/jar file. If
+ * the same URL is added again, the URL is re-opened and this zip/jar file is
+ * used for serving any future class requests.
+ *
+ * @param URL where to look for the classes.
+ */
+ public synchronized void addURL(URL url) {
+ // System.out.println("Adding url: " + url);
+ if (!urlset.containsKey(url)) {
+ try {
+ urlset.put(url, new URLResourceReader(url));
+ } catch (IOException ioe) {
+ // Probably a bad url...
+ }
+ } else {
+ // remove the old one & add a new one...
+ try {
+ URLResourceReader newu = new URLResourceReader(url);
+ URLResourceReader oldu = (URLResourceReader) urlset.get(url);
+ oldu.close();
+ urlset.remove(url);
+ urlset.put(url, newu);
+ } catch (IOException ioe) {
+ }
+ }
+ }
+
+ /**
+ * @return An enumeration of URLs where this class loader looks for classes.
+ */
+ public Enumeration getURLs() {
+ return urlset.keys();
+ }
+
+ /**
+ * Call this to bypass the implementation of loadClass.
+ */
+ public Class findClass(String name) {
+ byte[] b = loadClassData(name);
+ if (b == null)
+ return null;
+ return defineClass(name, b, 0, b.length);
+ }
+
+ protected byte[] loadResource(URL url, String resourceName) throws IOException {
+ URLResourceReader urr = (URLResourceReader) urlset.get(url);
+ // System.out.println("Loading from " + urr + " " + resourceName);
+ if (urr != null) {
+ return urr.getResource(resourceName);
+ }
+
+ return null;
+ }
+
+ protected byte[] loadResource(String resource) {
+ byte[] barray = null;
+ for (Enumeration e = urlset.keys(); e.hasMoreElements();) {
+ URL url = (URL) e.nextElement();
+
+ try {
+ barray = loadResource(url, resource);
+ } catch (Exception ex) {
+ } finally {
+ if (barray != null)
+ break;
+ }
+ }
+
+ return barray;
+ }
+
+ protected byte[] loadClassData(String classname) {
+ String resourceName = classname.replace('.', '/') + ".class";
+ return loadResource(resourceName);
+ }
+
+ /**
+ * Overridden to search for a resource and return a "jar"-style URL or normal
+ * "file" URL as necessary.
+ */
+ protected URL findResource(String name) { // System.out.println( "findResource: " + name );
+ URL url;
+ byte[] barray = null;
+
+ for (Enumeration e = urlset.keys(); e.hasMoreElements();) {
+ url = (URL) e.nextElement();
+ try {
+ barray = loadResource(url, name); // loads fully: wasteful
+ } catch (Exception ex) {
+ // do nothing
+ }
+ if (barray != null) {
+ try {
+ String ref = url.toString();
+ if (ref.endsWith(".jar")) {
+ // System.out.println( "jar:" + ref + "!/" + name );
+ return new URL("jar:" + ref + "!/" + name);
+ } else {
+ // System.out.println( new URL( url, name ).toString() );
+ return new URL(url, name);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return The resource as the input stream if such a resource exists, otherwise
+ * returns null.
+ */
+ public InputStream getResourceAsStream(String name) {
+ // System.out.println( "getResourceAsStream: " + name );
+ InputStream istream = null;
+
+ // Algorithm:
+ //
+ // 1. first check the system path for the resource
+ // 2. next check the delegate/parent class loader for the resource
+ // 3. then attempt to get the resource from the url set.
+ //
+
+ // Lets check the system path for the resource.
+ istream = getSystemResourceAsStream(name);
+ if (istream != null)
+ return istream;
+
+ // Lets check the parent/delegate class loader for the resource.
+ if (parent != null) {
+ istream = parent.getResourceAsStream(name);
+ if (istream != null)
+ return istream;
+ }
+
+ // Lets load it ourselves.
+ byte[] data = loadResource(name);
+ if (data != null) {
+ istream = new ByteArrayInputStream(data);
+ }
+
+ return istream;
+ }
+
+ /**
+ * java.lang.ClassLoader's defineClass method is final, so the its subclasses
+ * cannot override this method. But, this class calls this method in the
+ * loadClass() instead.
+ *
+ * @param The name of the class without ".class" extension.
+ * @param The class data bytes.
+ * @return The class object.
+ */
+ protected Class defineClass(String classname, byte[] classdata) {
+ return defineClass(classname, classdata, 0, classdata.length);
+ }
+
+ public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ Class c = null;
+
+ // Algorithm: (Please do not change the order; unless you
+ // have a good reason to do so).
+ //
+ // 1. first check the system class loader.
+ // 2. next check the delegate/parent class loader.
+ // 3. next check the class cache
+ // 4. then attempt to load classes from the URL set.
+ //
+
+ // Lets see if the class is in system class loader.
+ try {
+ c = findSystemClass(name);
+ } catch (ClassNotFoundException cnfe) {
+ } finally {
+ if (c != null)
+ return c;
+ }
+
+ // Lets see if the class is in parent class loader.
+ try {
+ if (parent != null)
+ c = parent.loadClass(name);
+ } catch (ClassNotFoundException cnfe) {
+ } finally {
+ if (c != null)
+ return c;
+ }
+
+ // Lets see if the class is in the cache..
+ c = (Class) classCache.get(name);
+
+ if (c != null)
+ return c;
+
+ // Lets see if we find the class all by ourselves.
+ byte[] data = loadClassData(name);
+
+ if (data != null) {
+ // we did !!
+ c = defineClass(name, data);
+ classCache.put(name, c);
+ if (resolve)
+ resolveClass(c);
+ } else {
+ // We are out of luck at this point...
+ throw new ClassNotFoundException(name);
+ }
+
+ return c;
+ }
+
+ /**
+ * This method resets this ClassLoader's state. It completely removes all the
+ * URLs and classes in this class loader cache.
+ */
+ public final void clear() {
+ urlset.clear();
+ classCache.clear();
+ }
+
+ /**
+ * This method resets this ClassLoader's state and resets the references for
+ * garbage collection.
+ */
+ protected void finalize() throws Throwable {
+ // Cleanup real well. Otherwise, this can be
+ // a major source of memory leaks...
+
+ // remove all the urls & class entries.
+ clear();
+
+ parent = null;
+ urlset = null;
+ classCache = null;
+ }
}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java
index e367211..bf1dffd 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java
@@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation.internal;
/**
-* A IntrospectorException that is thrown by Introspector when
-* trying to set a primitive type to null.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * A IntrospectorException that is thrown by Introspector when trying to set a
+ * primitive type to null.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
-public class NullPrimitiveException extends IntrospectorException
-{
+public class NullPrimitiveException extends IntrospectorException {
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java
index abdc82f..c804893 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java
@@ -21,80 +21,61 @@ package net.wotonomy.foundation.internal;
import java.io.Serializable;
import java.util.Comparator;
-
/**
-* A Comparator that will sort elements based on the
-* property specified in the constructor.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class PropertyComparator implements Comparator, Serializable
-{
- private String property;
+ * A Comparator that will sort elements based on the property specified in the
+ * constructor.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class PropertyComparator implements Comparator, Serializable {
+ private String property;
-/**
-* Standard constructor to configure the comparator.
-* @param aProperty A property whose value is used to sort elements.
-*/
- public PropertyComparator( String aProperty )
- {
+ /**
+ * Standard constructor to configure the comparator.
+ *
+ * @param aProperty A property whose value is used to sort elements.
+ */
+ public PropertyComparator(String aProperty) {
property = aProperty;
- }
+ }
- // interface Comparator
+ // interface Comparator
- public int compare(Object o1, Object o2)
- {
- Object v1 = Introspector.get( o1, property );
- Object v2 = Introspector.get( o2, property );
- if ( v1 instanceof Comparable )
- {
- return ((Comparable)v1).compareTo( v2 );
- }
- else
- if ( v2 instanceof Comparable )
- {
- return ((Comparable)v2).compareTo( v1 );
- }
- else
- {
- if ( v1 == null )
- {
- if ( v2 == null )
- {
+ public int compare(Object o1, Object o2) {
+ Object v1 = Introspector.get(o1, property);
+ Object v2 = Introspector.get(o2, property);
+ if (v1 instanceof Comparable) {
+ return ((Comparable) v1).compareTo(v2);
+ } else if (v2 instanceof Comparable) {
+ return ((Comparable) v2).compareTo(v1);
+ } else {
+ if (v1 == null) {
+ if (v2 == null) {
return 0; // both nulls are equal
}
return -1; // null is less than any object
- }
- else
- if ( v2 == null )
- {
+ } else if (v2 == null) {
return 1; // any object is greater than null
}
}
// last resort: compare string conversions
- return v1.toString().compareTo( v2.toString() );
+ return v1.toString().compareTo(v2.toString());
}
-
- public boolean equals( Object obj )
- {
- return ( obj instanceof PropertyComparator );
+
+ public boolean equals(Object obj) {
+ return (obj instanceof PropertyComparator);
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:11:47 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:52:07 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:07 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:46 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:46 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java
index 03231c7..3698325 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java
@@ -23,23 +23,26 @@ import java.io.*;
/**
* PropertyListParser can parse a property list (plist) file or string, and
- * return the top-level object represented by the plist. <p>
+ * return the top-level object represented by the plist.
+ * <p>
*
- * A property list is a heirarchical data structure containing only Maps,
- * Lists, and Strings -- nothing else. In other words, a property list is
- * either a Map, List, or String instance, with the restrictions that the
- * collections may only contain Map, List, or String instances. <p>
+ * A property list is a heirarchical data structure containing only Maps, Lists,
+ * and Strings -- nothing else. In other words, a property list is either a Map,
+ * List, or String instance, with the restrictions that the collections may only
+ * contain Map, List, or String instances.
+ * <p>
*
- * This class can read a particularly-formatted string or file, and create
- * the property list structure described. It provides a convenient means
- * for having a structured data file, letting programs simply deal with the
- * structure rather than having to do a lot of string parsing work as well.
- * The concept is similar to Properties files, except that the values can
- * be nested Maps or Lists instead of only Strings. <p>
+ * This class can read a particularly-formatted string or file, and create the
+ * property list structure described. It provides a convenient means for having
+ * a structured data file, letting programs simply deal with the structure
+ * rather than having to do a lot of string parsing work as well. The concept is
+ * similar to Properties files, except that the values can be nested Maps or
+ * Lists instead of only Strings.
+ * <p>
*
* A Map is specified in a file by key/value pairs surrounded by brace
- * characters. An equal sign (=) must be between the key and value, and
- * there must be a semicolon (;) following the value.
+ * characters. An equal sign (=) must be between the key and value, and there
+ * must be a semicolon (;) following the value.
*
* <pre>
* {
@@ -49,35 +52,42 @@ import java.io.*;
* }
* </pre>
*
- * A List is specified by a comma-separated list of values surrounded by parentheses, like:
+ * A List is specified by a comma-separated list of values surrounded by
+ * parentheses, like:
+ *
* <pre>
* ( value1, value2, value3, etc... )
* </pre>
*
- * A String can either be quoted in the manner of a constant string in
- * Java, or unquoted. If unquoted, the string can only contain
- * alphanumerics, underscores (_), periods (.), dollar signs ($), colons
- * (:), or forward slashes (/). If any other character appears in the
- * string, it must be quoted (i.e., surrounded by &quot; characters).
- * Quoted strings may also contain \n, \t, \f, \v, \b, and \a escapes,
- * octal escapes of the form \000, and unicode escapes of the form of \U
- * followed by four hexadecimal characters. Any other character escaped
- * by a backslash will be treated as that character, and the escaping
- * backslash character will be omitted. Thus, to represent an actual
- * backslash, it must appear as \\ in the quoted string. <p>
+ * A String can either be quoted in the manner of a constant string in Java, or
+ * unquoted. If unquoted, the string can only contain alphanumerics, underscores
+ * (_), periods (.), dollar signs ($), colons (:), or forward slashes (/). If
+ * any other character appears in the string, it must be quoted (i.e.,
+ * surrounded by &quot; characters). Quoted strings may also contain \n, \t, \f,
+ * \v, \b, and \a escapes, octal escapes of the form \000, and unicode escapes
+ * of the form of \U followed by four hexadecimal characters. Any other
+ * character escaped by a backslash will be treated as that character, and the
+ * escaping backslash character will be omitted. Thus, to represent an actual
+ * backslash, it must appear as \\ in the quoted string.
+ * <p>
+ *
+ * All whitespace between elements is ignored, and both //-style and /*-style
+ * comments are allowed to appear anywhere between elements.
+ * <p>
*
- * All whitespace between elements is ignored, and both //-style and
- * /*-style comments are allowed to appear anywhere between elements. <p>
+ * If there are any syntax errors encountered while parsing, RuntimeExceptions
+ * are thrown with the line number and column of the problem.
+ * <p>
*
- * If there are any syntax errors encountered while parsing,
- * RuntimeExceptions are thrown with the line number and column of the
- * problem. <p>
+ * Currenty, HashMaps and ArrayLists are the actual Map and List classes used
+ * when creating the property list.
+ * <p>
*
- * Currenty, HashMaps and ArrayLists are the actual Map and List classes
- * used when creating the property list. <p>
+ * Examples:
+ * <p>
+ * <blockquote>
*
- * Examples: <p><blockquote>
- <pre>
+ * <pre>
// This plist file represents a Map, since it starts with a '{'.
{
Map1 = { subkey1 = "foo"; };
@@ -104,443 +114,425 @@ import java.io.*;
}
);
}
- </pre>
- </blockquote>
- * For those wondering, this is essentially a re-implementation of
+ * </pre>
+ *
+ * </blockquote> For those wondering, this is essentially a re-implementation of
* NeXT/Apple's property lists, except that data values are not supported.
*
* @author clindberg@blacksmith.com
* @version $Revision: 899 $
*/
-public class PropertyListParser
-{
- private char buffer[];
- private int currIndex;
- private int lineNumber;
- private int currLineStartIndex;
-
- /** Reads an object (String, List, or Map) from plistString and returns it.
- * RuntimeExceptions are raised if there are parse problems.
- */
- public static Object propertyListFromString(String plistString)
- {
- PropertyListParser parser = new PropertyListParser(plistString);
- return parser.readTopLevelObject();
- }
-
- /**
- * Reads all remaining characters from the Reader, and returns the
- * result of propertyListFromString(). RuntimeExceptions are raised if
- * there are parse problems
- */
- public static Object propertyListFromReader(Reader reader) throws IOException
- {
- char charBuffer[] = new char[2048];
- StringBuffer stringBuffer = new StringBuffer();
- int numRead = 0;
-
- while (numRead >= 0)
- {
- numRead = reader.read(charBuffer);
- if (numRead > 0) stringBuffer.append(charBuffer, 0, numRead);
- }
-
- return propertyListFromString(stringBuffer.toString());
- }
-
- /**
- * Reads the contents of the specified file, and parses the contents.
- * If any error occurs, prints out a message using System.out.println()
- * and returns null.
- */
- public static Object propertyListFromFile(String filename)
- {
- try {
- FileInputStream stream = new FileInputStream(filename);
- return propertyListFromReader(new InputStreamReader(stream));
- } catch (Exception exception) {
- String errorMessage = exception.getMessage();
- System.out.println("Error parsing property list from "+filename+": "+errorMessage);
- }
-
- return null;
- }
-
- /**
- * Creates a new PropertyListParser to parse the contents of the
- * specified String.
- */
- public PropertyListParser(String plistString)
- {
- this(plistString.toCharArray());
- }
-
- /**
- * Creates a new PropertyListParser to parse the specified char array.
- */
- public PropertyListParser(char[] charArray)
- {
- buffer = charArray;
- lineNumber = 1;
- currLineStartIndex = 1;
- currIndex = 0;
- }
-
- public Object readTopLevelObject()
- {
- Object plist = readObject();
-
- skipCommentWhitespace();
- if (!isAtEnd())
- {
- throwParseException("Extra characters in plist string after parsing object. A plist should only contain one top-level object.");
- }
-
- return plist;
- }
-
- private void throwParseException(String errorMessage)
- {
- int column = currIndex - currLineStartIndex + 1;
- throw new RuntimeException(errorMessage + " (Line " + lineNumber + ", column " + column + ")");
- }
-
- private void updateLineNumberWithIndex(int lineStartIndex)
- {
- lineNumber++;
- currLineStartIndex = lineStartIndex;
- }
-
- private boolean isAtEnd()
- {
- return currIndex >= buffer.length;
- }
-
- private void skipDoubleslashComment()
- {
- while (!isAtEnd() && buffer[currIndex] != '\n') {
- currIndex++;
- }
- }
-
- private void skipStandardCComment()
- {
- currIndex++; //skip over the starting '/'
-
- while (!isAtEnd())
- {
- if (buffer[currIndex] == '\n')
- updateLineNumberWithIndex(currIndex+1);
-
- currIndex++;
-
- if (buffer[currIndex-2] == '*' && buffer[currIndex-1] == '/')
- {
- return;
- }
- }
-
- throwParseException("Input exhausted while parsing comment");
- }
-
- private void skipWhitespace()
- {
- while (!isAtEnd() && isWhitespace(buffer[currIndex]))
- {
- if (buffer[currIndex] == '\n')
- updateLineNumberWithIndex(currIndex+1);
- currIndex++;
- }
- }
-
- private void skipCommentWhitespace()
- {
- boolean done = false;
-
- while (!done)
- {
- done = true;
-
- skipWhitespace();
- if ((buffer.length - currIndex) > 1 && buffer[currIndex] == '/')
- {
- if (buffer[currIndex+1] == '/') {
- done = false; //iterate again
- skipDoubleslashComment();
- }
- else if (buffer[currIndex+1] == '*') {
- done = false; //iterate again
- skipStandardCComment();
- }
- }
- }
- }
-
- private Object readObject()
- {
- skipCommentWhitespace();
- if (isAtEnd()) return null;
-
- // Data (i.e. byte[]) not supported
- if (buffer[currIndex] == '"')
- return readQuotedString();
- if (buffer[currIndex] == '(')
- return readList();
- if (buffer[currIndex] == '{')
- return readMap();
-
- return readUnquotedString();
- }
-
- private static final byte valueForHexDigit(char c)
- {
- if(c >= '0' && c <= '9') return (byte)(c - '0');
- if(c >= 'a' && c <= 'f') return (byte)((c - 'a') + 10);
- if(c >= 'A' && c <= 'F') return (byte)((c - 'A') + 10);
-
- return 0;
- }
-
- private static final boolean isOctalDigit(char c)
- {
- return c >= '0' && c <= '7';
- }
-
- private static final boolean isHexDigit(char c)
- {
- return (c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'f') ||
- (c >= 'A' && c <= 'F');
- }
-
- private static String unquotedStringChars = "._$:/"; // chars allowed in unquoted strings
- private static String whitespaceChars = " \t\n\r\f";
-
- private static final boolean isWhitespace(char c)
- {
- return whitespaceChars.indexOf(c) >= 0;
- }
-
- private static final boolean isValidUnquotedStringChar(char c)
- {
- return ((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9') ||
- unquotedStringChars.indexOf(c) >= 0);
- }
-
- private String readUnquotedString()
- {
- int startIndex = currIndex;
-
- while (!isAtEnd() && isValidUnquotedStringChar(buffer[currIndex]))
- currIndex++;
-
- if (startIndex == currIndex)
- throwParseException("No allowable characters found to parse unquoted string");
-
- return new String(buffer, startIndex, currIndex - startIndex);
- }
-
- private String readQuotedString()
- {
- currIndex++; //skip over '"'
-
- StringBuffer stringBuffer = new StringBuffer();
- int startIndex = currIndex;
-
- while (!isAtEnd() && buffer[currIndex] != '"')
- {
- if (buffer[currIndex] != '\\')
- {
- if (buffer[currIndex] == '\n')
- updateLineNumberWithIndex(currIndex+1);
-
- /*
- * Just increment the index -- all these characters will be
- * appended in chunks, either before an escape sequence or
- * at the end.
- */
- currIndex++;
- }
- else // it's an escape
- {
- /* Append anything scanned past before the '\\' */
- if (startIndex < currIndex)
- stringBuffer.append(buffer, startIndex, currIndex - startIndex);
- currIndex++; // skip over '\\'
-
- if (isAtEnd())
- throwParseException("Input exhausted while parsing escape sequence");
-
- switch (buffer[currIndex])
- {
- case 't': stringBuffer.append('\t'); currIndex++; break; // tab
- case 'n': stringBuffer.append('\n'); currIndex++; break; // newline
- case 'r': stringBuffer.append('\r'); currIndex++; break; // carriage return
- case 'f': stringBuffer.append('\f'); currIndex++; break; // form feed
- case 'b': stringBuffer.append('\b'); currIndex++; break; // backspace
- case 'a': stringBuffer.append('\007'); currIndex++; break; // bell
- case 'v': stringBuffer.append('\013'); currIndex++; break; // vertical tab
- case 'U':
- case 'u':
- {
- /* A Unicode escape. Always followed by 4 hex digits. */
- currIndex++; // skip past the 'U'
- if ((currIndex+4) > buffer.length)
- throwParseException("Not enough chars to parse \\U sequence");
-
- if(!isHexDigit(buffer[currIndex]) || !isHexDigit(buffer[currIndex+1]) ||
- !isHexDigit(buffer[currIndex+2]) || !isHexDigit(buffer[currIndex+3]))
- {
- throwParseException("Four hex digits not found for \\U sequence");
- }
-
- byte byte3 = valueForHexDigit(buffer[currIndex]);
- byte byte2 = valueForHexDigit(buffer[currIndex+1]);
- byte byte1 = valueForHexDigit(buffer[currIndex+2]);
- byte byte0 = valueForHexDigit(buffer[currIndex+3]);
- char theChar = (char)((byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0);
- stringBuffer.append(theChar);
- currIndex += 4;
- break;
- }
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- {
- /* An octal escape. Expect 1, 2, or 3 octal digits. */
- int digits = 0;
- int value = 0;
-
- do {
- value *= 8;
- value += (int)(buffer[currIndex] - '0');
- currIndex++;
- digits++;
- } while (digits <= 3 && !isAtEnd() && isOctalDigit(buffer[currIndex]));
-
- if (value > 255)
- throwParseException("Value too large in octal escape sequence (> 0377)");
-
- // This assumes value is in ISO Latin 1 encoding
- stringBuffer.append((char)value);
- break;
- }
- /* I guess plists can't have the \x{HEX}{HEX} escapes */
- default:
- {
- // Unknown escape sequence, just add the character.
- // GCC warns if this isn't a '"', '\'', or '\\'...
- stringBuffer.append(buffer[currIndex]);
- if (buffer[currIndex] == '\n')
- updateLineNumberWithIndex(currIndex+1);
- currIndex++;
- break;
- }
- } // end case
-
- /* Reset startIndex, so a verbatim copy will now start from this index */
- startIndex = currIndex;
-
- } //end '\\' escape
- }
-
- if (isAtEnd())
- throwParseException("Input exhausted while parsing quoted string");
- if (startIndex < currIndex)
- stringBuffer.append(buffer, startIndex, currIndex - startIndex);
- currIndex++; //skip past '"'
-
- return stringBuffer.toString();
- }
-
- private List readList()
- {
- List newList = new ArrayList();
-
- currIndex++; //skip over '('
- skipCommentWhitespace();
- while (!isAtEnd() && buffer[currIndex] != ')')
- {
- /* A comma is required between list elements */
- if (newList.size() > 0)
- {
- if (buffer[currIndex] != ',')
- throwParseException("List parsing failed: expecting ','");
- currIndex++;
- skipCommentWhitespace();
- if (isAtEnd())
- throwParseException("Input exhausted while parsing list");
- }
-
- if (buffer[currIndex] != ')')
- {
- Object plistObject = readObject();
- if (plistObject == null)
- throwParseException("List parsing failed: could not read contained object.");
- newList.add(plistObject);
- skipCommentWhitespace();
- }
- }
-
- if (isAtEnd())
- throwParseException("Input exhausted while parsing list");
- currIndex++; //skip past ')'
-
- return newList;
- }
-
- private Map readMap()
- {
- HashMap newMap = new HashMap();
-
- currIndex++; // skip over open brace
- skipCommentWhitespace();
-
- while (!isAtEnd() && buffer[currIndex] != '}')
- {
- Object key;
- Object value;
-
- key = readObject();
- if (key == null || !(key instanceof String))
- throwParseException("Map parsing failed: could not parse key or key is not a String");
-
- skipCommentWhitespace();
- if (isAtEnd() || buffer[currIndex] != '=')
- throwParseException("Map parsing failed: expecting '='");
- currIndex++; //skip over '='
- skipCommentWhitespace();
- if (isAtEnd())
- throwParseException("Input exhausted while parsing map");
-
- value = readObject();
- if (value == null)
- throwParseException("Map parsing failed: could not parse value object");
-
- skipCommentWhitespace();
- if (isAtEnd() || buffer[currIndex] != ';')
- throwParseException("Map parsing failed: expecting ';'");
- currIndex++; //skip over ';'
- skipCommentWhitespace();
-
- newMap.put(key, value);
- }
-
- if (isAtEnd())
- throwParseException("Input exhausted while parsing map");
- currIndex++; //skip past '}'
-
- return newMap;
- }
-
-
- public static void main(String[] args)
- {
- String filename = args[0];
- Object plist = PropertyListParser.propertyListFromFile(filename);
- System.out.println(plist);
- }
+public class PropertyListParser {
+ private char buffer[];
+ private int currIndex;
+ private int lineNumber;
+ private int currLineStartIndex;
+
+ /**
+ * Reads an object (String, List, or Map) from plistString and returns it.
+ * RuntimeExceptions are raised if there are parse problems.
+ */
+ public static Object propertyListFromString(String plistString) {
+ PropertyListParser parser = new PropertyListParser(plistString);
+ return parser.readTopLevelObject();
+ }
+
+ /**
+ * Reads all remaining characters from the Reader, and returns the result of
+ * propertyListFromString(). RuntimeExceptions are raised if there are parse
+ * problems
+ */
+ public static Object propertyListFromReader(Reader reader) throws IOException {
+ char charBuffer[] = new char[2048];
+ StringBuffer stringBuffer = new StringBuffer();
+ int numRead = 0;
+
+ while (numRead >= 0) {
+ numRead = reader.read(charBuffer);
+ if (numRead > 0)
+ stringBuffer.append(charBuffer, 0, numRead);
+ }
+
+ return propertyListFromString(stringBuffer.toString());
+ }
+
+ /**
+ * Reads the contents of the specified file, and parses the contents. If any
+ * error occurs, prints out a message using System.out.println() and returns
+ * null.
+ */
+ public static Object propertyListFromFile(String filename) {
+ try {
+ FileInputStream stream = new FileInputStream(filename);
+ return propertyListFromReader(new InputStreamReader(stream));
+ } catch (Exception exception) {
+ String errorMessage = exception.getMessage();
+ System.out.println("Error parsing property list from " + filename + ": " + errorMessage);
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a new PropertyListParser to parse the contents of the specified
+ * String.
+ */
+ public PropertyListParser(String plistString) {
+ this(plistString.toCharArray());
+ }
+
+ /**
+ * Creates a new PropertyListParser to parse the specified char array.
+ */
+ public PropertyListParser(char[] charArray) {
+ buffer = charArray;
+ lineNumber = 1;
+ currLineStartIndex = 1;
+ currIndex = 0;
+ }
+
+ public Object readTopLevelObject() {
+ Object plist = readObject();
+
+ skipCommentWhitespace();
+ if (!isAtEnd()) {
+ throwParseException(
+ "Extra characters in plist string after parsing object. A plist should only contain one top-level object.");
+ }
+
+ return plist;
+ }
+
+ private void throwParseException(String errorMessage) {
+ int column = currIndex - currLineStartIndex + 1;
+ throw new RuntimeException(errorMessage + " (Line " + lineNumber + ", column " + column + ")");
+ }
+
+ private void updateLineNumberWithIndex(int lineStartIndex) {
+ lineNumber++;
+ currLineStartIndex = lineStartIndex;
+ }
+
+ private boolean isAtEnd() {
+ return currIndex >= buffer.length;
+ }
+
+ private void skipDoubleslashComment() {
+ while (!isAtEnd() && buffer[currIndex] != '\n') {
+ currIndex++;
+ }
+ }
+
+ private void skipStandardCComment() {
+ currIndex++; // skip over the starting '/'
+
+ while (!isAtEnd()) {
+ if (buffer[currIndex] == '\n')
+ updateLineNumberWithIndex(currIndex + 1);
+
+ currIndex++;
+
+ if (buffer[currIndex - 2] == '*' && buffer[currIndex - 1] == '/') {
+ return;
+ }
+ }
+
+ throwParseException("Input exhausted while parsing comment");
+ }
+
+ private void skipWhitespace() {
+ while (!isAtEnd() && isWhitespace(buffer[currIndex])) {
+ if (buffer[currIndex] == '\n')
+ updateLineNumberWithIndex(currIndex + 1);
+ currIndex++;
+ }
+ }
+
+ private void skipCommentWhitespace() {
+ boolean done = false;
+
+ while (!done) {
+ done = true;
+
+ skipWhitespace();
+ if ((buffer.length - currIndex) > 1 && buffer[currIndex] == '/') {
+ if (buffer[currIndex + 1] == '/') {
+ done = false; // iterate again
+ skipDoubleslashComment();
+ } else if (buffer[currIndex + 1] == '*') {
+ done = false; // iterate again
+ skipStandardCComment();
+ }
+ }
+ }
+ }
+
+ private Object readObject() {
+ skipCommentWhitespace();
+ if (isAtEnd())
+ return null;
+
+ // Data (i.e. byte[]) not supported
+ if (buffer[currIndex] == '"')
+ return readQuotedString();
+ if (buffer[currIndex] == '(')
+ return readList();
+ if (buffer[currIndex] == '{')
+ return readMap();
+
+ return readUnquotedString();
+ }
+
+ private static final byte valueForHexDigit(char c) {
+ if (c >= '0' && c <= '9')
+ return (byte) (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (byte) ((c - 'a') + 10);
+ if (c >= 'A' && c <= 'F')
+ return (byte) ((c - 'A') + 10);
+
+ return 0;
+ }
+
+ private static final boolean isOctalDigit(char c) {
+ return c >= '0' && c <= '7';
+ }
+
+ private static final boolean isHexDigit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+ }
+
+ private static String unquotedStringChars = "._$:/"; // chars allowed in unquoted strings
+ private static String whitespaceChars = " \t\n\r\f";
+
+ private static final boolean isWhitespace(char c) {
+ return whitespaceChars.indexOf(c) >= 0;
+ }
+
+ private static final boolean isValidUnquotedStringChar(char c) {
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
+ || unquotedStringChars.indexOf(c) >= 0);
+ }
+
+ private String readUnquotedString() {
+ int startIndex = currIndex;
+
+ while (!isAtEnd() && isValidUnquotedStringChar(buffer[currIndex]))
+ currIndex++;
+
+ if (startIndex == currIndex)
+ throwParseException("No allowable characters found to parse unquoted string");
+
+ return new String(buffer, startIndex, currIndex - startIndex);
+ }
+
+ private String readQuotedString() {
+ currIndex++; // skip over '"'
+
+ StringBuffer stringBuffer = new StringBuffer();
+ int startIndex = currIndex;
+
+ while (!isAtEnd() && buffer[currIndex] != '"') {
+ if (buffer[currIndex] != '\\') {
+ if (buffer[currIndex] == '\n')
+ updateLineNumberWithIndex(currIndex + 1);
+
+ /*
+ * Just increment the index -- all these characters will be appended in chunks,
+ * either before an escape sequence or at the end.
+ */
+ currIndex++;
+ } else // it's an escape
+ {
+ /* Append anything scanned past before the '\\' */
+ if (startIndex < currIndex)
+ stringBuffer.append(buffer, startIndex, currIndex - startIndex);
+ currIndex++; // skip over '\\'
+
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing escape sequence");
+
+ switch (buffer[currIndex]) {
+ case 't':
+ stringBuffer.append('\t');
+ currIndex++;
+ break; // tab
+ case 'n':
+ stringBuffer.append('\n');
+ currIndex++;
+ break; // newline
+ case 'r':
+ stringBuffer.append('\r');
+ currIndex++;
+ break; // carriage return
+ case 'f':
+ stringBuffer.append('\f');
+ currIndex++;
+ break; // form feed
+ case 'b':
+ stringBuffer.append('\b');
+ currIndex++;
+ break; // backspace
+ case 'a':
+ stringBuffer.append('\007');
+ currIndex++;
+ break; // bell
+ case 'v':
+ stringBuffer.append('\013');
+ currIndex++;
+ break; // vertical tab
+ case 'U':
+ case 'u': {
+ /* A Unicode escape. Always followed by 4 hex digits. */
+ currIndex++; // skip past the 'U'
+ if ((currIndex + 4) > buffer.length)
+ throwParseException("Not enough chars to parse \\U sequence");
+
+ if (!isHexDigit(buffer[currIndex]) || !isHexDigit(buffer[currIndex + 1])
+ || !isHexDigit(buffer[currIndex + 2]) || !isHexDigit(buffer[currIndex + 3])) {
+ throwParseException("Four hex digits not found for \\U sequence");
+ }
+
+ byte byte3 = valueForHexDigit(buffer[currIndex]);
+ byte byte2 = valueForHexDigit(buffer[currIndex + 1]);
+ byte byte1 = valueForHexDigit(buffer[currIndex + 2]);
+ byte byte0 = valueForHexDigit(buffer[currIndex + 3]);
+ char theChar = (char) ((byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0);
+ stringBuffer.append(theChar);
+ currIndex += 4;
+ break;
+ }
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': {
+ /* An octal escape. Expect 1, 2, or 3 octal digits. */
+ int digits = 0;
+ int value = 0;
+
+ do {
+ value *= 8;
+ value += (int) (buffer[currIndex] - '0');
+ currIndex++;
+ digits++;
+ } while (digits <= 3 && !isAtEnd() && isOctalDigit(buffer[currIndex]));
+
+ if (value > 255)
+ throwParseException("Value too large in octal escape sequence (> 0377)");
+
+ // This assumes value is in ISO Latin 1 encoding
+ stringBuffer.append((char) value);
+ break;
+ }
+ /* I guess plists can't have the \x{HEX}{HEX} escapes */
+ default: {
+ // Unknown escape sequence, just add the character.
+ // GCC warns if this isn't a '"', '\'', or '\\'...
+ stringBuffer.append(buffer[currIndex]);
+ if (buffer[currIndex] == '\n')
+ updateLineNumberWithIndex(currIndex + 1);
+ currIndex++;
+ break;
+ }
+ } // end case
+
+ /* Reset startIndex, so a verbatim copy will now start from this index */
+ startIndex = currIndex;
+
+ } // end '\\' escape
+ }
+
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing quoted string");
+ if (startIndex < currIndex)
+ stringBuffer.append(buffer, startIndex, currIndex - startIndex);
+ currIndex++; // skip past '"'
+
+ return stringBuffer.toString();
+ }
+
+ private List readList() {
+ List newList = new ArrayList();
+
+ currIndex++; // skip over '('
+ skipCommentWhitespace();
+ while (!isAtEnd() && buffer[currIndex] != ')') {
+ /* A comma is required between list elements */
+ if (newList.size() > 0) {
+ if (buffer[currIndex] != ',')
+ throwParseException("List parsing failed: expecting ','");
+ currIndex++;
+ skipCommentWhitespace();
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing list");
+ }
+
+ if (buffer[currIndex] != ')') {
+ Object plistObject = readObject();
+ if (plistObject == null)
+ throwParseException("List parsing failed: could not read contained object.");
+ newList.add(plistObject);
+ skipCommentWhitespace();
+ }
+ }
+
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing list");
+ currIndex++; // skip past ')'
+
+ return newList;
+ }
+
+ private Map readMap() {
+ HashMap newMap = new HashMap();
+
+ currIndex++; // skip over open brace
+ skipCommentWhitespace();
+
+ while (!isAtEnd() && buffer[currIndex] != '}') {
+ Object key;
+ Object value;
+
+ key = readObject();
+ if (key == null || !(key instanceof String))
+ throwParseException("Map parsing failed: could not parse key or key is not a String");
+
+ skipCommentWhitespace();
+ if (isAtEnd() || buffer[currIndex] != '=')
+ throwParseException("Map parsing failed: expecting '='");
+ currIndex++; // skip over '='
+ skipCommentWhitespace();
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing map");
+
+ value = readObject();
+ if (value == null)
+ throwParseException("Map parsing failed: could not parse value object");
+
+ skipCommentWhitespace();
+ if (isAtEnd() || buffer[currIndex] != ';')
+ throwParseException("Map parsing failed: expecting ';'");
+ currIndex++; // skip over ';'
+ skipCommentWhitespace();
+
+ newMap.put(key, value);
+ }
+
+ if (isAtEnd())
+ throwParseException("Input exhausted while parsing map");
+ currIndex++; // skip past '}'
+
+ return newMap;
+ }
+
+ public static void main(String[] args) {
+ String filename = args[0];
+ Object plist = PropertyListParser.propertyListFromFile(filename);
+ System.out.println(plist);
+ }
}
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java
index 6d35b7b..59104e5 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java
@@ -21,518 +21,488 @@ package net.wotonomy.foundation.internal;
import java.util.*; //collections
/**
-* A queue based implementation of the Map interface. This class provides for
-* all the opertions of a map, but keeps the entries in the same sequence as
-* originally added. The first entry placed in the map will be the first
-* entry retreived during iteration: first-in, first-out (FIFO). <BR><BR>
-*
-* Keys cannot be duplicated. If an entry is made using a key that already
-* exists, the value for that key will be replaced with that new value. There
-* are no such restrictions on the values. The values may be null. <BR><BR>
-*
-* Some convenience methods are provided for the queue type operations. The
-* first key can be retreived as well as the last key. A key can be used
-* to retreive its corresponding value from the map. A value can also be used
-* to retreive its key from the map, however, since there may be multiple values
-* of the same equality, the first key found will be returned. <BR><BR>
-*
-* @author rglista@blacksmith.com
-* @author mpowers@blacksmith.com
-* @date $Date: 2006-02-18 17:41:36 -0500 (Sat, 18 Feb 2006) $
-* @revision $Revision: 899 $
-*/
-public class QueueMap implements Map
-{
- List values;
- List keys;
- Map keyToValue;
-
-/**
-* Creates an empty QueueMap.
-*/
- public QueueMap()
- {
- values = new LinkedList();
- keys = new LinkedList();
- keyToValue = new HashMap();
- }
-
-/**
-* Creates a QueueMap and places the entries from the passed in map into this map.
-* The order of the entries is based on however the iterator iteratated through
-* the map entries.
-* @param t A map object.
-*/
- public QueueMap( Map t )
- {
- values = new ArrayList();
- keys = new ArrayList();
- keyToValue = new HashMap();
-
- putAll( t );
- }
-
-/**
-* Removes all the entries from this map.
-*/
- public void clear()
- {
- values.clear();
- keys.clear();
- keyToValue.clear();
- }
-
-/**
-* Tests to see if the key is contained in the map. If the key is present in
-* the map, then TRUE is returned, otherwise FALSE is returned. The equals()
-* operation is used to determine equality.
-* @return True if the map contains the given key, false otherwise.
-*/
- public boolean containsKey( Object key )
- {
- return keyToValue.containsKey( key );
- }
-
-/**
-* Tests to see if the value is contained in the map. If the value is present in
-* the map, then TRUE is returned, otherwise FALSE is returned. The equals()
-* operation is used to determine equality. The value can be null and will
-* return TRUE if null is a value in the map. If TRUE is returned, then there
-* may be more than one values in the map.
-* @return True if the map contains the given value, false otherwise.
-*/
- public boolean containsValue( Object value )
- {
- return keyToValue.containsValue( value );
- }
-
-/**
-* Returns a set view of the mappings contained in this map. Each element
-* in the returned set is a <tt>Map.Entry</tt>. The returned set is NOT backed
-* by the map, so changes to the map are NOT reflected in the set, and vice-versa.
-* The returned set is independent of this Map and its underlying structure.
-*
-* @return a set view of the mappings contained in this map.
-*/
- public Set entrySet()
- {
- Set result = new HashSet(keys.size(), 1F);
-
- for ( int i = 0; i < keys.size(); i++ )
- {
- result.add( new KeyValuePair( keys.get(i), values.get(i) ) );
- }
-
- return result;
- }
-
-/**
-* Compares the specified object with this map for equality. Returns
-* <tt>true</tt> if the given object is also a map and the two Maps
-* represent the same mappings. More formally, two maps <tt>t1</tt> and
-* <tt>t2</tt> represent the same mappings if
-* <tt>t1.entrySet().equals(t2.entrySet())</tt>. This ensures that the
-* <tt>equals</tt> method works properly across different implementations
-* of the <tt>Map</tt> interface.
-*
-* @param o object to be compared for equality with this map.
-* @return <tt>true</tt> if the specified object is equal to this map.
-*/
- public boolean equals( Object o )
- {
- return keyToValue.equals( o );
- }
-
-/**
-* Returns the corresponding value for the given key. The returned value may be
-* null as that is a legal value in this map. However, if the key is not
-* contained in this map then null is also returned. Use the containsKey()
-* method to distinguish between the two cases.
-* @param key A key into the map.
-* @return The value corresponding to the key (can be null), or null if the key
-* is not contained in the map.
-*/
- public Object get( Object key )
- {
- return keyToValue.get( key );
- }
-
-/**
-* Returns the hash code value for this map. The hash code of a map
-* is defined to be the sum of the hashCodes of each entry in the map's
-* entrySet view. This ensures that <tt>t1.equals(t2)</tt> implies
-* that <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps
-* <tt>t1</tt> and <tt>t2</tt>, as required by the general
-* contract of Object.hashCode.
-*
-* @return the hash code value for this map.
-*/
- public int hashCode()
- {
- return keyToValue.hashCode();
- }
-
-/**
-* Returns true is this map contains no key-value mappings.
-* @return True is this map contains no entries, false otherwise.
-*/
- public boolean isEmpty()
- {
- return keyToValue.isEmpty();
- }
-
-/**
-* Returns the keys used in the map. There is no order implied in the returned
-* set and may be different than the the order in which they were inserted.
-* @return A Set containing all the keys used in the map.
-*/
- public Set keySet()
- {
- Set result = new HashSet(keys.size(), 1F);
-
- for ( int i = 0; i < keys.size(); i++ )
- {
- result.add( keys.get(i) );
- }
-
- return result;
- }
-
-/**
-* Places the key/value entry into the map at the end position. If the key
-* already exists in the map, then its value is replaced by the new given
-* value. The mapping does not change order in this case. The specified
-* key cannot be null.
-* @param key The key to place into the map, cannot be null.
-* @param value The value to associate with the key, may be null.
-* @return Null if the key is new, the replaced value if the key already
-* existed. (Note: If the key was null, then null is returned.)
-*/
- public Object put( Object key, Object value )
- {
- if ( key == null ) return null;
-
- if ( keys.contains( key ) )
- {
- values.remove( keys.indexOf( key ) );
- values.add( keys.indexOf( key ), value );
- }
- else
- {
- values.add( value );
- keys.add( key );
- }
-
- return keyToValue.put( key, value );
- }
-
-/**
-* Places all the entries from this given map into this map. If the keys
-* already exist, then there values are replaced.
-* @param t A map of key/value entries.
-*/
- public void putAll( Map t )
- {
- if ( t == null )
- {
- // Nothing to do!
- return;
- }
-
- // Place the entries from the passed in map into this map.
- for ( Iterator it = t.keySet().iterator(); it.hasNext(); )
- {
- Object aKey = it.next();
- put( aKey, t.get( aKey ) );
- }
- }
-
-/**
-* Remove the mapping of the key and associated value from this map.
-* Note: null is a valid value in the map.
-* @param key A key to remove from the map, cannot be null.
-* @return The value of the removed mapping, null if the mapping did not exist.
-* Null could also be returned if the associated value of the key was null.
-*/
- public Object remove( Object key )
- {
- if ( key == null ) return null;
-
- Object value = null;
-
- if ( containsKey( key ) )
- {
- value = keyToValue.remove( key );
- int i = values.indexOf( value );
- if ( i != -1 )
- {
- keys.remove( i );
- values.remove( i );
- }
- }
-
- return value;
- }
-
-/**
-* Returns the number of key/value pairs in this map.
-* @return The number of pairs.
-*/
- public int size()
- {
- return values.size();
- }
-
-/**
-* Returns an ordered list of keys from the map. The order is the same
-* as the added order of the mapped items.<br>
-* NOTE: The returned list is the underlying keys list used by this class.
-* If modification are to be made to this list, it should be cloned first.
-* @return An ordered list of keys.
-*/
- public List keys()
- {
- return keys;
- }
-
-/**
-* Returns an ordered list of values from the map. The order is the same
-* as the added order of the mapped items.
-* NOTE: The returned list is the underlying keys list used by this class.
-* If modification are to be made to this list, it should be cloned first.
-* @return An ordered list of values.
-*/
- public Collection values()
- {
- return values;
- }
-
-/**
-* Returns the corresponding value for the given key. The returned value may be
-* null as that is a legal value in this map. However, if the key is not
-* contained in this map then null is also returned. Use the containsKey()
-* method to distinguish between the two cases.
-* @param key A key into the map.
-* @return The value corresponding to the key (can be null), or null if the key
-* is not contained in the map.
-*/
- public Object getValueForKey( Object key )
- {
- return keyToValue.get( key );
- }
-
-/**
-* Returns the associated key for this value. Since there may be more than one
-* of the same value in the map, this returns the first key associated with this
-* value. Null is returned if the value is not in the map.
-* @param value A value that is contained in this map.
-* @return A first key that corresponds to this value.
-*/
- public Object getKeyForValue( Object value )
- {
- int i = values.indexOf( value );
- if ( i != -1 )
- {
- return keys.get( i );
- }
- return null;
- }
-
-/**
-* Returns the first key in the map. If the map is empty, then null is
-* returned.
-* @return The first key in the map, null if there are no mappings.
-*/
- public Object getFirstKey()
- {
- if ( keys.size() < 1 )
- {
- return null;
- }
- return keys.get(0);
- }
-
-/**
-* Returns the last key in the map. If the map is empty, then null is
-* returned.
-* @return The last key in the map, null if there are no mappings.
-*/
- public Object getLastKey()
- {
- if ( keys.size() < 1 )
- {
- return null;
- }
- return keys.get( keys.size() -1 );
- }
-
-/**
-* This class contains a key/value pair. The key must be a valid object,
-* it cannot be null. The value can be a valid object or null.
-*/
- static public class KeyValuePair implements Map.Entry
- {
- Object key;
- Object value;
-
- /**
- * Default constructor. The constructor takes the key and value as parameters.
- * Since the key cannot be null, it must be specified during initialization.
- * The value can be null.
- * @param key The key object of this pair. The key cannot be null.
- * @param value The value object of this pair. The value can be null.
- */
- public KeyValuePair( Object aKey, Object aValue )
- {
- key = aKey;
- value = aValue;
- }
-
- /**
- * Returns the key object of this pair.
- * @return The key object.
- */
- public Object getKey()
- {
- return key;
- }
-
- /**
- * Returns the the value object of this pair. May be null.
- * @return The value object.
- */
- public Object getValue()
- {
- return value;
- }
-
- /**
- * Sets the value object of this pair. May be an object or null.
- * @param aValue The value object to place into this pair.
- */
- public Object setValue( Object aValue )
- {
- Object result = value;
- value = aValue;
- return result;
- }
-
- public boolean equals( Object o )
- {
- if ( o instanceof KeyValuePair )
- {
- KeyValuePair p = (KeyValuePair) o;
- if ( ( key.equals( p.getKey() ) ) && ( value.equals( p.getValue() ) ) )
- {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Returns a string reprsentation of this class. The contents of the
- * map are placed in the string in its proper order.
- */
- public String toString()
- {
- int max = size() - 1;
- StringBuffer buf = new StringBuffer();
-
- buf.append("{");
- for (int j = 0; j <= max; j++)
- {
- buf.append(keys.get(j) + "=" + values.get(j));
- if (j < max)
- {
- buf.append(", ");
- }
- }
- buf.append("}");
-
- return buf.toString();
- }
-
- // unit test
- public static void main( String[] argv )
- {
- QueueMap qMap;
-
- qMap = new QueueMap();
- for (int i = 0; i < 5; i++)
- {
- qMap.put(Integer.toString(i), Integer.toString(i));
- }
- System.out.println("\nMap = " + qMap);
- System.out.println("Keys = " + qMap.keys());
- System.out.println("Values = " + qMap.values());
-
- qMap = new QueueMap();
- for (int i = 0; i < 5; i++)
- {
- qMap.put(Integer.toString(i), "A");
- }
- System.out.println("\nMap = " + qMap);
- System.out.println("Keys = " + qMap.keys());
- System.out.println("Values = " + qMap.values());
-
- qMap = new QueueMap();
- for (int i = 0; i < 5; i++)
- {
- qMap.put(Integer.toString(i), null);
- }
- System.out.println("\nMap = " + qMap);
- System.out.println("Keys = " + qMap.keys());
- System.out.println("Values = " + qMap.values());
-
- Map aMap = new HashMap();
- for (int i = 0; i < 5; i++)
- {
- aMap.put(Integer.toString(i), Integer.toString(i));
- }
- qMap = new QueueMap( aMap );
- System.out.println("\nHashMap = " + aMap);
- System.out.println("Map = " + qMap);
- System.out.println("Keys = " + qMap.keys());
- System.out.println("Values = " + qMap.values());
-
- qMap = new QueueMap();
- qMap.put( "Test1", "String1" );
- qMap.put( "Test2", "String2" );
- qMap.put( "Test3", "String3" );
- qMap.put( "Test4", "String4" );
- qMap.put( "Test5", "String5" );
- System.out.println("\nStandard Test, Map = " + qMap);
- qMap.put( "Test6", "String6" );
- qMap.put( "Test7", "String7" );
- System.out.println("Put New Test, Map = " + qMap);
- qMap.put( "Test2", "New String2" );
- qMap.put( "Test6", "New String6" );
- System.out.println("Put Existing Test, Map = " + qMap);
- qMap.put( "Test5", null );
- qMap.put( "Test8", null );
- System.out.println("Put Null Test, Map = " + qMap);
- qMap.remove( "Test1" );
- qMap.remove( "Test3" );
- qMap.remove( "Test5" );
- qMap.remove( "Test9" );
- System.out.println("Remove Test, Map = " + qMap);
- System.out.println(" Keys = " + qMap.keys());
- System.out.println(" Values = " + qMap.values());
- qMap.clear();
- qMap.put( "Test10", "String10" );
- qMap.put( "Test11", "String11" );
- qMap.put( "Test12", "String12" );
- System.out.println("Clear Test, Map = " + qMap);
-
- aMap = new HashMap();
- aMap.put( "Test10", "String10" );
- aMap.put( "Test11", "String11" );
- aMap.put( "Test12", "String12" );
- System.out.println("Equality Test, Equal = " + qMap.equals( aMap ));
- }
+ * A queue based implementation of the Map interface. This class provides for
+ * all the opertions of a map, but keeps the entries in the same sequence as
+ * originally added. The first entry placed in the map will be the first entry
+ * retreived during iteration: first-in, first-out (FIFO). <BR>
+ * <BR>
+ *
+ * Keys cannot be duplicated. If an entry is made using a key that already
+ * exists, the value for that key will be replaced with that new value. There
+ * are no such restrictions on the values. The values may be null. <BR>
+ * <BR>
+ *
+ * Some convenience methods are provided for the queue type operations. The
+ * first key can be retreived as well as the last key. A key can be used to
+ * retreive its corresponding value from the map. A value can also be used to
+ * retreive its key from the map, however, since there may be multiple values of
+ * the same equality, the first key found will be returned. <BR>
+ * <BR>
+ *
+ * @author rglista@blacksmith.com
+ * @author mpowers@blacksmith.com
+ * @date $Date: 2006-02-18 17:41:36 -0500 (Sat, 18 Feb 2006) $
+ * @revision $Revision: 899 $
+ */
+public class QueueMap implements Map {
+ List values;
+ List keys;
+ Map keyToValue;
+
+ /**
+ * Creates an empty QueueMap.
+ */
+ public QueueMap() {
+ values = new LinkedList();
+ keys = new LinkedList();
+ keyToValue = new HashMap();
+ }
+
+ /**
+ * Creates a QueueMap and places the entries from the passed in map into this
+ * map. The order of the entries is based on however the iterator iteratated
+ * through the map entries.
+ *
+ * @param t A map object.
+ */
+ public QueueMap(Map t) {
+ values = new ArrayList();
+ keys = new ArrayList();
+ keyToValue = new HashMap();
+
+ putAll(t);
+ }
+
+ /**
+ * Removes all the entries from this map.
+ */
+ public void clear() {
+ values.clear();
+ keys.clear();
+ keyToValue.clear();
+ }
+
+ /**
+ * Tests to see if the key is contained in the map. If the key is present in the
+ * map, then TRUE is returned, otherwise FALSE is returned. The equals()
+ * operation is used to determine equality.
+ *
+ * @return True if the map contains the given key, false otherwise.
+ */
+ public boolean containsKey(Object key) {
+ return keyToValue.containsKey(key);
+ }
+
+ /**
+ * Tests to see if the value is contained in the map. If the value is present in
+ * the map, then TRUE is returned, otherwise FALSE is returned. The equals()
+ * operation is used to determine equality. The value can be null and will
+ * return TRUE if null is a value in the map. If TRUE is returned, then there
+ * may be more than one values in the map.
+ *
+ * @return True if the map contains the given value, false otherwise.
+ */
+ public boolean containsValue(Object value) {
+ return keyToValue.containsValue(value);
+ }
+
+ /**
+ * Returns a set view of the mappings contained in this map. Each element in the
+ * returned set is a <tt>Map.Entry</tt>. The returned set is NOT backed by the
+ * map, so changes to the map are NOT reflected in the set, and vice-versa. The
+ * returned set is independent of this Map and its underlying structure.
+ *
+ * @return a set view of the mappings contained in this map.
+ */
+ public Set entrySet() {
+ Set result = new HashSet(keys.size(), 1F);
+
+ for (int i = 0; i < keys.size(); i++) {
+ result.add(new KeyValuePair(keys.get(i), values.get(i)));
+ }
+
+ return result;
+ }
+
+ /**
+ * Compares the specified object with this map for equality. Returns
+ * <tt>true</tt> if the given object is also a map and the two Maps represent
+ * the same mappings. More formally, two maps <tt>t1</tt> and <tt>t2</tt>
+ * represent the same mappings if <tt>t1.entrySet().equals(t2.entrySet())</tt>.
+ * This ensures that the <tt>equals</tt> method works properly across different
+ * implementations of the <tt>Map</tt> interface.
+ *
+ * @param o object to be compared for equality with this map.
+ * @return <tt>true</tt> if the specified object is equal to this map.
+ */
+ public boolean equals(Object o) {
+ return keyToValue.equals(o);
+ }
+
+ /**
+ * Returns the corresponding value for the given key. The returned value may be
+ * null as that is a legal value in this map. However, if the key is not
+ * contained in this map then null is also returned. Use the containsKey()
+ * method to distinguish between the two cases.
+ *
+ * @param key A key into the map.
+ * @return The value corresponding to the key (can be null), or null if the key
+ * is not contained in the map.
+ */
+ public Object get(Object key) {
+ return keyToValue.get(key);
+ }
+
+ /**
+ * Returns the hash code value for this map. The hash code of a map is defined
+ * to be the sum of the hashCodes of each entry in the map's entrySet view. This
+ * ensures that <tt>t1.equals(t2)</tt> implies that
+ * <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps <tt>t1</tt> and
+ * <tt>t2</tt>, as required by the general contract of Object.hashCode.
+ *
+ * @return the hash code value for this map.
+ */
+ public int hashCode() {
+ return keyToValue.hashCode();
+ }
+
+ /**
+ * Returns true is this map contains no key-value mappings.
+ *
+ * @return True is this map contains no entries, false otherwise.
+ */
+ public boolean isEmpty() {
+ return keyToValue.isEmpty();
+ }
+
+ /**
+ * Returns the keys used in the map. There is no order implied in the returned
+ * set and may be different than the the order in which they were inserted.
+ *
+ * @return A Set containing all the keys used in the map.
+ */
+ public Set keySet() {
+ Set result = new HashSet(keys.size(), 1F);
+
+ for (int i = 0; i < keys.size(); i++) {
+ result.add(keys.get(i));
+ }
+
+ return result;
+ }
+
+ /**
+ * Places the key/value entry into the map at the end position. If the key
+ * already exists in the map, then its value is replaced by the new given value.
+ * The mapping does not change order in this case. The specified key cannot be
+ * null.
+ *
+ * @param key The key to place into the map, cannot be null.
+ * @param value The value to associate with the key, may be null.
+ * @return Null if the key is new, the replaced value if the key already
+ * existed. (Note: If the key was null, then null is returned.)
+ */
+ public Object put(Object key, Object value) {
+ if (key == null)
+ return null;
+
+ if (keys.contains(key)) {
+ values.remove(keys.indexOf(key));
+ values.add(keys.indexOf(key), value);
+ } else {
+ values.add(value);
+ keys.add(key);
+ }
+
+ return keyToValue.put(key, value);
+ }
+
+ /**
+ * Places all the entries from this given map into this map. If the keys already
+ * exist, then there values are replaced.
+ *
+ * @param t A map of key/value entries.
+ */
+ public void putAll(Map t) {
+ if (t == null) {
+ // Nothing to do!
+ return;
+ }
+
+ // Place the entries from the passed in map into this map.
+ for (Iterator it = t.keySet().iterator(); it.hasNext();) {
+ Object aKey = it.next();
+ put(aKey, t.get(aKey));
+ }
+ }
+
+ /**
+ * Remove the mapping of the key and associated value from this map. Note: null
+ * is a valid value in the map.
+ *
+ * @param key A key to remove from the map, cannot be null.
+ * @return The value of the removed mapping, null if the mapping did not exist.
+ * Null could also be returned if the associated value of the key was
+ * null.
+ */
+ public Object remove(Object key) {
+ if (key == null)
+ return null;
+
+ Object value = null;
+
+ if (containsKey(key)) {
+ value = keyToValue.remove(key);
+ int i = values.indexOf(value);
+ if (i != -1) {
+ keys.remove(i);
+ values.remove(i);
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Returns the number of key/value pairs in this map.
+ *
+ * @return The number of pairs.
+ */
+ public int size() {
+ return values.size();
+ }
+
+ /**
+ * Returns an ordered list of keys from the map. The order is the same as the
+ * added order of the mapped items.<br>
+ * NOTE: The returned list is the underlying keys list used by this class. If
+ * modification are to be made to this list, it should be cloned first.
+ *
+ * @return An ordered list of keys.
+ */
+ public List keys() {
+ return keys;
+ }
+
+ /**
+ * Returns an ordered list of values from the map. The order is the same as the
+ * added order of the mapped items. NOTE: The returned list is the underlying
+ * keys list used by this class. If modification are to be made to this list, it
+ * should be cloned first.
+ *
+ * @return An ordered list of values.
+ */
+ public Collection values() {
+ return values;
+ }
+
+ /**
+ * Returns the corresponding value for the given key. The returned value may be
+ * null as that is a legal value in this map. However, if the key is not
+ * contained in this map then null is also returned. Use the containsKey()
+ * method to distinguish between the two cases.
+ *
+ * @param key A key into the map.
+ * @return The value corresponding to the key (can be null), or null if the key
+ * is not contained in the map.
+ */
+ public Object getValueForKey(Object key) {
+ return keyToValue.get(key);
+ }
+
+ /**
+ * Returns the associated key for this value. Since there may be more than one
+ * of the same value in the map, this returns the first key associated with this
+ * value. Null is returned if the value is not in the map.
+ *
+ * @param value A value that is contained in this map.
+ * @return A first key that corresponds to this value.
+ */
+ public Object getKeyForValue(Object value) {
+ int i = values.indexOf(value);
+ if (i != -1) {
+ return keys.get(i);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first key in the map. If the map is empty, then null is returned.
+ *
+ * @return The first key in the map, null if there are no mappings.
+ */
+ public Object getFirstKey() {
+ if (keys.size() < 1) {
+ return null;
+ }
+ return keys.get(0);
+ }
+
+ /**
+ * Returns the last key in the map. If the map is empty, then null is returned.
+ *
+ * @return The last key in the map, null if there are no mappings.
+ */
+ public Object getLastKey() {
+ if (keys.size() < 1) {
+ return null;
+ }
+ return keys.get(keys.size() - 1);
+ }
+
+ /**
+ * This class contains a key/value pair. The key must be a valid object, it
+ * cannot be null. The value can be a valid object or null.
+ */
+ static public class KeyValuePair implements Map.Entry {
+ Object key;
+ Object value;
+
+ /**
+ * Default constructor. The constructor takes the key and value as parameters.
+ * Since the key cannot be null, it must be specified during initialization. The
+ * value can be null.
+ *
+ * @param key The key object of this pair. The key cannot be null.
+ * @param value The value object of this pair. The value can be null.
+ */
+ public KeyValuePair(Object aKey, Object aValue) {
+ key = aKey;
+ value = aValue;
+ }
+
+ /**
+ * Returns the key object of this pair.
+ *
+ * @return The key object.
+ */
+ public Object getKey() {
+ return key;
+ }
+
+ /**
+ * Returns the the value object of this pair. May be null.
+ *
+ * @return The value object.
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value object of this pair. May be an object or null.
+ *
+ * @param aValue The value object to place into this pair.
+ */
+ public Object setValue(Object aValue) {
+ Object result = value;
+ value = aValue;
+ return result;
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof KeyValuePair) {
+ KeyValuePair p = (KeyValuePair) o;
+ if ((key.equals(p.getKey())) && (value.equals(p.getValue()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns a string reprsentation of this class. The contents of the map are
+ * placed in the string in its proper order.
+ */
+ public String toString() {
+ int max = size() - 1;
+ StringBuffer buf = new StringBuffer();
+
+ buf.append("{");
+ for (int j = 0; j <= max; j++) {
+ buf.append(keys.get(j) + "=" + values.get(j));
+ if (j < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+
+ return buf.toString();
+ }
+
+ // unit test
+ public static void main(String[] argv) {
+ QueueMap qMap;
+
+ qMap = new QueueMap();
+ for (int i = 0; i < 5; i++) {
+ qMap.put(Integer.toString(i), Integer.toString(i));
+ }
+ System.out.println("\nMap = " + qMap);
+ System.out.println("Keys = " + qMap.keys());
+ System.out.println("Values = " + qMap.values());
+
+ qMap = new QueueMap();
+ for (int i = 0; i < 5; i++) {
+ qMap.put(Integer.toString(i), "A");
+ }
+ System.out.println("\nMap = " + qMap);
+ System.out.println("Keys = " + qMap.keys());
+ System.out.println("Values = " + qMap.values());
+
+ qMap = new QueueMap();
+ for (int i = 0; i < 5; i++) {
+ qMap.put(Integer.toString(i), null);
+ }
+ System.out.println("\nMap = " + qMap);
+ System.out.println("Keys = " + qMap.keys());
+ System.out.println("Values = " + qMap.values());
+
+ Map aMap = new HashMap();
+ for (int i = 0; i < 5; i++) {
+ aMap.put(Integer.toString(i), Integer.toString(i));
+ }
+ qMap = new QueueMap(aMap);
+ System.out.println("\nHashMap = " + aMap);
+ System.out.println("Map = " + qMap);
+ System.out.println("Keys = " + qMap.keys());
+ System.out.println("Values = " + qMap.values());
+
+ qMap = new QueueMap();
+ qMap.put("Test1", "String1");
+ qMap.put("Test2", "String2");
+ qMap.put("Test3", "String3");
+ qMap.put("Test4", "String4");
+ qMap.put("Test5", "String5");
+ System.out.println("\nStandard Test, Map = " + qMap);
+ qMap.put("Test6", "String6");
+ qMap.put("Test7", "String7");
+ System.out.println("Put New Test, Map = " + qMap);
+ qMap.put("Test2", "New String2");
+ qMap.put("Test6", "New String6");
+ System.out.println("Put Existing Test, Map = " + qMap);
+ qMap.put("Test5", null);
+ qMap.put("Test8", null);
+ System.out.println("Put Null Test, Map = " + qMap);
+ qMap.remove("Test1");
+ qMap.remove("Test3");
+ qMap.remove("Test5");
+ qMap.remove("Test9");
+ System.out.println("Remove Test, Map = " + qMap);
+ System.out.println(" Keys = " + qMap.keys());
+ System.out.println(" Values = " + qMap.values());
+ qMap.clear();
+ qMap.put("Test10", "String10");
+ qMap.put("Test11", "String11");
+ qMap.put("Test12", "String12");
+ System.out.println("Clear Test, Map = " + qMap);
+
+ aMap = new HashMap();
+ aMap.put("Test10", "String10");
+ aMap.put("Test11", "String11");
+ aMap.put("Test12", "String12");
+ System.out.println("Equality Test, Equal = " + qMap.equals(aMap));
+ }
}
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java
index 9133a8d..8694564 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java
@@ -47,7 +47,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
- */
+ */
package net.wotonomy.foundation.internal;
@@ -61,147 +61,134 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
- * This implementation of URL Resource Reader assumes 2 types
- * of base urls. A base url that ends with / is considered a
- * resource folder, whereas a resource that does not end with
- * / is considered a zip/jar resource folder.
+ * This implementation of URL Resource Reader assumes 2 types of base urls. A
+ * base url that ends with / is considered a resource folder, whereas a resource
+ * that does not end with / is considered a zip/jar resource folder.
*
- * If the resource folder happens is a zip/jar archive, the
- * entries are always cached.
- * For non-zip base urls, one could specify whether or not it should
- * be cached.
+ * If the resource folder happens is a zip/jar archive, the entries are always
+ * cached. For non-zip base urls, one could specify whether or not it should be
+ * cached.
*
* @author Harish Prabandham
*/
-public class URLResourceReader {
- private Hashtable resourceCache = new Hashtable();
- private boolean iszip = true;
- private URL url = null;
- private boolean cache = true;
-
- /**
- * Creates a new URLResourceReader object. You can either give
- * the URL of the zip/jar file or a base url where to
- * look for additional resources. If the url ends with
- * "/" then it is assumed to be a Base URL.
- * @param The base url to look for the resources.
- * @param If the base url is not a zip/jar, then true indicates
- * that entries should be cached, false otherwise.
- */
- public URLResourceReader(URL baseurl, boolean cache) throws IOException {
- this.url = baseurl;
- this.cache = cache;
- this.iszip = !url.getFile().endsWith("/");
- if(this.iszip)
- this.cache = true;
- initialize();
- }
-
- /**
- * equivalent to URLResourceReader(baseurl, false)
- */
- public URLResourceReader(URL baseurl) throws IOException {
- this(baseurl, false);
- }
-
- /**
- * Creates a new URLResourceReader object with the given
- * input stream. The stream is assumed to be a zip/jar
- * stream.
- */
- public URLResourceReader(InputStream is) throws IOException {
- init(is);
- }
-
- private void initialize() throws IOException {
- if(iszip) {
- InputStream is = url.openStream();
- init(is);
- is.close();
- }
- }
-
- private byte[] readFully(InputStream is) throws IOException {
- byte[] buf = new byte[1024];
- int num = 0;
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
- while( (num = is.read(buf)) != -1) {
- bout.write(buf, 0, num);
- }
-
- return bout.toByteArray();
- }
-
- private void init(InputStream is) throws IOException {
- ZipInputStream zstream = new ZipInputStream(is);
- ZipEntry entry;
-
- while( (entry = zstream.getNextEntry()) != null) {
- byte[] entryData = readFully(zstream);
- if(cache)
- resourceCache.put(entry.getName(), entryData);
- zstream.closeEntry();
- }
-
- zstream.close();
- }
-
- /**
- * Returns an Enumeration of all "known" resource names.
- */
- public Enumeration getResourceNames() {
- return resourceCache.keys();
- }
-
- /**
- * Returns an array of bytes read for this resource if the
- * resource exists. This method blocks until the resource
- * has been fully read. If the resource does not exist,
- * this method returns null.
- */
- public byte[] getResource(String resource) {
- // lookup the data in the cache...
- byte[] data = (byte[]) resourceCache.get(resource);
- if(data != null) {
- return data;
- }
-
- // if the data was to come from a zip file that we
- // already read fully & cached , then it is probably
- // not there.
- if(iszip) {
- return null;
- }
-
- // Now the only choice left is to make a url connection.
- try {
- URL realURL = new URL(url.getProtocol(), url.getHost(),
- url.getFile() + resource);
- data = readFully(realURL.openStream());
- // add it to cache if needed...
- if(cache)
- resourceCache.put(resource, data);
- return data;
- } catch(Exception e) {
- return null;
- }
- }
-
- public void close() {
- resourceCache.clear();
- resourceCache = null;
- }
-
- public String toString() {
- return url.toString();
- }
+public class URLResourceReader {
+ private Hashtable resourceCache = new Hashtable();
+ private boolean iszip = true;
+ private URL url = null;
+ private boolean cache = true;
+
+ /**
+ * Creates a new URLResourceReader object. You can either give the URL of the
+ * zip/jar file or a base url where to look for additional resources. If the url
+ * ends with "/" then it is assumed to be a Base URL.
+ *
+ * @param The base url to look for the resources.
+ * @param If the base url is not a zip/jar, then true indicates that entries
+ * should be cached, false otherwise.
+ */
+ public URLResourceReader(URL baseurl, boolean cache) throws IOException {
+ this.url = baseurl;
+ this.cache = cache;
+ this.iszip = !url.getFile().endsWith("/");
+ if (this.iszip)
+ this.cache = true;
+ initialize();
+ }
+
+ /**
+ * equivalent to URLResourceReader(baseurl, false)
+ */
+ public URLResourceReader(URL baseurl) throws IOException {
+ this(baseurl, false);
+ }
+
+ /**
+ * Creates a new URLResourceReader object with the given input stream. The
+ * stream is assumed to be a zip/jar stream.
+ */
+ public URLResourceReader(InputStream is) throws IOException {
+ init(is);
+ }
+
+ private void initialize() throws IOException {
+ if (iszip) {
+ InputStream is = url.openStream();
+ init(is);
+ is.close();
+ }
+ }
+
+ private byte[] readFully(InputStream is) throws IOException {
+ byte[] buf = new byte[1024];
+ int num = 0;
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+ while ((num = is.read(buf)) != -1) {
+ bout.write(buf, 0, num);
+ }
+
+ return bout.toByteArray();
+ }
+
+ private void init(InputStream is) throws IOException {
+ ZipInputStream zstream = new ZipInputStream(is);
+ ZipEntry entry;
+
+ while ((entry = zstream.getNextEntry()) != null) {
+ byte[] entryData = readFully(zstream);
+ if (cache)
+ resourceCache.put(entry.getName(), entryData);
+ zstream.closeEntry();
+ }
+
+ zstream.close();
+ }
+
+ /**
+ * Returns an Enumeration of all "known" resource names.
+ */
+ public Enumeration getResourceNames() {
+ return resourceCache.keys();
+ }
+
+ /**
+ * Returns an array of bytes read for this resource if the resource exists. This
+ * method blocks until the resource has been fully read. If the resource does
+ * not exist, this method returns null.
+ */
+ public byte[] getResource(String resource) {
+ // lookup the data in the cache...
+ byte[] data = (byte[]) resourceCache.get(resource);
+ if (data != null) {
+ return data;
+ }
+
+ // if the data was to come from a zip file that we
+ // already read fully & cached , then it is probably
+ // not there.
+ if (iszip) {
+ return null;
+ }
+
+ // Now the only choice left is to make a url connection.
+ try {
+ URL realURL = new URL(url.getProtocol(), url.getHost(), url.getFile() + resource);
+ data = readFully(realURL.openStream());
+ // add it to cache if needed...
+ if (cache)
+ resourceCache.put(resource, data);
+ return data;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public void close() {
+ resourceCache.clear();
+ resourceCache = null;
+ }
+
+ public String toString() {
+ return url.toString();
+ }
}
-
-
-
-
-
-
-
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
index d6bc797..7f28e06 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java
@@ -17,6 +17,7 @@ License along with this library; if not, see http://www.gnu.org
*/
package net.wotonomy.foundation.internal;
+
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Collection;
@@ -25,694 +26,562 @@ import java.util.LinkedList;
import java.util.Map;
/**
-* A utility class to convert objects to a desired class.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class ValueConverter
-{
- /**
- * Returns the specified object as converted to an instance of the
- * specified class, or null if the conversion could not be performed.
- */
- static public Object convertObjectToClass( Object anObject, Class aClass )
- {
- if ( aClass == String.class )
- {
- return getString( anObject );
- }
- if ( aClass == Short.class )
- {
- return getShort( anObject );
- }
- if ( aClass == short.class )
- {
- return getShort( anObject );
- }
- if ( aClass == Integer.class )
- {
- return getInteger( anObject );
- }
- if ( aClass == int.class )
- {
- return getInteger( anObject );
- }
- if ( aClass == Long.class )
- {
- return getLong( anObject );
- }
- if ( aClass == long.class )
- {
- return getLong( anObject );
- }
- if ( aClass == Float.class )
- {
- return getFloat( anObject );
- }
- if ( aClass == float.class )
- {
- return getFloat( anObject );
- }
- if ( aClass == Double.class )
- {
- return getDouble( anObject );
- }
- if ( aClass == double.class )
- {
- return getDouble( anObject );
- }
- if ( aClass == java.util.Date.class )
- {
- return getDate( anObject );
- }
- if ( aClass == Boolean.class )
- {
- return getBoolean( anObject );
- }
- if ( aClass == boolean.class )
- {
- return getBoolean( anObject );
- }
- if ( aClass == Character.class )
- {
- return getCharacter( anObject );
- }
- if ( aClass == char.class )
- {
- return getCharacter( anObject );
- }
- if ( aClass == Byte.class )
- {
- return getByte( anObject );
- }
- if ( aClass == byte.class )
- {
- return getByte( anObject );
- }
- if ( Collection.class.isAssignableFrom( aClass ) )
- {
- return getCollection( anObject, aClass );
- }
- if ( aClass.isArray() )
- {
- return getArray( anObject, aClass );
- }
-
- return convert( anObject, aClass );
- }
-
- /**
- * Called by convertObjectToClass() when we need to
- * convert to an unrecognized type.
- * This implementation scans the constructors of the
- * specified class for the best fit to the object.
- * and returns a new instance with that constructor.
- * Subclasses can override to directly support specific
- * types.
- */
- static protected Object convert( Object anObject, Class aClass )
- {
- Constructor[] ctors = aClass.getConstructors();
-
- Class[] types;
- for ( int i = 0; i < ctors.length; i++ )
- {
- types = ctors[i].getParameterTypes();
- if ( types.length == 1 )
- {
- if ( types[0].equals( anObject.getClass() ) )
- {
- try
- {
- return ctors[i].newInstance( new Object[] { anObject } );
- }
- catch ( Exception exc )
- {
- // fall through
- }
- }
- }
- }
-
- for ( int i = 0; i < ctors.length; i++ )
- {
- types = ctors[i].getParameterTypes();
- if ( types.length == 1 )
- {
- if ( anObject.getClass().isAssignableFrom( types[0] ) )
- {
- try
- {
- return ctors[i].newInstance( new Object[] { anObject } );
- }
- catch ( Exception exc )
- {
- // fall through
- }
- }
- }
- }
-
- return null;
- }
-
- /**
- * Tries to convert all objects to either Numbers or objects
- * that will produce a parsable toString result.
- */
- static protected Object preprocess( Object anObject )
- {
- if ( anObject instanceof Boolean )
- {
- if ( ((Boolean)anObject).booleanValue() )
- {
- return new Double( 1.0 );
- }
- return new Double( 0.0 );
- }
-
- if ( anObject instanceof Character )
- {
- return anObject.toString();
- }
-
- return anObject;
- }
-
- static public short getShortValue( Object anObject )
- {
- Short result = getShort( anObject );
- return ( result == null ) ? (short) 0 : result.shortValue();
- }
- static public Short getShort( Object anObject )
- {
- if ( anObject == null ) return new Short( (short) 0 );
- if ( "".equals( anObject ) ) return new Short( (short) 0 );
- if ( anObject instanceof Short ) return (Short) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Short( ((Number)anObject).shortValue() );
- }
-
- try
- {
- return Short.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public int getIntValue( Object anObject )
- {
- Integer result = getInteger( anObject );
- return ( result == null ) ? 0 : result.intValue();
- }
- static public Integer getInteger( Object anObject )
- {
- if ( anObject == null ) return new Integer( 0 );
- if ( "".equals( anObject ) ) return new Integer( 0 );
- if ( anObject instanceof Integer ) return (Integer) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Integer( ((Number)anObject).intValue() );
- }
-
- try
- {
- return Integer.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public long getLongValue ( Object anObject )
- {
- Long result = getLong( anObject );
- return ( result == null ) ? (long) 0 : result.longValue();
- }
- static public Long getLong( Object anObject )
- {
- if ( anObject == null ) return new Long( 0 );
- if ( "".equals( anObject ) ) return new Long( 0 );
- if ( anObject instanceof Long ) return (Long) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Long( ((Number)anObject).longValue() );
- }
-
- try
- {
- return Long.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public double getDoubleValue ( Object anObject )
- {
- Double result = getDouble( anObject );
- return ( result == null ) ? 0.0f : result.doubleValue();
- }
- static public Double getDouble( Object anObject )
- {
- if ( anObject == null ) return new Double( 0.0 );
- if ( "".equals( anObject ) ) return new Double( 0 );
- if ( anObject instanceof Double ) return (Double) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Double( ((Number)anObject).doubleValue() );
- }
-
- try
- {
- return Double.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public float getFloatValue( Object anObject )
- {
- Float result = getFloat( anObject );
- return ( result == null ) ? 0.0f : result.floatValue();
- }
- static public Float getFloat( Object anObject )
- {
- if ( anObject == null ) return new Float( 0.0 );
- if ( "".equals( anObject ) ) return new Float( 0.0 );
- if ( anObject instanceof Float ) return (Float) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Float( ((Number)anObject).floatValue() );
- }
-
- try
- {
- return Float.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public char getCharValue( Object anObject )
- {
- Character result = getCharacter( anObject );
- return ( result == null ) ? (char) 0 : result.charValue();
- }
- static public Character getCharacter( Object anObject )
- {
- if ( anObject == null ) return new Character( (char) 0 );
- if ( anObject instanceof Character ) return (Character) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Character( (char) ((Number)anObject).byteValue() );
- }
-
- try
- {
- return new Character( anObject.toString().charAt( 0 ) );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static public byte getByteValue( Object anObject )
- {
- Byte result = getByte ( anObject );
- return ( result == null ) ? (byte) 0 : result.byteValue();
- }
- static public Byte getByte( Object anObject )
- {
- if ( anObject == null ) return new Byte( Byte.MIN_VALUE );
- if ( "".equals( anObject ) ) return new Byte( Byte.MIN_VALUE );
- if ( anObject instanceof Byte ) return (Byte) anObject;
-
- anObject = preprocess( anObject );
-
- if ( anObject instanceof Number )
- {
- return new Byte( ((Number)anObject).byteValue() );
- }
-
- try
- {
- return Byte.decode( anObject.toString() );
- }
- catch ( Exception exc )
- {
- // fall through
- }
-
- try
- {
- return Byte.valueOf( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
+ * A utility class to convert objects to a desired class.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class ValueConverter {
+ /**
+ * Returns the specified object as converted to an instance of the specified
+ * class, or null if the conversion could not be performed.
+ */
+ static public Object convertObjectToClass(Object anObject, Class aClass) {
+ if (aClass == String.class) {
+ return getString(anObject);
+ }
+ if (aClass == Short.class) {
+ return getShort(anObject);
+ }
+ if (aClass == short.class) {
+ return getShort(anObject);
+ }
+ if (aClass == Integer.class) {
+ return getInteger(anObject);
+ }
+ if (aClass == int.class) {
+ return getInteger(anObject);
+ }
+ if (aClass == Long.class) {
+ return getLong(anObject);
+ }
+ if (aClass == long.class) {
+ return getLong(anObject);
+ }
+ if (aClass == Float.class) {
+ return getFloat(anObject);
+ }
+ if (aClass == float.class) {
+ return getFloat(anObject);
+ }
+ if (aClass == Double.class) {
+ return getDouble(anObject);
+ }
+ if (aClass == double.class) {
+ return getDouble(anObject);
+ }
+ if (aClass == java.util.Date.class) {
+ return getDate(anObject);
+ }
+ if (aClass == Boolean.class) {
+ return getBoolean(anObject);
+ }
+ if (aClass == boolean.class) {
+ return getBoolean(anObject);
+ }
+ if (aClass == Character.class) {
+ return getCharacter(anObject);
+ }
+ if (aClass == char.class) {
+ return getCharacter(anObject);
+ }
+ if (aClass == Byte.class) {
+ return getByte(anObject);
+ }
+ if (aClass == byte.class) {
+ return getByte(anObject);
+ }
+ if (Collection.class.isAssignableFrom(aClass)) {
+ return getCollection(anObject, aClass);
+ }
+ if (aClass.isArray()) {
+ return getArray(anObject, aClass);
+ }
+
+ return convert(anObject, aClass);
+ }
+
+ /**
+ * Called by convertObjectToClass() when we need to convert to an unrecognized
+ * type. This implementation scans the constructors of the specified class for
+ * the best fit to the object. and returns a new instance with that constructor.
+ * Subclasses can override to directly support specific types.
+ */
+ static protected Object convert(Object anObject, Class aClass) {
+ Constructor[] ctors = aClass.getConstructors();
+
+ Class[] types;
+ for (int i = 0; i < ctors.length; i++) {
+ types = ctors[i].getParameterTypes();
+ if (types.length == 1) {
+ if (types[0].equals(anObject.getClass())) {
+ try {
+ return ctors[i].newInstance(new Object[] { anObject });
+ } catch (Exception exc) {
+ // fall through
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < ctors.length; i++) {
+ types = ctors[i].getParameterTypes();
+ if (types.length == 1) {
+ if (anObject.getClass().isAssignableFrom(types[0])) {
+ try {
+ return ctors[i].newInstance(new Object[] { anObject });
+ } catch (Exception exc) {
+ // fall through
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Tries to convert all objects to either Numbers or objects that will produce a
+ * parsable toString result.
+ */
+ static protected Object preprocess(Object anObject) {
+ if (anObject instanceof Boolean) {
+ if (((Boolean) anObject).booleanValue()) {
+ return new Double(1.0);
+ }
+ return new Double(0.0);
+ }
+
+ if (anObject instanceof Character) {
+ return anObject.toString();
+ }
+
+ return anObject;
+ }
+
+ static public short getShortValue(Object anObject) {
+ Short result = getShort(anObject);
+ return (result == null) ? (short) 0 : result.shortValue();
+ }
+
+ static public Short getShort(Object anObject) {
+ if (anObject == null)
+ return new Short((short) 0);
+ if ("".equals(anObject))
+ return new Short((short) 0);
+ if (anObject instanceof Short)
+ return (Short) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Short(((Number) anObject).shortValue());
+ }
+
+ try {
+ return Short.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public int getIntValue(Object anObject) {
+ Integer result = getInteger(anObject);
+ return (result == null) ? 0 : result.intValue();
+ }
+
+ static public Integer getInteger(Object anObject) {
+ if (anObject == null)
+ return new Integer(0);
+ if ("".equals(anObject))
+ return new Integer(0);
+ if (anObject instanceof Integer)
+ return (Integer) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Integer(((Number) anObject).intValue());
+ }
+
+ try {
+ return Integer.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public long getLongValue(Object anObject) {
+ Long result = getLong(anObject);
+ return (result == null) ? (long) 0 : result.longValue();
+ }
+
+ static public Long getLong(Object anObject) {
+ if (anObject == null)
+ return new Long(0);
+ if ("".equals(anObject))
+ return new Long(0);
+ if (anObject instanceof Long)
+ return (Long) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Long(((Number) anObject).longValue());
+ }
+
+ try {
+ return Long.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public double getDoubleValue(Object anObject) {
+ Double result = getDouble(anObject);
+ return (result == null) ? 0.0f : result.doubleValue();
+ }
+
+ static public Double getDouble(Object anObject) {
+ if (anObject == null)
+ return new Double(0.0);
+ if ("".equals(anObject))
+ return new Double(0);
+ if (anObject instanceof Double)
+ return (Double) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Double(((Number) anObject).doubleValue());
+ }
+
+ try {
+ return Double.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public float getFloatValue(Object anObject) {
+ Float result = getFloat(anObject);
+ return (result == null) ? 0.0f : result.floatValue();
+ }
+
+ static public Float getFloat(Object anObject) {
+ if (anObject == null)
+ return new Float(0.0);
+ if ("".equals(anObject))
+ return new Float(0.0);
+ if (anObject instanceof Float)
+ return (Float) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Float(((Number) anObject).floatValue());
+ }
+
+ try {
+ return Float.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public char getCharValue(Object anObject) {
+ Character result = getCharacter(anObject);
+ return (result == null) ? (char) 0 : result.charValue();
+ }
+
+ static public Character getCharacter(Object anObject) {
+ if (anObject == null)
+ return new Character((char) 0);
+ if (anObject instanceof Character)
+ return (Character) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Character((char) ((Number) anObject).byteValue());
+ }
+
+ try {
+ return new Character(anObject.toString().charAt(0));
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static public byte getByteValue(Object anObject) {
+ Byte result = getByte(anObject);
+ return (result == null) ? (byte) 0 : result.byteValue();
+ }
+
+ static public Byte getByte(Object anObject) {
+ if (anObject == null)
+ return new Byte(Byte.MIN_VALUE);
+ if ("".equals(anObject))
+ return new Byte(Byte.MIN_VALUE);
+ if (anObject instanceof Byte)
+ return (Byte) anObject;
+
+ anObject = preprocess(anObject);
+
+ if (anObject instanceof Number) {
+ return new Byte(((Number) anObject).byteValue());
+ }
+
+ try {
+ return Byte.decode(anObject.toString());
+ } catch (Exception exc) {
+ // fall through
+ }
+
+ try {
+ return Byte.valueOf(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
/**
- * Calls getBoolean and converts result to primitive.
- */
- static public boolean getBooleanValue( Object anObject )
- {
- Boolean result = getBoolean( anObject );
- return ( result == null ) ? false : result.booleanValue();
- }
-
+ * Calls getBoolean and converts result to primitive.
+ */
+ static public boolean getBooleanValue(Object anObject) {
+ Boolean result = getBoolean(anObject);
+ return (result == null) ? false : result.booleanValue();
+ }
+
/**
- * Numbers equal to zero are true; Strings equal to "yes" are true;
- * Strings are then passed to the Boolean constructor.
- * Other values return null.
- */
- static public Boolean getBoolean( Object anObject )
- {
- if ( anObject instanceof Boolean )
- {
+ * Numbers equal to zero are true; Strings equal to "yes" are true; Strings are
+ * then passed to the Boolean constructor. Other values return null.
+ */
+ static public Boolean getBoolean(Object anObject) {
+ if (anObject instanceof Boolean) {
return (Boolean) anObject;
}
- if ( anObject instanceof Number )
- {
- return new Boolean( ((Number)anObject).doubleValue() == 0.0 );
- }
-
- if ( anObject instanceof String )
- {
- if ( anObject.toString().toLowerCase().equals( "yes" ) )
- {
+ if (anObject instanceof Number) {
+ return new Boolean(((Number) anObject).doubleValue() == 0.0);
+ }
+
+ if (anObject instanceof String) {
+ if (anObject.toString().toLowerCase().equals("yes")) {
return Boolean.TRUE;
}
- return new Boolean( (String) anObject );
- }
-
- return null;
- }
-
- /**
- * Get an appropriate String representation for the
- * object. Nulls are converted to "null". Date are
- * formatted according to the current date format.
- * All else uses toString.
- */
- static public String getString( Object anObject )
- {
- if ( anObject == null ) return "null";
- if ( anObject instanceof java.util.Date )
- {
- return dateFormat.format( (java.util.Date) anObject );
- }
- return anObject.toString();
- }
-
- /**
- * Converts the object into the specified collection class.
- * If unable to convert in any other way, resorts to creating
- * a new collection of the specified type containing the
- * specified object.
- */
- static public Collection getCollection( Object anObject, Class aCollectionClass )
- {
- if ( anObject == null ) return null;
- if ( aCollectionClass.isAssignableFrom( anObject.getClass() ) )
- {
- return (Collection) anObject;
- }
-
- Collection converted = null;
-
- // convert to collection class
- if ( anObject instanceof Collection )
- {
- converted = (Collection) anObject;
- }
- else
- // try to convert an array
- if ( anObject.getClass().isArray() )
- {
- try
- {
- int length = Array.getLength( anObject );
- converted = new LinkedList();
- for ( int i = 0; i < length; i++ )
- {
- converted.add( Array.get( anObject, i ) );
- }
- }
- catch ( Exception exc )
- {
- // try another approach
- }
- }
- else
- // convert map values to collection and pass through
- if ( anObject instanceof Map )
- {
- converted = ((Map)anObject).values();
- }
-
- // fall back on list containing the object
- if ( converted == null )
- {
- converted = new LinkedList();
- converted.add( anObject );
- }
-
- Collection result = null;
-
- if ( converted != null )
- {
- try
- {
- // collections required to have the copy constructor.
- Constructor ctor = aCollectionClass.getConstructor(
- new Class[] { Collection.class } );
- result = (Collection) ctor.newInstance( new Object[] { converted } );
- }
- catch ( Exception exc )
- {
- try
- {
- result = new LinkedList();
- result.addAll( converted );
- }
- catch ( Exception exc2 )
- {
- // all attempts failed
- result = null;
- }
- }
- }
-
- return result;
- }
-
- /**
- * Convert the object to the specified array type.
- */
- static public Object getArray( Object anObject, Class anArrayClass )
- {
- if ( anObject == null ) return null;
-
- // try to convert an array
- if ( anObject.getClass().isArray() )
- {
- try
- {
- int length = Array.getLength( anObject );
- Object result = Array.newInstance(
- anArrayClass.getComponentType(), length );
- for ( int i = 0; i < length; i++ )
- {
- Array.set( result, i, Array.get( anObject, i ) );
- }
- return result;
- }
- catch ( Exception exc )
- {
- // try another approach
- }
- }
- // convert map values to collection and pass through
- if ( anObject instanceof Map )
- {
- anObject = ((Map)anObject).values();
- }
- // try to convert a collection
- if ( anObject instanceof Collection )
- {
- try
- {
- int length = ((Collection)anObject).size();
- Object result = Array.newInstance(
- anArrayClass.getComponentType(), length );
- Iterator it = ((Collection)anObject).iterator();
- for ( int i = 0; i < length; i++ )
- {
- Array.set( result, i, it.next() );
- }
- return result;
- }
- catch ( Exception exc )
- {
- // try another approach
- }
- }
- // if appropriate type, put the object in a single element array
- if ( anObject.getClass().equals( anArrayClass.getComponentType() ) )
- {
- try
- {
- Object result = Array.newInstance(
- anArrayClass.getComponentType(), 1 );
- Array.set( result, 0, anObject );
- return result;
- }
- catch ( Exception exc )
- {
- // try another approach
- }
- }
- return null;
- }
-
- /**
- * Get an appropriate Date from the given object.
- */
- static public java.util.Date getDate( Object anObject )
- {
- if ( anObject == null ) return new java.util.Date( 0 );
- if ( anObject instanceof java.util.Date )
- return (java.util.Date) anObject;
-
- if ( anObject instanceof Number )
- {
- return new java.util.Date( getLongValue( anObject ) );
- }
-
- try
- {
- return dateFormat.parse( anObject.toString() );
- }
- catch ( Exception exc )
- {
- return null;
- }
- }
-
- static private java.text.DateFormat dateFormat =
- new java.text.SimpleDateFormat();
- static public java.text.DateFormat getDateFormat()
- {
- return dateFormat;
- }
- static public void setDateFormat( java.text.DateFormat aDateFormat )
- {
- if ( aDateFormat != null )
- {
- dateFormat = aDateFormat;
- }
- }
-
- /**
- * Returns the "inverted" value of the specified object.
- * Numbers except for chars and bytes are converted to
- * their negative representation. Chars and bytes are
- * treated as booleans. String are converted to booleans.
- * Booleans are converted to their opposite.
- * All other types return null.
- */
- public static Object invert( Object anObject )
- {
- if ( anObject == null ) return null;
- Class aClass = anObject.getClass();
-
- if ( ( ( anObject instanceof Number )
- &&! ( anObject instanceof Byte )
- &&! ( anObject instanceof Character ) )
- || ( aClass == short.class )
- || ( aClass == int.class )
- || ( aClass == long.class )
- || ( aClass == float.class )
- || ( aClass == double.class ) )
- {
- return convertObjectToClass(
- new Double( getDoubleValue( anObject ) * -1 ), aClass );
- }
-
- Boolean converted = getBoolean( anObject );
- if ( converted != null )
- {
- if ( converted.booleanValue() )
- {
- return convertObjectToClass(
- Boolean.FALSE, anObject.getClass() );
- }
- else
- {
- return convertObjectToClass(
- Boolean.TRUE, anObject.getClass() );
- }
- }
-
- return null;
- }
+ return new Boolean((String) anObject);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an appropriate String representation for the object. Nulls are converted
+ * to "null". Date are formatted according to the current date format. All else
+ * uses toString.
+ */
+ static public String getString(Object anObject) {
+ if (anObject == null)
+ return "null";
+ if (anObject instanceof java.util.Date) {
+ return dateFormat.format((java.util.Date) anObject);
+ }
+ return anObject.toString();
+ }
+
+ /**
+ * Converts the object into the specified collection class. If unable to convert
+ * in any other way, resorts to creating a new collection of the specified type
+ * containing the specified object.
+ */
+ static public Collection getCollection(Object anObject, Class aCollectionClass) {
+ if (anObject == null)
+ return null;
+ if (aCollectionClass.isAssignableFrom(anObject.getClass())) {
+ return (Collection) anObject;
+ }
+
+ Collection converted = null;
+
+ // convert to collection class
+ if (anObject instanceof Collection) {
+ converted = (Collection) anObject;
+ } else
+ // try to convert an array
+ if (anObject.getClass().isArray()) {
+ try {
+ int length = Array.getLength(anObject);
+ converted = new LinkedList();
+ for (int i = 0; i < length; i++) {
+ converted.add(Array.get(anObject, i));
+ }
+ } catch (Exception exc) {
+ // try another approach
+ }
+ } else
+ // convert map values to collection and pass through
+ if (anObject instanceof Map) {
+ converted = ((Map) anObject).values();
+ }
+
+ // fall back on list containing the object
+ if (converted == null) {
+ converted = new LinkedList();
+ converted.add(anObject);
+ }
+
+ Collection result = null;
+
+ if (converted != null) {
+ try {
+ // collections required to have the copy constructor.
+ Constructor ctor = aCollectionClass.getConstructor(new Class[] { Collection.class });
+ result = (Collection) ctor.newInstance(new Object[] { converted });
+ } catch (Exception exc) {
+ try {
+ result = new LinkedList();
+ result.addAll(converted);
+ } catch (Exception exc2) {
+ // all attempts failed
+ result = null;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Convert the object to the specified array type.
+ */
+ static public Object getArray(Object anObject, Class anArrayClass) {
+ if (anObject == null)
+ return null;
+
+ // try to convert an array
+ if (anObject.getClass().isArray()) {
+ try {
+ int length = Array.getLength(anObject);
+ Object result = Array.newInstance(anArrayClass.getComponentType(), length);
+ for (int i = 0; i < length; i++) {
+ Array.set(result, i, Array.get(anObject, i));
+ }
+ return result;
+ } catch (Exception exc) {
+ // try another approach
+ }
+ }
+ // convert map values to collection and pass through
+ if (anObject instanceof Map) {
+ anObject = ((Map) anObject).values();
+ }
+ // try to convert a collection
+ if (anObject instanceof Collection) {
+ try {
+ int length = ((Collection) anObject).size();
+ Object result = Array.newInstance(anArrayClass.getComponentType(), length);
+ Iterator it = ((Collection) anObject).iterator();
+ for (int i = 0; i < length; i++) {
+ Array.set(result, i, it.next());
+ }
+ return result;
+ } catch (Exception exc) {
+ // try another approach
+ }
+ }
+ // if appropriate type, put the object in a single element array
+ if (anObject.getClass().equals(anArrayClass.getComponentType())) {
+ try {
+ Object result = Array.newInstance(anArrayClass.getComponentType(), 1);
+ Array.set(result, 0, anObject);
+ return result;
+ } catch (Exception exc) {
+ // try another approach
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get an appropriate Date from the given object.
+ */
+ static public java.util.Date getDate(Object anObject) {
+ if (anObject == null)
+ return new java.util.Date(0);
+ if (anObject instanceof java.util.Date)
+ return (java.util.Date) anObject;
+
+ if (anObject instanceof Number) {
+ return new java.util.Date(getLongValue(anObject));
+ }
+
+ try {
+ return dateFormat.parse(anObject.toString());
+ } catch (Exception exc) {
+ return null;
+ }
+ }
+
+ static private java.text.DateFormat dateFormat = new java.text.SimpleDateFormat();
+
+ static public java.text.DateFormat getDateFormat() {
+ return dateFormat;
+ }
+
+ static public void setDateFormat(java.text.DateFormat aDateFormat) {
+ if (aDateFormat != null) {
+ dateFormat = aDateFormat;
+ }
+ }
+
+ /**
+ * Returns the "inverted" value of the specified object. Numbers except for
+ * chars and bytes are converted to their negative representation. Chars and
+ * bytes are treated as booleans. String are converted to booleans. Booleans are
+ * converted to their opposite. All other types return null.
+ */
+ public static Object invert(Object anObject) {
+ if (anObject == null)
+ return null;
+ Class aClass = anObject.getClass();
+
+ if (((anObject instanceof Number) && !(anObject instanceof Byte) && !(anObject instanceof Character))
+ || (aClass == short.class) || (aClass == int.class) || (aClass == long.class) || (aClass == float.class)
+ || (aClass == double.class)) {
+ return convertObjectToClass(new Double(getDoubleValue(anObject) * -1), aClass);
+ }
+
+ Boolean converted = getBoolean(anObject);
+ if (converted != null) {
+ if (converted.booleanValue()) {
+ return convertObjectToClass(Boolean.FALSE, anObject.getClass());
+ } else {
+ return convertObjectToClass(Boolean.TRUE, anObject.getClass());
+ }
+ }
+
+ return null;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 13:11:47 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2002/10/11 15:33:53 mpowers
- * Now supporting "!" to invert the value of a string property.
+ * Revision 1.4 2002/10/11 15:33:53 mpowers Now supporting "!" to invert the
+ * value of a string property.
*
- * Revision 1.3 2001/07/02 16:29:08 mpowers
- * XMLRPC decoder was relying on ValueConverter to convert LinkedLists into
- * the appropriate type. This is now implemented in ValueConverter.
+ * Revision 1.3 2001/07/02 16:29:08 mpowers XMLRPC decoder was relying on
+ * ValueConverter to convert LinkedLists into the appropriate type. This is now
+ * implemented in ValueConverter.
*
- * Revision 1.2 2001/03/01 20:36:35 mpowers
- * Better error handling and better handling of nulls.
+ * Revision 1.2 2001/03/01 20:36:35 mpowers Better error handling and better
+ * handling of nulls.
*
- * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy.
*
- * Revision 1.8 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.8 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java
index e2210d0..21b47b3 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java
@@ -22,113 +22,96 @@ import java.io.PrintStream;
import java.io.PrintWriter;
/**
-* This is a simple RuntimeException that can encapsulate
-* another throwable. Behaves as a normal RuntimeException
-* except that it prints a stack trace of the wrapped
-* throwable if one is specified.
-*
-* Intended to be used anytime you'd
-* report an exception with System.out.println: that is,
-* for debugging and non-user-visible exceptions.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * This is a simple RuntimeException that can encapsulate another throwable.
+ * Behaves as a normal RuntimeException except that it prints a stack trace of
+ * the wrapped throwable if one is specified.
+ *
+ * Intended to be used anytime you'd report an exception with
+ * System.out.println: that is, for debugging and non-user-visible exceptions.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
-public class WotonomyException extends RuntimeException
-{
+public class WotonomyException extends RuntimeException {
protected String message;
protected Throwable wrappedThrowable;
-
+
/**
- * Default constructor.
- */
- public WotonomyException()
- {
+ * Default constructor.
+ */
+ public WotonomyException() {
super();
message = null;
- wrappedThrowable = null;
+ wrappedThrowable = null;
}
-
+
/**
- * Standard constructor with message.
- */
- public WotonomyException( String aMessage )
- {
- super( aMessage );
+ * Standard constructor with message.
+ */
+ public WotonomyException(String aMessage) {
+ super(aMessage);
message = aMessage;
wrappedThrowable = null;
}
-
+
/**
- * Specifies a throwable to wrap.
- */
- public WotonomyException( Throwable aThrowable )
- {
+ * Specifies a throwable to wrap.
+ */
+ public WotonomyException(Throwable aThrowable) {
super();
message = null;
wrappedThrowable = aThrowable;
}
-
+
/**
- * Specifies a message and a throwable to wrap.
- */
- public WotonomyException( String aMessage, Throwable aThrowable )
- {
- super( aMessage );
+ * Specifies a message and a throwable to wrap.
+ */
+ public WotonomyException(String aMessage, Throwable aThrowable) {
+ super(aMessage);
message = aMessage;
wrappedThrowable = aThrowable;
}
-
- /**
- * Returns the wrapped throwable.
- */
- public Throwable getWrappedThrowable()
- {
- return wrappedThrowable;
- }
-
- public void printStackTrace(PrintWriter s)
- {
- if ( message != null )
- {
- s.println( "Exception: " + message );
+
+ /**
+ * Returns the wrapped throwable.
+ */
+ public Throwable getWrappedThrowable() {
+ return wrappedThrowable;
+ }
+
+ public void printStackTrace(PrintWriter s) {
+ if (message != null) {
+ s.println("Exception: " + message);
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace( s );
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace(s);
return;
}
- super.printStackTrace( s );
+ super.printStackTrace(s);
}
-
- public void printStackTrace(PrintStream s)
- {
- if ( message != null )
- {
- s.println( "Exception: " + message );
+
+ public void printStackTrace(PrintStream s) {
+ if (message != null) {
+ s.println("Exception: " + message);
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace( s );
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace(s);
return;
}
- super.printStackTrace( s );
+ super.printStackTrace(s);
}
-
- public void printStackTrace()
- {
- if ( message != null )
- {
- System.err.println( "Exception: " + message );
+
+ public void printStackTrace() {
+ if (message != null) {
+ System.err.println("Exception: " + message);
}
- if ( wrappedThrowable != null )
- {
- wrappedThrowable.printStackTrace();
+ if (wrappedThrowable != null) {
+ wrappedThrowable.printStackTrace();
return;
}
super.printStackTrace();
}
-
+
}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java
index 64ac4b2..79b3967 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java
@@ -22,47 +22,42 @@ import java.io.InputStream;
import java.net.URL;
/**
-* Defines an interface for classes that can de-serialize
-* java objects from an XML representation.
-*/
-public interface XMLDecoder
-{
- /**
- * Decodes an object from the specified input stream.
- * @param anInputStream The input stream from which to read.
- * The stream will be read fully.
- * @param aDescription A description to accompany error messages
- * for the stream, typically a file name.
- * @param aURL A URL against which relative references within the
- * XML will be resolved.
- * @return The object that was constructed from the XML content,
- * or null if no object could be constructed.
- */
- public Object decode(
- InputStream anInputStream, String aDescription, URL aURL );
+ * Defines an interface for classes that can de-serialize java objects from an
+ * XML representation.
+ */
+public interface XMLDecoder {
+ /**
+ * Decodes an object from the specified input stream.
+ *
+ * @param anInputStream The input stream from which to read. The stream will be
+ * read fully.
+ * @param aDescription A description to accompany error messages for the
+ * stream, typically a file name.
+ * @param aURL A URL against which relative references within the XML
+ * will be resolved.
+ * @return The object that was constructed from the XML content, or null if no
+ * object could be constructed.
+ */
+ public Object decode(InputStream anInputStream, String aDescription, URL aURL);
}
/*
- * $Log$
- * Revision 1.1 2006/02/18 22:21:10 cgruber
- * Add in simple xml interfaces from net.wotonomy.xml project.
- * Add cobertura.ser to .cvsignore. God I wish sourceforge would move on this subversion thing...
+ * $Log$ Revision 1.1 2006/02/18 22:21:10 cgruber Add in simple xml interfaces
+ * from net.wotonomy.xml project. Add cobertura.ser to .cvsignore. God I wish
+ * sourceforge would move on this subversion thing...
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java
index e543bca..0d180aa 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java
@@ -21,41 +21,37 @@ package net.wotonomy.foundation.xml;
import java.io.OutputStream;
/**
-* Defines an interface for classes that can serialize
-* an arbitrary java object into XML format.
-*/
-public interface XMLEncoder
-{
- /**
- * Encodes an object to the specified output stream as XML.
- * @param anObject The object to be serialized to XML format.
- * @param anOutputStream The output stream to which the object
- * will be written. The stream will not be flushed nor closed.
- */
- public void encode( Object anObject, OutputStream anOutputStream );
+ * Defines an interface for classes that can serialize an arbitrary java object
+ * into XML format.
+ */
+public interface XMLEncoder {
+ /**
+ * Encodes an object to the specified output stream as XML.
+ *
+ * @param anObject The object to be serialized to XML format.
+ * @param anOutputStream The output stream to which the object will be written.
+ * The stream will not be flushed nor closed.
+ */
+ public void encode(Object anObject, OutputStream anOutputStream);
}
/*
- * $Log$
- * Revision 1.1 2006/02/18 22:21:10 cgruber
- * Add in simple xml interfaces from net.wotonomy.xml project.
- * Add cobertura.ser to .cvsignore. God I wish sourceforge would move on this subversion thing...
+ * $Log$ Revision 1.1 2006/02/18 22:21:10 cgruber Add in simple xml interfaces
+ * from net.wotonomy.xml project. Add cobertura.ser to .cvsignore. God I wish
+ * sourceforge would move on this subversion thing...
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.foundation/src/test/java/AllTests.java b/projects/net.wotonomy.foundation/src/test/java/AllTests.java
index 1b36871..906dfac 100644
--- a/projects/net.wotonomy.foundation/src/test/java/AllTests.java
+++ b/projects/net.wotonomy.foundation/src/test/java/AllTests.java
@@ -8,9 +8,9 @@ public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("Test for default package");
- //$JUnit-BEGIN$
+ // $JUnit-BEGIN$
suite.addTestSuite(net.wotonomy.foundation.AllTests.class);
- //$JUnit-END$
+ // $JUnit-END$
return suite;
}
diff --git a/projects/net.wotonomy.foundation/src/test/java/TestBundle.java b/projects/net.wotonomy.foundation/src/test/java/TestBundle.java
index 7fb5020..9c0b1c7 100644
--- a/projects/net.wotonomy.foundation/src/test/java/TestBundle.java
+++ b/projects/net.wotonomy.foundation/src/test/java/TestBundle.java
@@ -5,17 +5,19 @@ import java.util.List;
import java.util.Properties;
public class TestBundle {
- public String toString() { return "This is a test"; }
-
+ public String toString() {
+ return "This is a test";
+ }
+
public static void main(String[] argv) {
Properties p = System.getProperties();
List keyList = new ArrayList(p.keySet());
Collections.sort(keyList);
Iterator keys = keyList.iterator();
while (keys.hasNext()) {
- String key = (String)keys.next();
+ String key = (String) keys.next();
System.out.println(key + "=" + p.getProperty(key));
}
-
+
}
}
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java
index 920b0a7..7a2e664 100644
--- a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java
+++ b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java
@@ -7,10 +7,10 @@ public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("Test for net.wotonomy.foundation");
- //$JUnit-BEGIN$
+ // $JUnit-BEGIN$
suite.addTestSuite(NSArrayTest.class);
suite.addTestSuite(NSBundleTest.class);
- //$JUnit-END$
+ // $JUnit-END$
return suite;
}
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
index 8873f1a..e8bdbbc 100644
--- a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
+++ b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
@@ -11,9 +11,8 @@ import junit.framework.TestCase;
public class NSArrayTest extends TestCase {
-
- Object o1, o2, o3, o4, o5;
-
+ Object o1, o2, o3, o4, o5;
+
public void setUp() throws Exception {
o1 = "o1";
o2 = new Integer(2);
@@ -21,7 +20,7 @@ public class NSArrayTest extends TestCase {
o4 = "o4";
super.setUp();
}
-
+
public void tearDown() throws Exception {
o1 = null;
o2 = null;
@@ -29,17 +28,17 @@ public class NSArrayTest extends TestCase {
o4 = null;
super.tearDown();
}
-
+
/*
* Test method for 'net.wotonomy.foundation.NSArray.hashCode()'
*/
public void testHashCode() {
NSArray array1 = new NSArray(o1);
- NSArray array2 = new NSArray(o1); //same content, same hashcode.
+ NSArray array2 = new NSArray(o1); // same content, same hashcode.
NSArray array3 = new NSArray("Different");
- assertNotSame(array1,array2);
- assertEquals(array1.hashCode(),array2.hashCode());
- assertFalse("Should have different hashcodes",array1.hashCode() == array3.hashCode());
+ assertNotSame(array1, array2);
+ assertEquals(array1.hashCode(), array2.hashCode());
+ assertFalse("Should have different hashcodes", array1.hashCode() == array3.hashCode());
}
/*
@@ -49,7 +48,7 @@ public class NSArrayTest extends TestCase {
List list = new ArrayList();
NSArray array = NSArray.arrayBackedByList(list);
assertNotNull(array);
- assertSame(list,array.list);
+ assertSame(list, array.list);
}
/*
@@ -57,7 +56,7 @@ public class NSArrayTest extends TestCase {
*/
public void testEmptyList() {
assertNotNull(NSArray.EmptyArray);
- assertEquals(0,NSArray.EmptyArray.count());
+ assertEquals(0, NSArray.EmptyArray.count());
}
/*
@@ -67,7 +66,7 @@ public class NSArrayTest extends TestCase {
List list = new ArrayList();
NSArray array = new NSArray(list, null);
assertNotNull(array);
- assertSame(list,array.list);
+ assertSame(list, array.list);
}
/*
@@ -81,7 +80,8 @@ public class NSArrayTest extends TestCase {
try {
array = new NSArray(-1);
fail("Failed to catch IllegalArgumentException.");
- } catch (IllegalArgumentException e) {}
+ } catch (IllegalArgumentException e) {
+ }
assertNotNull(array);
array = new NSArray(1000);
assertNotNull(array);
@@ -101,29 +101,29 @@ public class NSArrayTest extends TestCase {
public void testNSArrayObject() {
NSArray array = new NSArray(o1);
assertNotNull(array);
- assertEquals(1,array.count());
- assertEquals(o1,array.get(0));
+ assertEquals(1, array.count());
+ assertEquals(o1, array.get(0));
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Object)'
*/
public void testNSArrayObjectWithNull() {
- NSArray array = new NSArray((Object)null);
+ NSArray array = new NSArray((Object) null);
assertNotNull(array);
- assertEquals(1,array.count());
- assertEquals(null,array.get(0));
+ assertEquals(1, array.count());
+ assertEquals(null, array.get(0));
}
-
+
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Object[])'
*/
public void testNSArrayObjectArray() {
Object[] objects = { o1, o2, o3 };
NSArray array = new NSArray(objects);
- assertEquals(3,array.count());
- for (int i = 0; i < objects.length ; i++) {
- assertEquals(objects[i],array.get(i));
+ assertEquals(3, array.count());
+ for (int i = 0; i < objects.length; i++) {
+ assertEquals(objects[i], array.get(i));
}
}
@@ -137,29 +137,30 @@ public class NSArrayTest extends TestCase {
list.add(o3);
NSArray array = new NSArray(list);
assertNotNull(array);
- assertNotSame(list,array.list);
- assertEquals(3,array.count());
+ assertNotSame(list, array.list);
+ assertEquals(3, array.count());
// the following only works because we used ArrayList.
// A collection that doesn't guarrantee order may not
// pass this test.
- for (int i = 0; i < list.size() ; i++) {
- assertEquals(list.get(i),array.get(i));
+ for (int i = 0; i < list.size(); i++) {
+ assertEquals(list.get(i), array.get(i));
}
}
-
+
/*
* Test method for 'net.wotonomy.foundation.NSArray.arrayByAddingObject(Object)'
*/
public void testArrayByAddingObject() {
NSArray array = new NSArray(o1);
NSArray array2 = array.arrayByAddingObject(o2);
- assertEquals(2,array2.count());
- assertEquals(o1,array2.get(0));
- assertEquals(o2,array2.get(1));
+ assertEquals(2, array2.count());
+ assertEquals(o1, array2.get(0));
+ assertEquals(o2, array2.get(1));
}
/*
- * Test method for 'net.wotonomy.foundation.NSArray.arrayByAddingObjectsFromArray(Collection)'
+ * Test method for
+ * 'net.wotonomy.foundation.NSArray.arrayByAddingObjectsFromArray(Collection)'
*/
public void testArrayByAddingObjectsFromArray() {
NSArray array = new NSArray(o1);
@@ -167,14 +168,15 @@ public class NSArrayTest extends TestCase {
list.add(o2);
list.add(o3);
NSArray array2 = array.arrayByAddingObjectsFromArray(list);
- assertEquals(3,array2.count());
- assertEquals(o1,array2.get(0));
- assertEquals(o2,array2.get(1));
- assertEquals(o3,array2.get(2));
+ assertEquals(3, array2.count());
+ assertEquals(o1, array2.get(0));
+ assertEquals(o2, array2.get(1));
+ assertEquals(o3, array2.get(2));
}
/*
- * Test method for 'net.wotonomy.foundation.NSArray.componentsJoinedByString(String)'
+ * Test method for
+ * 'net.wotonomy.foundation.NSArray.componentsJoinedByString(String)'
*/
public void testComponentsJoinedByString() {
Object[] objects = { o1, o2, o3 };
@@ -192,15 +194,16 @@ public class NSArrayTest extends TestCase {
}
/*
- * Test method for 'net.wotonomy.foundation.NSArray.firstObjectCommonWithArray(Collection)'
+ * Test method for
+ * 'net.wotonomy.foundation.NSArray.firstObjectCommonWithArray(Collection)'
*/
- public void testFirstObjectCommonWithArray() {
+ public void testFirstObjectCommonWithArray() {
ArrayList list = new ArrayList();
list.add(o2);
list.add(o3);
list.add(o4);
- NSArray array = new NSArray(new Object[]{o1, o3, o4});
- assertEquals(o3,array.firstObjectCommonWithArray(list));
+ NSArray array = new NSArray(new Object[] { o1, o3, o4 });
+ assertEquals(o3, array.firstObjectCommonWithArray(list));
}
/*
@@ -208,61 +211,61 @@ public class NSArrayTest extends TestCase {
*/
public void testEqualsAndIsEqualToArray() {
NSArray array1 = new NSArray(o1);
- NSArray array2 = new NSArray(o1); //same content, same hashcode.
+ NSArray array2 = new NSArray(o1); // same content, same hashcode.
NSArray array3 = new NSArray(o2);
- assertNotSame(array1,array2);
- assertTrue("Should be equal",array1.equals(array2));
- assertTrue("Should be equal",array1.isEqualToArray(array2));
- assertFalse("Should be unequal",array1.equals(array3));
- assertFalse("Should be unequal",array1.isEqualToArray(array3));
+ assertNotSame(array1, array2);
+ assertTrue("Should be equal", array1.equals(array2));
+ assertTrue("Should be equal", array1.isEqualToArray(array2));
+ assertFalse("Should be unequal", array1.equals(array3));
+ assertFalse("Should be unequal", array1.isEqualToArray(array3));
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.lastObject()'
*/
- public void testLastObject() {
- NSArray array = new NSArray(new Object[]{o1, o2});
- assertEquals(o2,array.lastObject());
+ public void testLastObject() {
+ NSArray array = new NSArray(new Object[] { o1, o2 });
+ assertEquals(o2, array.lastObject());
// test for empty array
- assertEquals(null,NSArray.EmptyArray.lastObject());
+ assertEquals(null, NSArray.EmptyArray.lastObject());
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.subarrayWithRange(NSRange)'
* TODO: Add ranges that exceed the size of the array.
*/
- public void testSubarrayWithRange() {
- NSArray array = new NSArray(new Object[]{o1, o2, o3, o4});
- NSArray subarray = array.subarrayWithRange(new NSRange(1,2));
- assertEquals(2,subarray.count());
- assertEquals(o2,subarray.get(0));
- assertEquals(o3,subarray.get(1));
+ public void testSubarrayWithRange() {
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray subarray = array.subarrayWithRange(new NSRange(1, 2));
+ assertEquals(2, subarray.count());
+ assertEquals(o2, subarray.get(0));
+ assertEquals(o3, subarray.get(1));
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.objectEnumerator()'
*/
public void testObjectEnumerator() {
- NSArray array = new NSArray(new Object[]{o1, o2, o3, o4});
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
Enumeration e = array.objectEnumerator();
assertTrue(e.hasMoreElements());
- assertEquals(o1,e.nextElement());
- assertEquals(o2,e.nextElement());
- assertEquals(o3,e.nextElement());
- assertEquals(o4,e.nextElement());
+ assertEquals(o1, e.nextElement());
+ assertEquals(o2, e.nextElement());
+ assertEquals(o3, e.nextElement());
+ assertEquals(o4, e.nextElement());
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.reverseObjectEnumerator()'
*/
public void testReverseObjectEnumerator() {
- NSArray array = new NSArray(new Object[]{o1, o2, o3, o4});
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
Enumeration e = array.reverseObjectEnumerator();
assertTrue(e.hasMoreElements());
- assertEquals(o4,e.nextElement());
- assertEquals(o3,e.nextElement());
- assertEquals(o2,e.nextElement());
- assertEquals(o1,e.nextElement());
+ assertEquals(o4, e.nextElement());
+ assertEquals(o3, e.nextElement());
+ assertEquals(o2, e.nextElement());
+ assertEquals(o1, e.nextElement());
}
/*
@@ -270,369 +273,359 @@ public class NSArrayTest extends TestCase {
*/
public void testGetObjectsObjectArray() {
Object[] oa = new Object[4];
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
- assertEquals(o1,oa[0]);
- assertEquals(o2,oa[1]);
- assertEquals(o3,oa[2]);
- assertEquals(o4,oa[3]);
- assertEquals(4,oa.length);
+ assertEquals(o1, oa[0]);
+ assertEquals(o2, oa[1]);
+ assertEquals(o3, oa[2]);
+ assertEquals(o4, oa[3]);
+ assertEquals(4, oa.length);
}
-
+
public void testGetObjectsObjectArrayWithSmallArray() {
Object[] oa = new Object[2];
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
- assertEquals(o1,oa[0]);
- assertEquals(o2,oa[1]);
- assertEquals(2,oa.length);
+ assertEquals(o1, oa[0]);
+ assertEquals(o2, oa[1]);
+ assertEquals(2, oa.length);
}
-
+
public void testGetObjectsObjectArrayWithLargeArray() {
Object[] oa = new Object[5];
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
- assertEquals(o1,oa[0]);
- assertEquals(o2,oa[1]);
- assertEquals(o3,oa[2]);
- assertEquals(o4,oa[3]);
- assertEquals(null,oa[4]);
- assertEquals(5,oa.length);
+ assertEquals(o1, oa[0]);
+ assertEquals(o2, oa[1]);
+ assertEquals(o3, oa[2]);
+ assertEquals(o4, oa[3]);
+ assertEquals(null, oa[4]);
+ assertEquals(5, oa.length);
}
+
/*
- * Test method for 'net.wotonomy.foundation.NSArray.getObjects(Object[], NSRange)'
- * TODO: Try more ranges.
+ * Test method for 'net.wotonomy.foundation.NSArray.getObjects(Object[],
+ * NSRange)' TODO: Try more ranges.
*/
public void testGetObjectsObjectArrayNSRange() {
Object[] oa = new Object[2];
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- array.getObjects(oa, new NSRange(1,2));
- assertEquals(o2,oa[0]);
- assertEquals(o3,oa[1]);
- assertEquals(2,oa.length);
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ array.getObjects(oa, new NSRange(1, 2));
+ assertEquals(o2, oa[0]);
+ assertEquals(o3, oa[1]);
+ assertEquals(2, oa.length);
}
public void testGetObjectsObjectArrayNSRangeWithLargeRange() {
Object[] oa = new Object[4];
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- array.getObjects(oa, new NSRange(1,90));
- assertEquals(o2,oa[0]);
- assertEquals(o3,oa[1]);
- assertEquals(o4,oa[2]);
- assertEquals(null,oa[3]);
- assertEquals(4,oa.length);
- }
-
-
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ array.getObjects(oa, new NSRange(1, 90));
+ assertEquals(o2, oa[0]);
+ assertEquals(o3, oa[1]);
+ assertEquals(o4, oa[2]);
+ assertEquals(null, oa[3]);
+ assertEquals(4, oa.length);
+ }
+
/*
* Test method for 'net.wotonomy.foundation.NSArray.indexOfObject(Object)'
*/
public void testIndexOfObjectObject() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- assertEquals(0,array.indexOfObject(o1));
- assertEquals(1,array.indexOfObject(o2));
- assertEquals(2,array.indexOfObject(o3));
- assertEquals(3,array.indexOfObject(o4));
- assertEquals(-1,array.indexOfObject("No Such Object"));
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ assertEquals(0, array.indexOfObject(o1));
+ assertEquals(1, array.indexOfObject(o2));
+ assertEquals(2, array.indexOfObject(o3));
+ assertEquals(3, array.indexOfObject(o4));
+ assertEquals(-1, array.indexOfObject("No Such Object"));
}
/*
- * Test method for 'net.wotonomy.foundation.NSArray.indexOfObject(Object, NSRange)'
+ * Test method for 'net.wotonomy.foundation.NSArray.indexOfObject(Object,
+ * NSRange)'
*/
public void testIndexOfObjectObjectNSRange() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- NSRange range = new NSRange(1,2);
- assertEquals(-1,array.indexOfObject(o1,range));
- assertEquals(1,array.indexOfObject(o2,range));
-
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSRange range = new NSRange(1, 2);
+ assertEquals(-1, array.indexOfObject(o1, range));
+ assertEquals(1, array.indexOfObject(o2, range));
+
// should be -1 because o3 == null;
- assertEquals(-1,array.indexOfObject(o3,range));
- assertEquals(-1,array.indexOfObject(o4,range));
- assertEquals(-1,array.indexOfObject("No Such Object"));
+ assertEquals(-1, array.indexOfObject(o3, range));
+ assertEquals(-1, array.indexOfObject(o4, range));
+ assertEquals(-1, array.indexOfObject("No Such Object"));
}
-
public void testIndexOfIdenticalObjectObject() {
- Integer i1 = new Integer(3-1);
- Integer i2 = new Integer(4/2);
- NSArray array = new NSArray(new Object[] { o1,i2,o3,o4 });
- assertEquals(1,array.indexOfObject(i1));
+ Integer i1 = new Integer(3 - 1);
+ Integer i2 = new Integer(4 / 2);
+ NSArray array = new NSArray(new Object[] { o1, i2, o3, o4 });
+ assertEquals(1, array.indexOfObject(i1));
assertFalse(1 == array.indexOfIdenticalObject(i1));
assertEquals(1, array.indexOfIdenticalObject(i2));
}
public void testIndexOfIdenticalObjectObjectNSRange() {
- Integer i1 = new Integer(3-1);
- Integer i2 = new Integer(4/2);
- NSRange range = new NSRange(1,2);
- NSArray array = new NSArray(new Object[] { o1,i2,o3,o4 });
- assertEquals(1,array.indexOfObject(i1,range));
- assertFalse(1 == array.indexOfIdenticalObject(i1,range));
- assertEquals(1, array.indexOfIdenticalObject(i2,range));
- NSRange range2 = new NSRange(3,2);
- assertEquals(-1, array.indexOfObject(i1,range2));
- assertEquals(-1, array.indexOfIdenticalObject(i1,range2));
- assertEquals(-1, array.indexOfIdenticalObject(i2,range2));
+ Integer i1 = new Integer(3 - 1);
+ Integer i2 = new Integer(4 / 2);
+ NSRange range = new NSRange(1, 2);
+ NSArray array = new NSArray(new Object[] { o1, i2, o3, o4 });
+ assertEquals(1, array.indexOfObject(i1, range));
+ assertFalse(1 == array.indexOfIdenticalObject(i1, range));
+ assertEquals(1, array.indexOfIdenticalObject(i2, range));
+ NSRange range2 = new NSRange(3, 2);
+ assertEquals(-1, array.indexOfObject(i1, range2));
+ assertEquals(-1, array.indexOfIdenticalObject(i1, range2));
+ assertEquals(-1, array.indexOfIdenticalObject(i2, range2));
}
public void testObjectAtIndex() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- assertEquals(o1,array.objectAtIndex(0));
- assertEquals(o2,array.objectAtIndex(1));
- assertEquals(o3,array.objectAtIndex(2));
- assertEquals(o4,array.objectAtIndex(3));
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ assertEquals(o1, array.objectAtIndex(0));
+ assertEquals(o2, array.objectAtIndex(1));
+ assertEquals(o3, array.objectAtIndex(2));
+ assertEquals(o4, array.objectAtIndex(3));
try {
- assertEquals(null,array.objectAtIndex(4));
+ assertEquals(null, array.objectAtIndex(4));
fail("Should have thrown index out of bounds.");
- } catch (IndexOutOfBoundsException e) {}
+ } catch (IndexOutOfBoundsException e) {
+ }
}
public void testComponentsSeparatedByString() {
String arrayString = "word0 word1 word2 word3";
- NSArray array = NSArray.componentsSeparatedByString(arrayString," ");
- assertEquals("word0",array.objectAtIndex(0));
- assertEquals("word1",array.objectAtIndex(1));
- assertEquals("word2",array.objectAtIndex(2));
- assertEquals("word3",array.objectAtIndex(3));
- }
-
-/*
- public void testClone() {
- fail("Not yet implemented");
-
- }
-
- public void testImmutableClone() {
- fail("Not yet implemented");
-
+ NSArray array = NSArray.componentsSeparatedByString(arrayString, " ");
+ assertEquals("word0", array.objectAtIndex(0));
+ assertEquals("word1", array.objectAtIndex(1));
+ assertEquals("word2", array.objectAtIndex(2));
+ assertEquals("word3", array.objectAtIndex(3));
}
- public void testMutableClone() {
- fail("Not yet implemented");
+ /*
+ * public void testClone() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testImmutableClone() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testMutableClone() { fail("Not yet implemented");
+ *
+ * }
+ */
- }
-*/
-
public void testToString() {
- NSArray array = new NSArray(new Object[] { "o1",new Integer(1),"o3" });
- assertEquals("(o1, 1, o3)",array.toString());
+ NSArray array = new NSArray(new Object[] { "o1", new Integer(1), "o3" });
+ assertEquals("(o1, 1, o3)", array.toString());
}
-
-
public void testContains() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
- assertTrue("Should contain object",array.contains(o1));
- assertTrue("Should contain object",array.contains(o2));
- assertFalse("Should not contain object",array.contains(o3));
- assertTrue("Should contain object",array.contains(o4));
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ assertTrue("Should contain object", array.contains(o1));
+ assertTrue("Should contain object", array.contains(o2));
+ assertFalse("Should not contain object", array.contains(o3));
+ assertTrue("Should contain object", array.contains(o4));
}
+
public void testContainsAll() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
ArrayList list = new ArrayList();
list.add(o1);
list.add(o2);
- assertTrue("Should have all elements of provided list.",array.containsAll(list));
+ assertTrue("Should have all elements of provided list.", array.containsAll(list));
ArrayList list2 = new ArrayList();
list2.add(o2);
list2.add(o3);
- assertFalse("Should not have all elements of provided list.",array.containsAll(list2));
+ assertFalse("Should not have all elements of provided list.", array.containsAll(list2));
}
public void testGet() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
- assertEquals(o1,array.get(0));
- assertEquals(o2,array.get(1));
- assertEquals(o4,array.get(2));
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ assertEquals(o1, array.get(0));
+ assertEquals(o2, array.get(1));
+ assertEquals(o4, array.get(2));
try {
array.get(3);
- } catch (IndexOutOfBoundsException e) {}
+ } catch (IndexOutOfBoundsException e) {
+ }
}
public void testIndexOf() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
- assertEquals(0,array.indexOf(o1));
- assertEquals(1,array.indexOf(o2));
- assertEquals(-1,array.indexOf(o3));
- assertEquals(2,array.indexOf(o4));
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ assertEquals(0, array.indexOf(o1));
+ assertEquals(1, array.indexOf(o2));
+ assertEquals(-1, array.indexOf(o3));
+ assertEquals(2, array.indexOf(o4));
}
-
+
public void testIsEmpty() {
- assertFalse(new NSArray(new Object[] { o1,o2,o4 } ).isEmpty());
- assertTrue(new NSArray(new Object[] {} ).isEmpty());
+ assertFalse(new NSArray(new Object[] { o1, o2, o4 }).isEmpty());
+ assertTrue(new NSArray(new Object[] {}).isEmpty());
}
public void testLastIndexOf() {
- NSArray array = new NSArray(new Object[] { o1,o4,o2,o4 });
- assertEquals(0,array.lastIndexOf(o1));
- assertEquals(2,array.lastIndexOf(o2));
- assertEquals(-1,array.lastIndexOf(o3));
- assertEquals(3,array.lastIndexOf(o4));
+ NSArray array = new NSArray(new Object[] { o1, o4, o2, o4 });
+ assertEquals(0, array.lastIndexOf(o1));
+ assertEquals(2, array.lastIndexOf(o2));
+ assertEquals(-1, array.lastIndexOf(o3));
+ assertEquals(3, array.lastIndexOf(o4));
}
public void testSize() {
- assertEquals(3,new NSArray(new Object[] { o1,o2,o4 }).size());
- assertEquals(1,new NSArray(new Object[] { o1 }).size());
- assertEquals(0,new NSArray(new Object[] { }).size());
+ assertEquals(3, new NSArray(new Object[] { o1, o2, o4 }).size());
+ assertEquals(1, new NSArray(new Object[] { o1 }).size());
+ assertEquals(0, new NSArray(new Object[] {}).size());
}
public void testToArray() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
Object[] oarray = array.toArray();
- assertEquals(oarray[0],o1);
- assertEquals(oarray[1],o2);
- assertEquals(oarray[2],o4);
+ assertEquals(oarray[0], o1);
+ assertEquals(oarray[1], o2);
+ assertEquals(oarray[2], o4);
}
public void testToArrayObjectArray() {
- NSArray array = new NSArray(new Object[] { o1,o2,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o4 });
Object[] oa0 = new Object[3];
Object[] oa1 = array.toArray(oa0);
- assertSame(oa0,oa1);
- assertEquals(oa1[0],o1);
- assertEquals(oa1[1],o2);
- assertEquals(oa1[2],o4);
+ assertSame(oa0, oa1);
+ assertEquals(oa1[0], o1);
+ assertEquals(oa1[1], o2);
+ assertEquals(oa1[2], o4);
}
public void testAddIntObject() {
- NSArray array = new NSArray(new Object[] { o1,o3,o4 });
- array.add(1,o2);
- assertEquals(0,array.indexOfObject(o1));
- assertEquals(1,array.indexOfObject(o2));
- assertEquals(2,array.indexOfObject(o3));
- assertEquals(3,array.indexOfObject(o4));
+ NSArray array = new NSArray(new Object[] { o1, o3, o4 });
+ array.add(1, o2);
+ assertEquals(0, array.indexOfObject(o1));
+ assertEquals(1, array.indexOfObject(o2));
+ assertEquals(2, array.indexOfObject(o3));
+ assertEquals(3, array.indexOfObject(o4));
}
public void testAddObject() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3 });
array.add(o4);
- assertEquals(0,array.indexOfObject(o1));
- assertEquals(1,array.indexOfObject(o2));
- assertEquals(2,array.indexOfObject(o3));
- assertEquals(3,array.indexOfObject(o4));
+ assertEquals(0, array.indexOfObject(o1));
+ assertEquals(1, array.indexOfObject(o2));
+ assertEquals(2, array.indexOfObject(o3));
+ assertEquals(3, array.indexOfObject(o4));
}
public void testAddAllCollection() {
- NSArray array = new NSArray(new Object[] { o1,o2 });
+ NSArray array = new NSArray(new Object[] { o1, o2 });
ArrayList list = new ArrayList();
list.add(o3);
list.add(o4);
array.addAll(list);
- assertEquals(0,array.indexOfObject(o1));
- assertEquals(1,array.indexOfObject(o2));
- assertEquals(2,array.indexOfObject(o3));
- assertEquals(3,array.indexOfObject(o4));
+ assertEquals(0, array.indexOfObject(o1));
+ assertEquals(1, array.indexOfObject(o2));
+ assertEquals(2, array.indexOfObject(o3));
+ assertEquals(3, array.indexOfObject(o4));
}
-
public void testAddAllIntCollection() {
- NSArray array = new NSArray(new Object[] { o1,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o4 });
ArrayList list = new ArrayList();
list.add(o2);
list.add(o3);
- array.addAll(1,list);
- assertEquals(0,array.indexOfObject(o1));
- assertEquals(1,array.indexOfObject(o2));
- assertEquals(2,array.indexOfObject(o3));
- assertEquals(3,array.indexOfObject(o4));
+ array.addAll(1, list);
+ assertEquals(0, array.indexOfObject(o1));
+ assertEquals(1, array.indexOfObject(o2));
+ assertEquals(2, array.indexOfObject(o3));
+ assertEquals(3, array.indexOfObject(o4));
}
-
public void testClear() {
- NSArray array = new NSArray(new Object[] { o1,o2 });
+ NSArray array = new NSArray(new Object[] { o1, o2 });
array.clear();
- assertEquals(0,array.size());
+ assertEquals(0, array.size());
}
public void testIterator() {
- NSArray array = new NSArray(new Object[] { o1,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o4 });
Iterator i = array.iterator();
- assertEquals(o1,i.next());
- assertEquals(o4,i.next());
+ assertEquals(o1, i.next());
+ assertEquals(o4, i.next());
assertFalse(i.hasNext());
}
public void testListIterator() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
ListIterator i = array.listIterator();
- assertEquals(o1,i.next());
- assertEquals(o2,i.next());
- assertEquals(o3,i.next());
- assertEquals(o4,i.next());
- assertEquals(o4,i.previous());
- assertEquals(o3,i.previous());
- assertEquals(o3,i.next());
- assertEquals(o4,i.next());
+ assertEquals(o1, i.next());
+ assertEquals(o2, i.next());
+ assertEquals(o3, i.next());
+ assertEquals(o4, i.next());
+ assertEquals(o4, i.previous());
+ assertEquals(o3, i.previous());
+ assertEquals(o3, i.next());
+ assertEquals(o4, i.next());
assertFalse(i.hasNext());
}
public void testListIteratorInt() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
ListIterator i = array.listIterator(1);
- assertEquals(o2,i.next());
- assertEquals(o3,i.next());
- assertEquals(o4,i.next());
- assertEquals(o4,i.previous());
- assertEquals(o3,i.previous());
- assertEquals(o3,i.next());
- assertEquals(o4,i.next());
+ assertEquals(o2, i.next());
+ assertEquals(o3, i.next());
+ assertEquals(o4, i.next());
+ assertEquals(o4, i.previous());
+ assertEquals(o3, i.previous());
+ assertEquals(o3, i.next());
+ assertEquals(o4, i.next());
assertFalse(i.hasNext());
}
public void testRemoveInt() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
- assertEquals(o2,array.remove(1));
- assertEquals(o3,array.remove(1));
- assertEquals(o1,array.objectAtIndex(0));
- assertEquals(o4,array.objectAtIndex(1));
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ assertEquals(o2, array.remove(1));
+ assertEquals(o3, array.remove(1));
+ assertEquals(o1, array.objectAtIndex(0));
+ assertEquals(o4, array.objectAtIndex(1));
}
public void testRemoveObject() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
assertTrue(array.remove(o2));
assertTrue(array.remove(o3));
assertFalse(array.remove("blah"));
- assertEquals(o1,array.objectAtIndex(0));
- assertEquals(o4,array.objectAtIndex(1));
+ assertEquals(o1, array.objectAtIndex(0));
+ assertEquals(o4, array.objectAtIndex(1));
}
public void testRemoveAll() {
- NSArray array = new NSArray(new Object[] { o1,o2,o3,o4 });
+ NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
ArrayList list = new ArrayList();
list.add(o1);
- list.add(o2);
+ list.add(o2);
array.removeAll(list);
- assertEquals(2,array.size());
- assertEquals(o3,array.objectAtIndex(0));
- assertEquals(o4,array.objectAtIndex(1));
+ assertEquals(2, array.size());
+ assertEquals(o3, array.objectAtIndex(0));
+ assertEquals(o4, array.objectAtIndex(1));
}
/*
- public void testRetainAll() {
- fail("Not yet implemented");
-
- }
-
- public void testSet() {
- fail("Not yet implemented");
-
- }
-
- public void testSubList() {
- fail("Not yet implemented");
-
- }
-
- public void testProtectedAdd() {
- fail("Not yet implemented");
-
- }
-
- public void testProtectedAddAll() {
- fail("Not yet implemented");
-
- }
-*/
-
+ * public void testRetainAll() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testSet() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testSubList() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testProtectedAdd() { fail("Not yet implemented");
+ *
+ * }
+ *
+ * public void testProtectedAddAll() { fail("Not yet implemented");
+ *
+ * }
+ */
}
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSBundleTest.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSBundleTest.java
index d441bec..3945f4a 100644
--- a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSBundleTest.java
+++ b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSBundleTest.java
@@ -30,7 +30,7 @@ public class NSBundleTest extends TestCase {
public NSBundleTest(String arg0) {
super(arg0);
}
-
+
protected void setUp() throws Exception {
super.setUp();
}
@@ -39,141 +39,92 @@ public class NSBundleTest extends TestCase {
super.tearDown();
}
/*
- public void testNSBundle() {
- //TODO Implement NSBundle().
- fail("Test not implemented.");
- }
-
- public void testBundleForClass() {
- //TODO Implement bundleForClass().
- fail("Test not implemented.");
- }
- */
-
- public void testBundleWithURL() throws Exception{
+ * public void testNSBundle() { //TODO Implement NSBundle().
+ * fail("Test not implemented."); }
+ *
+ * public void testBundleForClass() { //TODO Implement bundleForClass().
+ * fail("Test not implemented."); }
+ */
+
+ public void testBundleWithURL() throws Exception {
/*
- URL url = new File(System.getProperty("user.dir")+"/target/test-classes/TestBundle.framework").toURI().toURL();
- System.out.println(url.toString());
- NSBundle bundle = NSBundle.bundleWithURL(url);
- Assert.assertNotNull(bundle);
- Assert.assertEquals("TestBundle",bundle.name());
- Assert.assertEquals(true,bundle.isFramework());
- Properties p = bundle.properties();
- Assert.assertNotNull(p);
- Assert.assertEquals("TestValue",p.getProperty("TestKey"));
- */
+ * URL url = new File(System.getProperty("user.dir")+
+ * "/target/test-classes/TestBundle.framework").toURI().toURL();
+ * System.out.println(url.toString()); NSBundle bundle =
+ * NSBundle.bundleWithURL(url); Assert.assertNotNull(bundle);
+ * Assert.assertEquals("TestBundle",bundle.name());
+ * Assert.assertEquals(true,bundle.isFramework()); Properties p =
+ * bundle.properties(); Assert.assertNotNull(p);
+ * Assert.assertEquals("TestValue",p.getProperty("TestKey"));
+ */
}
/*
- public void testBundleForName() {
- //TODO Implement bundleForName().
- fail("Test not implemented.");
- }
-
- public void testFrameworkBundles() {
- //TODO Implement frameworkBundles().
- fail("Test not implemented.");
- }
-
- public void testSetMainBundle() {
- //TODO Implement setMainBundle().
- fail("Test not implemented.");
- }
-
- public void testMainBundle() {
- //TODO Implement mainBundle().
- fail("Test not implemented.");
- }
-
- public void testDefaultLocalePrefix() {
- //TODO Implement defaultLocalePrefix().
- fail("Test not implemented.");
- }
-
- public void testFindOrCreateBundleWithPath() {
- //TODO Implement findOrCreateBundleWithPath().
- fail("Test not implemented.");
- }
-
- public void testBundleClassPackageNames() {
- //TODO Implement bundleClassPackageNames().
- fail("Test not implemented.");
- }
-
- public void testBundlePath() {
- //TODO Implement bundlePath().
- fail("Test not implemented.");
- }
-
- public void testBytesForResourcePath() {
- //TODO Implement bytesForResourcePath().
- fail("Test not implemented.");
- }
-
- public void testBundleClassNames() {
- //TODO Implement bundleClassNames().
- fail("Test not implemented.");
- }
-
- public void testInfoDictionary() {
- //TODO Implement infoDictionary().
- fail("Test not implemented.");
- }
-
- public void testInputStreamForResourcePath() {
- //TODO Implement inputStreamForResourcePath().
- fail("Test not implemented.");
- }
-
- public void testIsFramework() {
- //TODO Implement isFramework().
- fail("Test not implemented.");
- }
-
- public void testLoad() {
- //TODO Implement load().
- fail("Test not implemented.");
- }
-
- public void testName() {
- //TODO Implement name().
- fail("Test not implemented.");
- }
-
- public void testPrincipalClass() {
- //TODO Implement principalClass().
- fail("Test not implemented.");
- }
-
- public void testProperties() {
- //TODO Implement properties().
- fail("Test not implemented.");
- }
-
- public void testResourcePathForLocalizedResourceNamed() {
- //TODO Implement resourcePathForLocalizedResourceNamed().
- fail("Test not implemented.");
- }
-
- public void testResourcePathsForDirectories() {
- //TODO Implement resourcePathsForDirectories().
- fail("Test not implemented.");
- }
-
- public void testResourcePathsForLocalizedResources() {
- //TODO Implement resourcePathsForLocalizedResources().
- fail("Test not implemented.");
- }
-
- public void testResourcePathsForResources() {
- //TODO Implement resourcePathsForResources().
- fail("Test not implemented.");
- }
-
- public void testToString() {
- //TODO Implement toString().
- fail("Test not implemented.");
- }
-
- */
+ * public void testBundleForName() { //TODO Implement bundleForName().
+ * fail("Test not implemented."); }
+ *
+ * public void testFrameworkBundles() { //TODO Implement frameworkBundles().
+ * fail("Test not implemented."); }
+ *
+ * public void testSetMainBundle() { //TODO Implement setMainBundle().
+ * fail("Test not implemented."); }
+ *
+ * public void testMainBundle() { //TODO Implement mainBundle().
+ * fail("Test not implemented."); }
+ *
+ * public void testDefaultLocalePrefix() { //TODO Implement
+ * defaultLocalePrefix(). fail("Test not implemented."); }
+ *
+ * public void testFindOrCreateBundleWithPath() { //TODO Implement
+ * findOrCreateBundleWithPath(). fail("Test not implemented."); }
+ *
+ * public void testBundleClassPackageNames() { //TODO Implement
+ * bundleClassPackageNames(). fail("Test not implemented."); }
+ *
+ * public void testBundlePath() { //TODO Implement bundlePath().
+ * fail("Test not implemented."); }
+ *
+ * public void testBytesForResourcePath() { //TODO Implement
+ * bytesForResourcePath(). fail("Test not implemented."); }
+ *
+ * public void testBundleClassNames() { //TODO Implement bundleClassNames().
+ * fail("Test not implemented."); }
+ *
+ * public void testInfoDictionary() { //TODO Implement infoDictionary().
+ * fail("Test not implemented."); }
+ *
+ * public void testInputStreamForResourcePath() { //TODO Implement
+ * inputStreamForResourcePath(). fail("Test not implemented."); }
+ *
+ * public void testIsFramework() { //TODO Implement isFramework().
+ * fail("Test not implemented."); }
+ *
+ * public void testLoad() { //TODO Implement load().
+ * fail("Test not implemented."); }
+ *
+ * public void testName() { //TODO Implement name().
+ * fail("Test not implemented."); }
+ *
+ * public void testPrincipalClass() { //TODO Implement principalClass().
+ * fail("Test not implemented."); }
+ *
+ * public void testProperties() { //TODO Implement properties().
+ * fail("Test not implemented."); }
+ *
+ * public void testResourcePathForLocalizedResourceNamed() { //TODO Implement
+ * resourcePathForLocalizedResourceNamed(). fail("Test not implemented."); }
+ *
+ * public void testResourcePathsForDirectories() { //TODO Implement
+ * resourcePathsForDirectories(). fail("Test not implemented."); }
+ *
+ * public void testResourcePathsForLocalizedResources() { //TODO Implement
+ * resourcePathsForLocalizedResources(). fail("Test not implemented."); }
+ *
+ * public void testResourcePathsForResources() { //TODO Implement
+ * resourcePathsForResources(). fail("Test not implemented."); }
+ *
+ * public void testToString() { //TODO Implement toString().
+ * fail("Test not implemented."); }
+ *
+ */
}
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java
index ece159b..f3d848c 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java
@@ -23,14 +23,13 @@ import net.wotonomy.access.EOModel;
import net.wotonomy.access.EOSQLExpressionFactory;
import net.wotonomy.foundation.NSDictionary;
-
/**
-* An adaptor that connects to a databaser server via JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * An adaptor that connects to a databaser server via JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCAdaptor extends EOAdaptor {
protected EOSQLExpressionFactory _expressionFactory;
@@ -39,6 +38,7 @@ public class JDBCAdaptor extends EOAdaptor {
/**
* Creates a new instance.
+ *
* @param name The name of the adaptor (should always be JDBC)
*/
public JDBCAdaptor(String name) {
@@ -48,17 +48,19 @@ public class JDBCAdaptor extends EOAdaptor {
public void setConnectionDictionary(NSDictionary dict) {
super.setConnectionDictionary(dict);
if (dict.objectForKey("driver") != null)
- _driverName = (String)dict.objectForKey("driver");
+ _driverName = (String) dict.objectForKey("driver");
else
throw new JDBCAdaptorException("Connection dictionary must have a 'driver' key.", null);
if (dict.objectForKey("jdbc2Info") != null)
- _jdbcInfo = (NSDictionary)dict.objectForKey("jdbc2Info");
+ _jdbcInfo = (NSDictionary) dict.objectForKey("jdbc2Info");
else
throw new JDBCAdaptorException("Connection dictionary must have a 'jdbc2Info' key.", null);
}
- /* Checks to see if the connection dictionary is valid.
- * Throws an exception if it's not.
+ /*
+ * Checks to see if the connection dictionary is valid. Throws an exception if
+ * it's not.
+ *
* @see net.wotonomy.access.EOAdaptor#assertConnectionDictionaryIsValid()
*/
public void assertConnectionDictionaryIsValid() {
@@ -67,7 +69,9 @@ public class JDBCAdaptor extends EOAdaptor {
context.disconnect();
}
- /* Creates a JDBCContext.
+ /*
+ * Creates a JDBCContext.
+ *
* @see net.wotonomy.access.EOAdaptor#createAdaptorContext()
*/
public EOAdaptorContext createAdaptorContext() {
@@ -76,14 +80,18 @@ public class JDBCAdaptor extends EOAdaptor {
return context;
}
- /* Returns the JDBCExpression class.
+ /*
+ * Returns the JDBCExpression class.
+ *
* @see net.wotonomy.access.EOAdaptor#defaultExpressionClass()
*/
public Class defaultExpressionClass() {
return JDBCExpression.class;
}
- /* Returns a JDBCExpressionFactory.
+ /*
+ * Returns a JDBCExpressionFactory.
+ *
* @see net.wotonomy.access.EOAdaptor#expressionFactory()
*/
public EOSQLExpressionFactory expressionFactory() {
@@ -92,8 +100,11 @@ public class JDBCAdaptor extends EOAdaptor {
return _expressionFactory;
}
- /* Determines if a qualifier type is valid.
- * @see net.wotonomy.access.EOAdaptor#isValidQualifierType(java.lang.String, net.wotonomy.access.EOModel)
+ /*
+ * Determines if a qualifier type is valid.
+ *
+ * @see net.wotonomy.access.EOAdaptor#isValidQualifierType(java.lang.String,
+ * net.wotonomy.access.EOModel)
*/
public boolean isValidQualifierType(String typeName, EOModel model) {
// TODO Auto-generated method stub
@@ -110,14 +121,13 @@ public class JDBCAdaptor extends EOAdaptor {
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 22:59:22 cgruber
- * make it compile with maven dependencies and add a cvsignore.
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 20:09:37 chochos
- * a concrete implementation of EOAdaptor for use with JDBC
+ * Revision 1.1 2003/08/13 20:09:37 chochos a concrete implementation of
+ * EOAdaptor for use with JDBC
*
*/
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java
index 5a999d0..412c0a1 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java
@@ -14,19 +14,20 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see http://www.gnu.org
- */package net.wotonomy.jdbcadaptor;
+ */
+package net.wotonomy.jdbcadaptor;
import java.sql.SQLException;
import net.wotonomy.access.EOGeneralAdaptorException;
/**
-* Concrete implementation of EOSQLExpression for use with JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * Concrete implementation of EOSQLExpression for use with JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCAdaptorException extends EOGeneralAdaptorException {
protected SQLException _sqlException;
@@ -55,14 +56,13 @@ public class JDBCAdaptorException extends EOGeneralAdaptorException {
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 22:59:22 cgruber
- * make it compile with maven dependencies and add a cvsignore.
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/13 20:11:30 chochos
- * forgot to add the wotonomy disclaimer...
+ * Revision 1.2 2003/08/13 20:11:30 chochos forgot to add the wotonomy
+ * disclaimer...
*
*/
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCChannel.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCChannel.java
index c62c463..64e4572 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCChannel.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCChannel.java
@@ -41,12 +41,12 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSTimestamp;
/**
-* Concrete implementation of EOAdaptorChannel for use with JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * Concrete implementation of EOAdaptorChannel for use with JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCChannel extends EOAdaptorChannel {
protected boolean _fetchInProgress;
@@ -60,6 +60,7 @@ public class JDBCChannel extends EOAdaptorChannel {
/**
* Creates a new JDBCChannel.
+ *
* @param context The JDBCContext this channel belongs to.
*/
public JDBCChannel(JDBCContext context) {
@@ -67,24 +68,31 @@ public class JDBCChannel extends EOAdaptorChannel {
}
protected JDBCContext _context() {
- return (JDBCContext)adaptorContext();
+ return (JDBCContext) adaptorContext();
}
- /* Sets the attributes to be fetched from the database.
- * @see net.wotonomy.access.EOAdaptorChannel#setAttributesToFetch(net.wotonomy.foundation.NSArray)
+ /*
+ * Sets the attributes to be fetched from the database.
+ *
+ * @see net.wotonomy.access.EOAdaptorChannel#setAttributesToFetch(net.wotonomy.
+ * foundation.NSArray)
*/
public void setAttributesToFetch(NSArray atts) {
_attsToFetch = atts;
}
- /* Returns an array with the attributes that will be fetched.
+ /*
+ * Returns an array with the attributes that will be fetched.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#attributesToFetch()
*/
public NSArray attributesToFetch() {
return _attsToFetch;
}
- /* Cancels the fetch, rolling back the transaction.
+ /*
+ * Cancels the fetch, rolling back the transaction.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#cancelFetch()
*/
public void cancelFetch() {
@@ -98,7 +106,9 @@ public class JDBCChannel extends EOAdaptorChannel {
}
}
- /* Closes the jdbc channel.
+ /*
+ * Closes the jdbc channel.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#closeChannel()
*/
public void closeChannel() {
@@ -111,9 +121,11 @@ public class JDBCChannel extends EOAdaptorChannel {
}
}
- /* If the fetch was done with an array of EOAttributes, returns
- * that same array; otherwise it creates an array of EOAttributes
- * based on the column names that will be fetched.
+ /*
+ * If the fetch was done with an array of EOAttributes, returns that same array;
+ * otherwise it creates an array of EOAttributes based on the column names that
+ * will be fetched.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#describeResults()
*/
public NSArray describeResults() {
@@ -134,7 +146,7 @@ public class JDBCChannel extends EOAdaptorChannel {
a.setAllowsNull(_rsmeta.isNullable(i) == ResultSetMetaData.columnNullable);
a.setWidth(_rsmeta.getColumnDisplaySize(i));
a.setReadOnly(_rsmeta.isReadOnly(i));
- attarr[i-1] = a;
+ attarr[i - 1] = a;
}
_resultAttributes = new NSArray(attarr);
} catch (SQLException ex) {
@@ -144,9 +156,12 @@ public class JDBCChannel extends EOAdaptorChannel {
return _resultAttributes;
}
- /* Deletes from the database the rows described by the qualifier,
- * in the specified entity.
- * @see net.wotonomy.access.EOAdaptorChannel#deleteRowsDescribedByQualifier(net.wotonomy.control.EOQualifier, net.wotonomy.access.EOEntity)
+ /*
+ * Deletes from the database the rows described by the qualifier, in the
+ * specified entity.
+ *
+ * @see net.wotonomy.access.EOAdaptorChannel#deleteRowsDescribedByQualifier(net.
+ * wotonomy.control.EOQualifier, net.wotonomy.access.EOEntity)
*/
public int deleteRowsDescribedByQualifier(EOQualifier q, EOEntity entity) {
EOSQLExpression exp = adaptorContext().adaptor().expressionFactory().createExpression(entity);
@@ -155,11 +170,14 @@ public class JDBCChannel extends EOAdaptorChannel {
return _resultCount;
}
- /* Creates a java.sql.Statement object and executes it.
- * If there is an open transaction, the statement is executed inside it;
- * otherwise a transaction is started, the statement executed, and
- * the transaction is committed.
- * @see net.wotonomy.access.EOAdaptorChannel#evaluateExpression(net.wotonomy.access.EOSQLExpression)
+ /*
+ * Creates a java.sql.Statement object and executes it. If there is an open
+ * transaction, the statement is executed inside it; otherwise a transaction is
+ * started, the statement executed, and the transaction is committed.
+ *
+ * @see
+ * net.wotonomy.access.EOAdaptorChannel#evaluateExpression(net.wotonomy.access.
+ * EOSQLExpression)
*/
public void evaluateExpression(EOSQLExpression sql) {
if (!isOpen())
@@ -173,20 +191,20 @@ public class JDBCChannel extends EOAdaptorChannel {
boolean isQuery = false;
String text = sql.statement();
try {
- //run an executeUpdate with these prefixes
+ // run an executeUpdate with these prefixes
if (text.startsWith("INSERT") || text.startsWith("DELETE") || text.startsWith("UPDATE")) {
conditionalBeginTransaction();
_resultCount = _statement.executeUpdate(text);
conditionalCommitTransaction();
return;
} else if (text.startsWith("SELECT")) {
- //run an executeQuery with SELECT
+ // run an executeQuery with SELECT
if (_resultCount > 0)
_statement.setMaxRows(_resultCount);
_resultSet = _statement.executeQuery(text);
_fetchInProgress = true;
return;
- } else { //just plain execute
+ } else { // just plain execute
conditionalBeginTransaction();
isQuery = _statement.execute(text);
}
@@ -207,80 +225,83 @@ public class JDBCChannel extends EOAdaptorChannel {
}
}
- /* Executes a stored procedure with the specified parameters.
- * Any results that the procedure returns should be obtained
- * by calling returnValuesForLastStoredProcedureInvocation.
- * @see net.wotonomy.access.EOAdaptorChannel#executeStoredProcedure(net.wotonomy.access.EOStoredProcedure, net.wotonomy.foundation.NSDictionary)
+ /*
+ * Executes a stored procedure with the specified parameters. Any results that
+ * the procedure returns should be obtained by calling
+ * returnValuesForLastStoredProcedureInvocation.
+ *
+ * @see
+ * net.wotonomy.access.EOAdaptorChannel#executeStoredProcedure(net.wotonomy.
+ * access.EOStoredProcedure, net.wotonomy.foundation.NSDictionary)
*/
- public void executeStoredProcedure(
- EOStoredProcedure proc, NSDictionary values) {
+ public void executeStoredProcedure(EOStoredProcedure proc, NSDictionary values) {
if (!isOpen())
throw new EOGeneralAdaptorException("Attempt to execute a stored procedure on a closed channel.");
conditionalBeginTransaction();
try {
- //Assemble the procedure call
+ // Assemble the procedure call
StringBuffer buf = new StringBuffer("{ call ");
buf.append(proc.externalName());
NSArray args = proc.arguments();
if (args != null && args.count() > 0) {
buf.append("[");
for (int i = 0; i < args.count(); i++) {
- EOAttribute a = (EOAttribute)args.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) args.objectAtIndex(i);
if (a.parameterDirection() != EOAttribute.OutParameter) {
buf.append('?');
buf.append(", ");
}
}
- buf.delete(buf.length()-2, buf.length());
+ buf.delete(buf.length() - 2, buf.length());
buf.append("]");
}
buf.append(" }");
- //get the callable statement
+ // get the callable statement
CallableStatement sp = _context().connection().prepareCall(buf.toString());
if (args != null && args.count() > 0) {
int pos = 1;
- //set the in and inOut parameters
+ // set the in and inOut parameters
for (int i = 0; i < args.count(); i++) {
- EOAttribute a = (EOAttribute)args.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) args.objectAtIndex(i);
if (a.parameterDirection() != EOAttribute.OutParameter) {
Object val = values.objectForKey(a.name());
if (val == NSKeyValueCoding.NullValue)
- sp.setNull(pos, 0); //TODO: check sql type
+ sp.setNull(pos, 0); // TODO: check sql type
if (val instanceof String)
- sp.setString(pos, (String)val);
+ sp.setString(pos, (String) val);
else if (val instanceof BigDecimal)
- sp.setBigDecimal(pos, (BigDecimal)val);
+ sp.setBigDecimal(pos, (BigDecimal) val);
else if (val instanceof NSTimestamp)
- sp.setTimestamp(pos, (NSTimestamp)val);
+ sp.setTimestamp(pos, (NSTimestamp) val);
else if (val instanceof NSData)
- sp.setBytes(pos, ((NSData)val).bytes());
+ sp.setBytes(pos, ((NSData) val).bytes());
else if (val instanceof Integer)
- sp.setInt(pos, ((Integer)val).intValue());
+ sp.setInt(pos, ((Integer) val).intValue());
else if (val instanceof Long)
- sp.setLong(pos, ((Long)val).longValue());
+ sp.setLong(pos, ((Long) val).longValue());
else
sp.setObject(pos, val);
pos++;
}
}
}
- //run the procedure
+ // run the procedure
sp.execute();
- //get the return values
+ // get the return values
if (args != null && args.count() > 0) {
int pos = 1;
NSMutableDictionary retvals = new NSMutableDictionary();
for (int i = 0; i < args.count(); i++) {
- EOAttribute a = (EOAttribute)args.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) args.objectAtIndex(i);
if (a.parameterDirection() != EOAttribute.InParameter) {
Object val = sp.getObject(pos);
if (val == null)
retvals.setObjectForKey(NSKeyValueCoding.NullValue, a.name());
else if (val instanceof Blob) {
try {
- retvals.setObjectForKey(new NSData(((Blob)val).getBinaryStream(), 1024), a.name());
+ retvals.setObjectForKey(new NSData(((Blob) val).getBinaryStream(), 1024), a.name());
} catch (java.io.IOException ex) {
- //what should I do here?
+ // what should I do here?
retvals.setObjectForKey(NSData.EmptyData, a.name());
}
} else
@@ -296,7 +317,9 @@ public class JDBCChannel extends EOAdaptorChannel {
conditionalCommitTransaction();
}
- /* Fetches one row from the database
+ /*
+ * Fetches one row from the database
+ *
* @see net.wotonomy.access.EOAdaptorChannel#fetchRow()
*/
public NSMutableDictionary fetchRow() {
@@ -306,7 +329,7 @@ public class JDBCChannel extends EOAdaptorChannel {
if (attributesToFetch() == null)
throw new EOGeneralAdaptorException("Attempt to fetchRow without setting attributes to fetch first.");
try {
- //If the current result set ends, there may be another one
+ // If the current result set ends, there may be another one
if (!_resultSet.next()) {
_resultSet.close();
_resultAttributes = null;
@@ -319,12 +342,12 @@ public class JDBCChannel extends EOAdaptorChannel {
throw new JDBCAdaptorException("While trying to fetch row.", ex);
}
- //Assemble the dictionary
+ // Assemble the dictionary
NSMutableDictionary dict = new NSMutableDictionary(attributesToFetch().count());
try {
for (int i = 0; i < attributesToFetch().count(); i++) {
- EOAttribute a = (EOAttribute)attributesToFetch().objectAtIndex(i);
- Object o = _resultSet.getObject(i+1);
+ EOAttribute a = (EOAttribute) attributesToFetch().objectAtIndex(i);
+ Object o = _resultSet.getObject(i + 1);
if (o == null)
o = NSKeyValueCoding.NullValue;
dict.setObjectForKey(o, a.name());
@@ -335,8 +358,11 @@ public class JDBCChannel extends EOAdaptorChannel {
return dict;
}
- /* Inserts a row into a table in the database.
- * @see net.wotonomy.access.EOAdaptorChannel#insertRow(net.wotonomy.foundation.NSDictionary, net.wotonomy.access.EOEntity)
+ /*
+ * Inserts a row into a table in the database.
+ *
+ * @see net.wotonomy.access.EOAdaptorChannel#insertRow(net.wotonomy.foundation.
+ * NSDictionary, net.wotonomy.access.EOEntity)
*/
public void insertRow(NSDictionary row, EOEntity entity) {
EOSQLExpression exp = adaptorContext().adaptor().expressionFactory().createExpression(entity);
@@ -344,15 +370,19 @@ public class JDBCChannel extends EOAdaptorChannel {
evaluateExpression(exp);
}
- /* Indicates if a fetch is in progress; that is, if a SELECT statement
- * was executed and there are still rows to be fetched.
+ /*
+ * Indicates if a fetch is in progress; that is, if a SELECT statement was
+ * executed and there are still rows to be fetched.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#isFetchInProgress()
*/
public boolean isFetchInProgress() {
return _fetchInProgress;
}
- /* Indicates if the channel is open.
+ /*
+ * Indicates if the channel is open.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#isOpen()
*/
public boolean isOpen() {
@@ -365,9 +395,10 @@ public class JDBCChannel extends EOAdaptorChannel {
return open;
}
- /* Opens the channel. If the adaptor context has not yet made
- * a connection to the database, this forces the context to
- * connect.
+ /*
+ * Opens the channel. If the adaptor context has not yet made a connection to
+ * the database, this forces the context to connect.
+ *
* @see net.wotonomy.access.EOAdaptorChannel#openChannel()
*/
public void openChannel() {
@@ -379,36 +410,46 @@ public class JDBCChannel extends EOAdaptorChannel {
}
}
- /* Returns the values obtained from the last stored procedure executed.
- * @see net.wotonomy.access.EOAdaptorChannel#returnValuesForLastStoredProcedureInvocation()
+ /*
+ * Returns the values obtained from the last stored procedure executed.
+ *
+ * @see net.wotonomy.access.EOAdaptorChannel#
+ * returnValuesForLastStoredProcedureInvocation()
*/
public NSDictionary returnValuesForLastStoredProcedureInvocation() {
return _spReturnValues;
}
- /* Creates a SELECT expression and executes it. If the attribute array is null,
- * then the result's metadata is used to dynamically create an array
- * of attributes.
- * @see net.wotonomy.access.EOAdaptorChannel#selectAttributes(net.wotonomy.foundation.NSArray, net.wotonomy.control.EOFetchSpecification, boolean, net.wotonomy.access.EOEntity)
+ /*
+ * Creates a SELECT expression and executes it. If the attribute array is null,
+ * then the result's metadata is used to dynamically create an array of
+ * attributes.
+ *
+ * @see
+ * net.wotonomy.access.EOAdaptorChannel#selectAttributes(net.wotonomy.foundation
+ * .NSArray, net.wotonomy.control.EOFetchSpecification, boolean,
+ * net.wotonomy.access.EOEntity)
*/
- public void selectAttributes(
- NSArray atts, EOFetchSpecification fspec,
- boolean lock, EOEntity entity) {
+ public void selectAttributes(NSArray atts, EOFetchSpecification fspec, boolean lock, EOEntity entity) {
_resultAttributes = atts;
EOSQLExpression expr = adaptorContext().adaptor().expressionFactory().createExpression(entity);
_fetchInProgress = true;
expr.prepareSelectExpressionWithAttributes(atts, lock, fspec);
- //for now we store the fetch limit here
+ // for now we store the fetch limit here
if (fspec != null)
_resultCount = fspec.fetchLimit();
evaluateExpression(expr);
}
- /* Creates and executes an UPDATE statement.
- * @see net.wotonomy.access.EOAdaptorChannel#updateValuesInRowsDescribedByQualifier(net.wotonomy.foundation.NSDictionary, net.wotonomy.control.EOQualifier, net.wotonomy.access.EOEntity)
+ /*
+ * Creates and executes an UPDATE statement.
+ *
+ * @see
+ * net.wotonomy.access.EOAdaptorChannel#updateValuesInRowsDescribedByQualifier(
+ * net.wotonomy.foundation.NSDictionary, net.wotonomy.control.EOQualifier,
+ * net.wotonomy.access.EOEntity)
*/
- public int updateValuesInRowsDescribedByQualifier(
- NSDictionary row, EOQualifier q, EOEntity entity) {
+ public int updateValuesInRowsDescribedByQualifier(NSDictionary row, EOQualifier q, EOEntity entity) {
EOSQLExpression exp = adaptorContext().adaptor().expressionFactory().createExpression(entity);
exp.prepareUpdateExpressionWithRow(row, q);
evaluateExpression(exp);
@@ -429,21 +470,18 @@ public class JDBCChannel extends EOAdaptorChannel {
}
/*
-* $Log$
-* Revision 1.2 2006/02/18 22:59:22 cgruber
-* make it compile with maven dependencies and add a cvsignore.
-*
-* Revision 1.1 2006/02/16 13:22:23 cgruber
-* Check in all sources in eclipse-friendly maven-enabled packages.
-*
-* Revision 1.3 2003/08/14 02:15:11 chochos
-* added lots of comments
-*
-* Revision 1.2 2003/08/13 20:45:20 chochos
-* small fixes in evaluateExpression, which has been successfully tested with a SELECT statement.
-*
-* Revision 1.1 2003/08/13 20:12:48 chochos
-* a subclass of EOAdaptorChannel to be used with JDBC.
-*
-*/
-
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
+ *
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.3 2003/08/14 02:15:11 chochos added lots of comments
+ *
+ * Revision 1.2 2003/08/13 20:45:20 chochos small fixes in evaluateExpression,
+ * which has been successfully tested with a SELECT statement.
+ *
+ * Revision 1.1 2003/08/13 20:12:48 chochos a subclass of EOAdaptorChannel to be
+ * used with JDBC.
+ *
+ */
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java
index 445ffb5..9e6df6c 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java
@@ -27,18 +27,19 @@ import net.wotonomy.access.EOAdaptorChannel;
import net.wotonomy.access.EOAdaptorContext;
/**
-* Concrete implementation of EOAdaptorContext for use with JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * Concrete implementation of EOAdaptorContext for use with JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCContext extends EOAdaptorContext {
protected Connection _jdbcConnection;
/**
* Creates a new instance.
+ *
* @param adaptor The adaptor this context belongs to.
*/
public JDBCContext(EOAdaptor adaptor) {
@@ -49,12 +50,12 @@ public class JDBCContext extends EOAdaptorContext {
try {
if (_jdbcConnection != null && !_jdbcConnection.isClosed())
throw new JDBCAdaptorException("Attempt to connect when already connected.", null);
- Class.forName(((JDBCAdaptor)adaptor()).driverName());
- String url = (String)adaptor().connectionDictionary().objectForKey("URL");
+ Class.forName(((JDBCAdaptor) adaptor()).driverName());
+ String url = (String) adaptor().connectionDictionary().objectForKey("URL");
Driver driver = DriverManager.getDriver(url);
java.util.Properties props = new java.util.Properties();
- props.setProperty("user", (String)adaptor().connectionDictionary().objectForKey("username"));
- props.setProperty("password", (String)adaptor().connectionDictionary().objectForKey("password"));
+ props.setProperty("user", (String) adaptor().connectionDictionary().objectForKey("username"));
+ props.setProperty("password", (String) adaptor().connectionDictionary().objectForKey("password"));
_jdbcConnection = driver.connect(url, props);
_jdbcConnection.setAutoCommit(false);
} catch (SQLException ex) {
@@ -80,8 +81,9 @@ public class JDBCContext extends EOAdaptorContext {
return _jdbcConnection;
}
- /* Begins a transaction. Actually it does nothing because it's not
- * necessary.
+ /*
+ * Begins a transaction. Actually it does nothing because it's not necessary.
+ *
* @see net.wotonomy.access.EOAdaptorContext#beginTransaction()
*/
public void beginTransaction() {
@@ -90,7 +92,9 @@ public class JDBCContext extends EOAdaptorContext {
transactionDidBegin();
}
- /* Commits a transaction.
+ /*
+ * Commits a transaction.
+ *
* @see net.wotonomy.access.EOAdaptorContext#commitTransaction()
*/
public void commitTransaction() {
@@ -102,7 +106,9 @@ public class JDBCContext extends EOAdaptorContext {
}
}
- /* Rolls back a transacion.
+ /*
+ * Rolls back a transacion.
+ *
* @see net.wotonomy.access.EOAdaptorContext#rollbackTransaction()
*/
public void rollbackTransaction() {
@@ -114,7 +120,9 @@ public class JDBCContext extends EOAdaptorContext {
}
}
- /* Creates a JDBCChannel instance.
+ /*
+ * Creates a JDBCChannel instance.
+ *
* @see net.wotonomy.access.EOAdaptorContext#createAdaptorChannel()
*/
public EOAdaptorChannel createAdaptorChannel() {
@@ -123,7 +131,9 @@ public class JDBCContext extends EOAdaptorContext {
return channel;
}
- /* I don't know what to do here. Throw something, maybe?
+ /*
+ * I don't know what to do here. Throw something, maybe?
+ *
* @see net.wotonomy.access.EOAdaptorContext#handleDroppedConnection()
*/
public void handleDroppedConnection() {
@@ -133,14 +143,14 @@ public class JDBCContext extends EOAdaptorContext {
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 22:59:22 cgruber
- * make it compile with maven dependencies and add a cvsignore.
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 20:13:33 chochos
- * concrete implementation of EOAdaptorContext for use with JDBC. This is the class that holds the physical connection to the database.
+ * Revision 1.1 2003/08/13 20:13:33 chochos concrete implementation of
+ * EOAdaptorContext for use with JDBC. This is the class that holds the physical
+ * connection to the database.
*
*/
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpression.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpression.java
index 2258a65..97e3352 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpression.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpression.java
@@ -23,14 +23,13 @@ import net.wotonomy.access.EOSQLExpression;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
-
/**
-* Concrete implementation of EOSQLExpression for use with JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * Concrete implementation of EOSQLExpression for use with JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCExpression extends EOSQLExpression {
protected NSDictionary _jdbcInfo;
@@ -45,29 +44,32 @@ public class JDBCExpression extends EOSQLExpression {
public void setJdbcInfo(NSDictionary info) {
_jdbcInfo = info;
}
+
public NSDictionary jdbcInfo() {
return _jdbcInfo;
}
- /* (non-Javadoc)
- * @see net.wotonomy.access.EOSQLExpression#bindVariableDictionaryForAttribute(net.wotonomy.access.EOAttribute, java.lang.Object)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.access.EOSQLExpression#bindVariableDictionaryForAttribute(net.
+ * wotonomy.access.EOAttribute, java.lang.Object)
*/
- public NSMutableDictionary bindVariableDictionaryForAttribute(
- EOAttribute attr, Object variable) {
+ public NSMutableDictionary bindVariableDictionaryForAttribute(EOAttribute attr, Object variable) {
// TODO Auto-generated method stub
return null;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 22:59:22 cgruber
- * make it compile with maven dependencies and add a cvsignore.
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 20:14:38 chochos
- * subclass of EOSQLExpression. Still needs a lot of work for bindings, mostly.
+ * Revision 1.1 2003/08/13 20:14:38 chochos subclass of EOSQLExpression. Still
+ * needs a lot of work for bindings, mostly.
*
*/
diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpressionFactory.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpressionFactory.java
index 15c167f..6f51181 100644
--- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpressionFactory.java
+++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCExpressionFactory.java
@@ -23,25 +23,25 @@ import net.wotonomy.access.EOSQLExpression;
import net.wotonomy.access.EOSQLExpressionFactory;
import net.wotonomy.foundation.NSDictionary;
-
/**
-* Concrete implementation of EOSQLExpressionFactory for use with JDBC.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 903 $
-*/
+ * Concrete implementation of EOSQLExpressionFactory for use with JDBC.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 903 $
+ */
public class JDBCExpressionFactory extends EOSQLExpressionFactory {
protected NSDictionary _jdbcInfo;
/**
* Creates a new instance.
+ *
* @param adaptor The adaptor for this factory.
*/
public JDBCExpressionFactory(EOAdaptor adaptor) {
super(adaptor);
- _jdbcInfo = ((JDBCAdaptor)adaptor()).jdbcInfo();
+ _jdbcInfo = ((JDBCAdaptor) adaptor()).jdbcInfo();
}
public EOSQLExpression createExpression(EOEntity entity) {
@@ -52,14 +52,13 @@ public class JDBCExpressionFactory extends EOSQLExpressionFactory {
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 22:59:22 cgruber
- * make it compile with maven dependencies and add a cvsignore.
+ * $Log$ Revision 1.2 2006/02/18 22:59:22 cgruber make it compile with maven
+ * dependencies and add a cvsignore.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 20:15:05 chochos
- * the subclass of EOSQLExpressionFactory to be used with JDBC.
+ * Revision 1.1 2003/08/13 20:15:05 chochos the subclass of
+ * EOSQLExpressionFactory to be used with JDBC.
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessArrayFaultHandler.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessArrayFaultHandler.java
index 1aafa13..ebb8199 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessArrayFaultHandler.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessArrayFaultHandler.java
@@ -21,25 +21,31 @@ import net.wotonomy.control.EOEditingContext;
import net.wotonomy.control.EOKeyGlobalID;
/**
-* A fault handler for to-many relationships.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/public class EOAccessArrayFaultHandler extends EOAccessGenericFaultHandler {
+ * A fault handler for to-many relationships.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOAccessArrayFaultHandler extends EOAccessGenericFaultHandler {
protected EOKeyGlobalID _sourceID;
protected String _relation;
- public EOAccessArrayFaultHandler(EOKeyGlobalID sourceID, String relationName, EODatabaseContext dbc, EOEditingContext ec) {
+ public EOAccessArrayFaultHandler(EOKeyGlobalID sourceID, String relationName, EODatabaseContext dbc,
+ EOEditingContext ec) {
super();
_sourceID = sourceID;
_relation = relationName;
setContext(dbc, ec);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOFaultHandler#completeInitializationOfObject(java.lang.Object)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOFaultHandler#completeInitializationOfObject(java.lang.
+ * Object)
*/
public void completeInitializationOfObject(Object obj) {
// TODO Auto-generated method stub
@@ -56,16 +62,16 @@ import net.wotonomy.control.EOKeyGlobalID;
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/19 19:53:20 chochos
- * EOAccess fault handlers (still incomplete)
+ * Revision 1.1 2003/08/19 19:53:20 chochos EOAccess fault handlers (still
+ * incomplete)
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessFaultHandler.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessFaultHandler.java
index d4cabe9..0690295 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessFaultHandler.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessFaultHandler.java
@@ -21,13 +21,14 @@ import net.wotonomy.control.EOEditingContext;
import net.wotonomy.control.EOKeyGlobalID;
/**
-* A fault handler for single objects. Usually the destinations of a
-* to-one relationship.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/public class EOAccessFaultHandler extends EOAccessGenericFaultHandler {
+ * A fault handler for single objects. Usually the destinations of a to-one
+ * relationship.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOAccessFaultHandler extends EOAccessGenericFaultHandler {
protected EOKeyGlobalID _gid;
@@ -37,8 +38,12 @@ import net.wotonomy.control.EOKeyGlobalID;
setContext(dbc, ec);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOFaultHandler#completeInitializationOfObject(java.lang.Object)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOFaultHandler#completeInitializationOfObject(java.lang.
+ * Object)
*/
public void completeInitializationOfObject(Object obj) {
// TODO Auto-generated method stub
@@ -51,16 +56,16 @@ import net.wotonomy.control.EOKeyGlobalID;
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/19 19:53:20 chochos
- * EOAccess fault handlers (still incomplete)
+ * Revision 1.1 2003/08/19 19:53:20 chochos EOAccess fault handlers (still
+ * incomplete)
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessGenericFaultHandler.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessGenericFaultHandler.java
index 6876151..31378f4 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessGenericFaultHandler.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessGenericFaultHandler.java
@@ -21,12 +21,12 @@ import net.wotonomy.control.EOEditingContext;
import net.wotonomy.control.EOFaultHandler;
/**
-* A generic fault handler for EOAccess.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * A generic fault handler for EOAccess.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public abstract class EOAccessGenericFaultHandler extends EOFaultHandler {
protected EODatabaseContext _dbContext;
@@ -36,7 +36,9 @@ public abstract class EOAccessGenericFaultHandler extends EOFaultHandler {
super();
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOFaultHandler#faultWillFire(java.lang.Object)
*/
public void faultWillFire(Object obj) {
@@ -59,17 +61,16 @@ public abstract class EOAccessGenericFaultHandler extends EOFaultHandler {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/19 19:53:20 chochos
- * EOAccess fault handlers (still incomplete)
+ * Revision 1.1 2003/08/19 19:53:20 chochos EOAccess fault handlers (still
+ * incomplete)
*
*/
- \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessLock.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessLock.java
index 28199c5..f305579 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessLock.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAccessLock.java
@@ -20,8 +20,8 @@ package net.wotonomy.access;
import net.wotonomy.foundation.NSRecursiveLock;
/**
- * This class offers a very simple interface to a global locking
- * mechanism to be used by the whole access layer.
+ * This class offers a very simple interface to a global locking mechanism to be
+ * used by the whole access layer.
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -45,16 +45,15 @@ public class EOAccessLock {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/29 20:43:25 chochos
- * a global access layer lock
+ * Revision 1.1 2003/08/29 20:43:25 chochos a global access layer lock
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptor.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptor.java
index 28295d1..17d6454 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptor.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptor.java
@@ -26,11 +26,11 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSTimestamp;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public abstract class EOAdaptor {
@@ -48,6 +48,7 @@ public abstract class EOAdaptor {
/**
* Creates an adaptor with model's adaptorName and sets its connection
* dictionary to the model's connection dictionary.
+ *
* @param model The model to take adaptorName and connectionDictionary from.
* @return The adaptor specified in model.
*/
@@ -64,11 +65,13 @@ public abstract class EOAdaptor {
}
/**
- * Instantiates an adaptor of a concrete EOAdaptor subclass, based on name.
- * If name is a fully qualified class name, then it returns an instance of that class
- * by invoking the constructor with a string argument. Otherwise, it
- * tries to find a class called (name)Adaptor in a package called
- * net.wotonomy.(lowercase name)adaptor; if it can't find one, an exception is raised.
+ * Instantiates an adaptor of a concrete EOAdaptor subclass, based on name. If
+ * name is a fully qualified class name, then it returns an instance of that
+ * class by invoking the constructor with a string argument. Otherwise, it tries
+ * to find a class called (name)Adaptor in a package called
+ * net.wotonomy.(lowercase name)adaptor; if it can't find one, an exception is
+ * raised.
+ *
* @param name The name of the adaptor, or a fully qualified class name.
* @return
*/
@@ -78,10 +81,10 @@ public abstract class EOAdaptor {
if (name.endsWith("Adaptor") && name.indexOf('.') > 0) {
cname = name;
int lastdot = name.lastIndexOf('.');
- //take off the package and the 'Adaptor' suffix
+ // take off the package and the 'Adaptor' suffix
name = cname.substring(lastdot, cname.length() - 7);
} else {
- //construct the fully qualified class name
+ // construct the fully qualified class name
cname = "net.wotonomy." + name.toLowerCase() + "adaptor." + name + "Adaptor";
}
try {
@@ -92,12 +95,14 @@ public abstract class EOAdaptor {
EOAdaptor adaptor = null;
java.lang.reflect.Constructor callme = null;
try {
- callme = adaptorClass.getConstructor(new Class[]{ String.class });
- adaptor = (EOAdaptor)callme.newInstance((Object[])new String[]{ name });
+ callme = adaptorClass.getConstructor(new Class[] { String.class });
+ adaptor = (EOAdaptor) callme.newInstance((Object[]) new String[] { name });
} catch (ClassCastException ex) {
- throw new IllegalArgumentException("Class " + adaptorClass.getName() + " must inherit from net.wotonomy.access.EOAdaptor");
- }catch (Exception ex) {
- throw new IllegalArgumentException("Cannot find or invoke constructor with name argument in class " + adaptorClass.getName());
+ throw new IllegalArgumentException(
+ "Class " + adaptorClass.getName() + " must inherit from net.wotonomy.access.EOAdaptor");
+ } catch (Exception ex) {
+ throw new IllegalArgumentException(
+ "Cannot find or invoke constructor with name argument in class " + adaptorClass.getName());
}
return adaptor;
}
@@ -105,8 +110,9 @@ public abstract class EOAdaptor {
public static void setExpressionClassName(String expClassName, String adaptorClassName) {
_expressionClassesByName.setObjectForKey(expClassName, adaptorClassName);
}
+
public static String expressionClassName(String adaptorClassName) {
- return (String)_expressionClassesByName.objectForKey(adaptorClassName);
+ return (String) _expressionClassesByName.objectForKey(adaptorClassName);
}
public void assignExternalInfoForAttribute(EOAttribute attribute) {
@@ -126,11 +132,11 @@ public abstract class EOAdaptor {
public void assignExternalInfoForEntireModel(EOModel model) {
NSArray ents = model.entities();
for (int i = 0; i < ents.count(); i++) {
- EOEntity e = (EOEntity)ents.objectAtIndex(i);
- //TODO: check that entity is not a prototypes entity
+ EOEntity e = (EOEntity) ents.objectAtIndex(i);
+ // TODO: check that entity is not a prototypes entity
NSArray atts = e.attributes();
for (int j = 0; j < atts.count(); j++) {
- EOAttribute a = (EOAttribute)atts.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) atts.objectAtIndex(i);
assignExternalInfoForAttribute(a);
}
assignExternalInfoForEntity(e);
@@ -149,6 +155,7 @@ public abstract class EOAdaptor {
public void setConnectionDictionary(NSDictionary connection) {
_connectionDictionary = connection;
}
+
public NSDictionary connectionDictionary() {
return _connectionDictionary;
}
@@ -205,19 +212,19 @@ public abstract class EOAdaptor {
if (value == NSKeyValueCoding.NullValue)
return value;
if (value instanceof String)
- return fetchedValueForStringValue((String)value, attr);
+ return fetchedValueForStringValue((String) value, attr);
if (value instanceof NSData)
- return fetchedValueForDataValue((NSData)value, attr);
+ return fetchedValueForDataValue((NSData) value, attr);
if (value instanceof Number)
- return fetchedValueForNumberValue((Number)value, attr);
+ return fetchedValueForNumberValue((Number) value, attr);
if (value instanceof NSTimestamp)
- return fetchedValueForDateValue((NSTimestamp)value, attr);
+ return fetchedValueForDateValue((NSTimestamp) value, attr);
return value;
}
public void handleDroppedConnection() {
for (int i = 0; i < _contexts.count(); i++) {
- EOAdaptorContext c = (EOAdaptorContext)_contexts.objectAtIndex(i);
+ EOAdaptorContext c = (EOAdaptorContext) _contexts.objectAtIndex(i);
c.transactionDidRollback();
c.handleDroppedConnection();
}
@@ -226,7 +233,7 @@ public abstract class EOAdaptor {
public boolean hasOpenChannels() {
for (int i = 0; i < _contexts.count(); i++) {
- EOAdaptorContext c = (EOAdaptorContext)_contexts.objectAtIndex(i);
+ EOAdaptorContext c = (EOAdaptorContext) _contexts.objectAtIndex(i);
if (c.hasOpenChannels())
return true;
}
@@ -251,19 +258,19 @@ public abstract class EOAdaptor {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2005/12/08 06:52:32 cgruber
- * Move tests, improve build.xml, and make certain casts explicit so that Java 1.5 doesn't complain about varargs.
+ * Revision 1.2 2005/12/08 06:52:32 cgruber Move tests, improve build.xml, and
+ * make certain casts explicit so that Java 1.5 doesn't complain about varargs.
*
- * Revision 1.1 2003/08/13 00:37:45 chochos
- * an almost complete implementation of the abstract adaptor-layer classes
+ * Revision 1.1 2003/08/13 00:37:45 chochos an almost complete implementation of
+ * the abstract adaptor-layer classes
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorChannel.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorChannel.java
index 09b8a6d..44b3401 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorChannel.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorChannel.java
@@ -24,11 +24,11 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public abstract class EOAdaptorChannel {
protected EOAdaptorContext _context;
@@ -102,7 +102,7 @@ public abstract class EOAdaptorChannel {
public NSMutableDictionary dictionaryWithObjectsForAttributes(Object[] values, NSArray attributes) {
Object[] keys = new Object[attributes.count()];
for (int i = 0; i < attributes.count(); i++)
- keys[i] = ((EOAttribute)attributes.objectAtIndex(i)).name();
+ keys[i] = ((EOAttribute) attributes.objectAtIndex(i)).name();
return new NSMutableDictionary(values, keys);
}
@@ -150,57 +150,60 @@ public abstract class EOAdaptorChannel {
public void performAdaptorOperation(EOAdaptorOperation operation) {
int opcode = operation.adaptorOperator();
switch (opcode) {
- case EODatabaseOperation.AdaptorLockOperator:
- if (operation.entity() == null)
- throw new EOGeneralAdaptorException("A lock operation must have an entity assigned to it.",
+ case EODatabaseOperation.AdaptorLockOperator:
+ if (operation.entity() == null)
+ throw new EOGeneralAdaptorException("A lock operation must have an entity assigned to it.",
new NSDictionary(operation, "operation"));
- if (operation.qualifier() == null)
- throw new EOGeneralAdaptorException("A lock operation must have a qualifier assigned to it.",
+ if (operation.qualifier() == null)
+ throw new EOGeneralAdaptorException("A lock operation must have a qualifier assigned to it.",
new NSDictionary(operation, "operation"));
- if (operation.qualifier() == null)
- throw new EOGeneralAdaptorException("A lock operation must have changedValues assigned to it.",
+ if (operation.qualifier() == null)
+ throw new EOGeneralAdaptorException("A lock operation must have changedValues assigned to it.",
new NSDictionary(operation, "operation"));
- lockRowComparingAttributes(operation.attributes(), operation.entity(), operation.qualifier(), operation.changedValues());
- break;
- case EODatabaseOperation.AdaptorInsertOperator:
- if (operation.entity() == null)
- throw new EOGeneralAdaptorException("An insert operation must have an entity assigned to it.",
+ lockRowComparingAttributes(operation.attributes(), operation.entity(), operation.qualifier(),
+ operation.changedValues());
+ break;
+ case EODatabaseOperation.AdaptorInsertOperator:
+ if (operation.entity() == null)
+ throw new EOGeneralAdaptorException("An insert operation must have an entity assigned to it.",
new NSDictionary(operation, "operation"));
- if (operation.changedValues() == null)
- throw new EOGeneralAdaptorException("An insert operation must have changedValues assigned to it.",
+ if (operation.changedValues() == null)
+ throw new EOGeneralAdaptorException("An insert operation must have changedValues assigned to it.",
new NSDictionary(operation, "operation"));
- insertRow(operation.changedValues(), operation.entity());
- break;
- case EODatabaseOperation.AdaptorUpdateOperator:
- if (operation.entity() == null)
- throw new EOGeneralAdaptorException("An update operation must have an entity assigned to it.",
+ insertRow(operation.changedValues(), operation.entity());
+ break;
+ case EODatabaseOperation.AdaptorUpdateOperator:
+ if (operation.entity() == null)
+ throw new EOGeneralAdaptorException("An update operation must have an entity assigned to it.",
new NSDictionary(operation, "operation"));
- if (operation.changedValues() == null)
- throw new EOGeneralAdaptorException("An update operation must have changedValues assigned to it.",
+ if (operation.changedValues() == null)
+ throw new EOGeneralAdaptorException("An update operation must have changedValues assigned to it.",
new NSDictionary(operation, "operation"));
- updateValuesInRowsDescribedByQualifier(operation.changedValues(), operation.qualifier(), operation.entity());
- break;
- case EODatabaseOperation.AdaptorDeleteOperator:
- if (operation.entity() == null)
- throw new EOGeneralAdaptorException("A delete operation must have an entity assigned to it.",
+ updateValuesInRowsDescribedByQualifier(operation.changedValues(), operation.qualifier(),
+ operation.entity());
+ break;
+ case EODatabaseOperation.AdaptorDeleteOperator:
+ if (operation.entity() == null)
+ throw new EOGeneralAdaptorException("A delete operation must have an entity assigned to it.",
new NSDictionary(operation, "operation"));
- deleteRowsDescribedByQualifier(operation.qualifier(), operation.entity());
- break;
- case EODatabaseOperation.AdaptorStoredProcedureOperator:
- if (operation.storedProcedure() == null)
- throw new EOGeneralAdaptorException("A stored procedure operation must have a stored procedure assigned to it.",
+ deleteRowsDescribedByQualifier(operation.qualifier(), operation.entity());
+ break;
+ case EODatabaseOperation.AdaptorStoredProcedureOperator:
+ if (operation.storedProcedure() == null)
+ throw new EOGeneralAdaptorException(
+ "A stored procedure operation must have a stored procedure assigned to it.",
new NSDictionary(operation, "operation"));
- executeStoredProcedure(operation.storedProcedure(), operation.changedValues());
- break;
- default:
- throw new EOGeneralAdaptorException("I don't know how to perform an operation with code " + opcode,
+ executeStoredProcedure(operation.storedProcedure(), operation.changedValues());
+ break;
+ default:
+ throw new EOGeneralAdaptorException("I don't know how to perform an operation with code " + opcode,
new NSDictionary(operation, "operation"));
}
}
public void performAdaptorOperations(NSArray ops) {
for (int i = 0; i < ops.count(); i++) {
- EOAdaptorOperation adop = (EOAdaptorOperation)ops.objectAtIndex(i);
+ EOAdaptorOperation adop = (EOAdaptorOperation) ops.objectAtIndex(i);
performAdaptorOperation(adop);
}
}
@@ -217,28 +220,29 @@ public abstract class EOAdaptorChannel {
int count = updateValuesInRowsDescribedByQualifier(row, q, entity);
if (count != 1) {
adaptorContext().rollbackTransaction();
- throw new EOGeneralAdaptorException("The qualifier should describe exactly one row (updated " + count + " rows)");
+ throw new EOGeneralAdaptorException(
+ "The qualifier should describe exactly one row (updated " + count + " rows)");
}
adaptorContext().commitTransaction();
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.2 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.1 2003/08/13 00:37:45 chochos
- * an almost complete implementation of the abstract adaptor-layer classes
+ * Revision 1.1 2003/08/13 00:37:45 chochos an almost complete implementation of
+ * the abstract adaptor-layer classes
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorContext.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorContext.java
index aff0ddd..35a1468 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorContext.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorContext.java
@@ -22,11 +22,11 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSNotificationCenter;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public abstract class EOAdaptorContext {
@@ -63,7 +63,7 @@ public abstract class EOAdaptorContext {
public boolean hasBusyChannels() {
for (int i = 0; i < _channels.count(); i++) {
- EOAdaptorChannel chan = (EOAdaptorChannel)_channels.objectAtIndex(i);
+ EOAdaptorChannel chan = (EOAdaptorChannel) _channels.objectAtIndex(i);
if (chan.isFetchInProgress())
return true;
}
@@ -72,7 +72,7 @@ public abstract class EOAdaptorContext {
public boolean hasOpenChannels() {
for (int i = 0; i < _channels.count(); i++) {
- EOAdaptorChannel chan = (EOAdaptorChannel)_channels.objectAtIndex(i);
+ EOAdaptorChannel chan = (EOAdaptorChannel) _channels.objectAtIndex(i);
if (chan.isOpen())
return true;
}
@@ -85,34 +85,31 @@ public abstract class EOAdaptorContext {
public void transactionDidBegin() {
_hasOpenTransaction = true;
- NSNotificationCenter.defaultCenter().postNotification(
- AdaptorContextBeginTransactionNotification, this);
+ NSNotificationCenter.defaultCenter().postNotification(AdaptorContextBeginTransactionNotification, this);
}
public void transactionDidCommit() {
_hasOpenTransaction = false;
- NSNotificationCenter.defaultCenter().postNotification(
- AdaptorContextCommitTransactionNotification, this);
+ NSNotificationCenter.defaultCenter().postNotification(AdaptorContextCommitTransactionNotification, this);
}
public void transactionDidRollback() {
_hasOpenTransaction = false;
- NSNotificationCenter.defaultCenter().postNotification(
- AdaptorContextRollbackTransactionNotification, this);
+ NSNotificationCenter.defaultCenter().postNotification(AdaptorContextRollbackTransactionNotification, this);
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 00:37:45 chochos
- * an almost complete implementation of the abstract adaptor-layer classes
+ * Revision 1.1 2003/08/13 00:37:45 chochos an almost complete implementation of
+ * the abstract adaptor-layer classes
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorOperation.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorOperation.java
index 818985d..6c977b9 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorOperation.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAdaptorOperation.java
@@ -22,14 +22,13 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* Represents a single primitive operation in a database server.
-* Can be insert, update, delete, lock a row, or execute a
-* stored procedure.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * Represents a single primitive operation in a database server. Can be insert,
+ * update, delete, lock a row, or execute a stored procedure.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOAdaptorOperation {
protected EOEntity _entity;
@@ -48,6 +47,7 @@ public class EOAdaptorOperation {
public void setAdaptorOperator(int adOp) {
_adaptorOp = adOp;
}
+
public int adaptorOperator() {
return _adaptorOp;
}
@@ -55,6 +55,7 @@ public class EOAdaptorOperation {
public void setAttributes(NSArray atts) {
_attributes = atts;
}
+
public NSArray attributes() {
return _attributes;
}
@@ -62,6 +63,7 @@ public class EOAdaptorOperation {
public void setChangedValues(NSDictionary values) {
_changedValues = values;
}
+
public NSDictionary changedValues() {
return _changedValues;
}
@@ -85,6 +87,7 @@ public class EOAdaptorOperation {
public void setException(Throwable t) {
_exception = t;
}
+
public Throwable exception() {
return _exception;
}
@@ -92,6 +95,7 @@ public class EOAdaptorOperation {
public void setQualifier(EOQualifier q) {
_qualifier = q;
}
+
public EOQualifier qualifier() {
return _qualifier;
}
@@ -99,22 +103,23 @@ public class EOAdaptorOperation {
public void setStoredProcedure(EOStoredProcedure sp) {
_proc = sp;
}
+
public EOStoredProcedure storedProcedure() {
return _proc;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 00:37:45 chochos
- * an almost complete implementation of the abstract adaptor-layer classes
+ * Revision 1.1 2003/08/13 00:37:45 chochos an almost complete implementation of
+ * the abstract adaptor-layer classes
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAttribute.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAttribute.java
index 8b651ec..d77a162 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAttribute.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOAttribute.java
@@ -22,18 +22,18 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSSelector;
/**
-* Represents an attribute inside an entity. Contains mapping data for
-* the attribute's external name, external and internal datatypes, etc.
-* It can also represent a flattened or derived attribute, or a prototype;
-* and they are also used to represent parameters in a stored procedure.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * Represents an attribute inside an entity. Contains mapping data for the
+ * attribute's external name, external and internal datatypes, etc. It can also
+ * represent a flattened or derived attribute, or a prototype; and they are also
+ * used to represent parameters in a stored procedure.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
- //These are used for stored procedure parameters.
+ // These are used for stored procedure parameters.
public static final int Void = 0;
public static final int InParameter = 1;
public static final int OutParameter = 2;
@@ -75,26 +75,26 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public EOAttribute(NSDictionary dict, Object obj) {
super();
if (obj instanceof EOEntity)
- _entity = (EOEntity)obj;
- setName((String)dict.objectForKey("name"));
+ _entity = (EOEntity) obj;
+ setName((String) dict.objectForKey("name"));
if (dict.objectForKey("columnName") != null)
- setColumnName((String)dict.objectForKey("columnName"));
+ setColumnName((String) dict.objectForKey("columnName"));
if (dict.objectForKey("definition") != null)
- setDefinition((String)dict.objectForKey("definition"));
- _prototypeName = (String)dict.objectForKey("prototypeName");
- setExternalType((String)dict.objectForKey("externalType"));
- setClassName((String)dict.objectForKey("valueClassName"));
- setValueType((String)dict.objectForKey("valueType"));
- _writeFormat = (String)dict.objectForKey("writeFormat");
- _readFormat = (String)dict.objectForKey("readFormat");
+ setDefinition((String) dict.objectForKey("definition"));
+ _prototypeName = (String) dict.objectForKey("prototypeName");
+ setExternalType((String) dict.objectForKey("externalType"));
+ setClassName((String) dict.objectForKey("valueClassName"));
+ setValueType((String) dict.objectForKey("valueType"));
+ _writeFormat = (String) dict.objectForKey("writeFormat");
+ _readFormat = (String) dict.objectForKey("readFormat");
if (dict.objectForKey("precision") != null)
- setPrecision(Integer.parseInt((String)dict.objectForKey("precision")));
+ setPrecision(Integer.parseInt((String) dict.objectForKey("precision")));
if (dict.objectForKey("scale") != null)
- setScale(Integer.parseInt((String)dict.objectForKey("scale")));
+ setScale(Integer.parseInt((String) dict.objectForKey("scale")));
if (dict.objectForKey("width") != null)
- setWidth(Integer.parseInt((String)dict.objectForKey("width")));
+ setWidth(Integer.parseInt((String) dict.objectForKey("width")));
if (dict.objectForKey("parameterDirection") != null)
- setParameterDirection(Integer.parseInt((String)dict.objectForKey("parameterDirection")));
+ setParameterDirection(Integer.parseInt((String) dict.objectForKey("parameterDirection")));
setAllowsNull("Y".equals(dict.objectForKey("allowsNull")));
}
@@ -105,6 +105,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setName(String name) {
_name = name;
}
+
public String name() {
return _name;
}
@@ -112,6 +113,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setColumnName(String name) {
_columnName = name;
}
+
public String columnName() {
if (_columnName != null)
return _columnName;
@@ -124,6 +126,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setClassName(String name) {
_className = name;
}
+
public String className() {
if (_className != null)
return _className;
@@ -137,6 +140,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
_definition = def;
_columnName = null;
}
+
public String definition() {
if (_definition != null)
return _definition;
@@ -149,6 +153,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setExternalType(String type) {
_externalType = type;
}
+
public String externalType() {
if (_externalType != null)
return _externalType;
@@ -162,6 +167,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
_allowsNull = flag;
_has_allowsNull = true;
}
+
public boolean allowsNull() {
if (_has_allowsNull)
return _allowsNull;
@@ -173,6 +179,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setReadOnly(boolean flag) {
_readOnly = flag;
}
+
public boolean readOnly() {
return _readOnly;
}
@@ -184,6 +191,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
else
_prototypeName = null;
}
+
public EOAttribute prototype() {
if (_prototypeName != null && _prototype == null) {
try {
@@ -202,6 +210,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setPrecision(int value) {
_precision = value;
}
+
public int precision() {
if (_precision > 0)
return _precision;
@@ -213,6 +222,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setScale(int value) {
_scale = value;
}
+
public int scale() {
if (_scale > 0)
return _scale;
@@ -224,10 +234,11 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setWidth(int value) {
_width = value;
}
+
public int width() {
if (_width > 0)
return _width;
- if (prototype() != null)
+ if (prototype() != null)
return _prototype.width();
return _width;
}
@@ -236,6 +247,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setValueClassName(String name) {
setClassName(name);
}
+
/** @deprecated Use className() instead. */
public String valueClassName() {
return className();
@@ -244,6 +256,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setValueType(String type) {
_valueType = type;
}
+
public String valueType() {
if (_valueType != null)
return _valueType;
@@ -255,6 +268,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setReadFormat(String value) {
_readFormat = value;
}
+
public String readFormat() {
return _readFormat;
}
@@ -262,6 +276,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setWriteFormat(String value) {
_writeFormat = value;
}
+
public String writeFormat() {
return _writeFormat;
}
@@ -270,9 +285,11 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
return (definition() != null);
}
- /** Determines whether the receiver is a flattened attribute.
- * A flattened attribute has as its definition a relationship
- * path that can be resolved to an attribute.
+ /**
+ * Determines whether the receiver is a flattened attribute. A flattened
+ * attribute has as its definition a relationship path that can be resolved to
+ * an attribute.
+ *
* @return true if the receiver is flattened.
*/
public boolean isFlattened() {
@@ -292,6 +309,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setParameterDirection(int dir) {
_parameterDirection = dir;
}
+
public int parameterDirection() {
return _parameterDirection;
}
@@ -305,6 +323,7 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
public void setUserInfo(NSDictionary value) {
_userInfo = value;
}
+
public NSDictionary userInfo() {
return _userInfo;
}
@@ -348,34 +367,31 @@ public class EOAttribute extends EOProperty implements EOPropertyListEncoding {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2003/08/14 02:13:56 chochos
- * implement and use _attributeForPath()
+ * Revision 1.7 2003/08/14 02:13:56 chochos implement and use
+ * _attributeForPath()
*
- * Revision 1.6 2003/08/12 01:45:04 chochos
- * added some code to handle prototypes
+ * Revision 1.6 2003/08/12 01:45:04 chochos added some code to handle prototypes
*
- * Revision 1.5 2003/08/11 19:38:27 chochos
- * Can now read from a file and re-write to another file.
+ * Revision 1.5 2003/08/11 19:38:27 chochos Can now read from a file and
+ * re-write to another file.
*
- * Revision 1.4 2003/08/09 01:35:35 chochos
- * implement EOPropertyListEncoding
+ * Revision 1.4 2003/08/09 01:35:35 chochos implement EOPropertyListEncoding
*
- * Revision 1.3 2003/08/08 06:52:09 chochos
- * isFlattened() works
+ * Revision 1.3 2003/08/08 06:52:09 chochos isFlattened() works
*
- * Revision 1.2 2003/08/08 02:15:03 chochos
- * added parameterDirection (for use with stored procedures)
+ * Revision 1.2 2003/08/08 02:15:03 chochos added parameterDirection (for use
+ * with stored procedures)
*
- * Revision 1.1 2003/08/07 02:39:45 chochos
- * EOAttribute. Can be initialized from a property list.
+ * Revision 1.1 2003/08/07 02:39:45 chochos EOAttribute. Can be initialized from
+ * a property list.
*
-*/ \ No newline at end of file
+ */ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabase.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabase.java
index a9177c5..a995290 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabase.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabase.java
@@ -28,11 +28,11 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSTimestamp;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EODatabase {
protected EOAdaptor _adaptor;
@@ -98,10 +98,10 @@ public class EODatabase {
public EOEntity entityForObject(EOEnterpriseObject eo) {
String cname = eo.getClass().getName();
for (int i = 0; i < _models.count(); i++) {
- EOModel m = (EOModel)_models.objectAtIndex(i);
+ EOModel m = (EOModel) _models.objectAtIndex(i);
NSArray ents = m.entities();
for (int j = 0; j < ents.count(); j++) {
- EOEntity e = (EOEntity)ents.objectAtIndex(i);
+ EOEntity e = (EOEntity) ents.objectAtIndex(i);
if (e.className().equals(cname))
return e;
}
@@ -111,10 +111,10 @@ public class EODatabase {
public EOEntity entityNamed(String name) {
for (int i = 0; i < _models.count(); i++) {
- EOModel m = (EOModel)_models.objectAtIndex(i);
+ EOModel m = (EOModel) _models.objectAtIndex(i);
NSArray ents = m.entities();
for (int j = 0; j < ents.count(); j++) {
- EOEntity e = (EOEntity)ents.objectAtIndex(i);
+ EOEntity e = (EOEntity) ents.objectAtIndex(i);
if (e.name().equals(name))
return e;
}
@@ -132,13 +132,13 @@ public class EODatabase {
public void forgetSnapshotsForGlobalIDs(NSArray gids) {
for (int i = 0; i < gids.count(); i++)
- forgetSnapshotForGlobalID((EOGlobalID)gids.objectAtIndex(i));
+ forgetSnapshotForGlobalID((EOGlobalID) gids.objectAtIndex(i));
}
public void handleDroppedConnection() {
adaptor().handleDroppedConnection();
for (int i = 0; i < _contexts.count(); i++) {
- EODatabaseContext c = (EODatabaseContext)_contexts.objectAtIndex(i);
+ EODatabaseContext c = (EODatabaseContext) _contexts.objectAtIndex(i);
c.handleDroppedConnection();
}
}
@@ -160,7 +160,7 @@ public class EODatabase {
}
public void recordSnapshotForSourceGlobalID(NSArray gids, EOGlobalID gid, String name) {
- NSMutableDictionary d = (NSMutableDictionary)_snapshots.objectForKey(gid);
+ NSMutableDictionary d = (NSMutableDictionary) _snapshots.objectForKey(gid);
if (d == null) {
d = new NSMutableDictionary();
_snapshots.setObjectForKey(d, gid);
@@ -175,12 +175,12 @@ public class EODatabase {
public void recordToManySnapshots(NSDictionary snaps) {
Enumeration enumeration = snaps.keyEnumerator();
while (enumeration.hasMoreElements()) {
- EOGlobalID gid = (EOGlobalID)enumeration.nextElement();
- NSDictionary rels = (NSDictionary)snaps.objectForKey(gid);
+ EOGlobalID gid = (EOGlobalID) enumeration.nextElement();
+ NSDictionary rels = (NSDictionary) snaps.objectForKey(gid);
Enumeration relEnum = rels.keyEnumerator();
while (relEnum.hasMoreElements()) {
- String relName = (String)relEnum.nextElement();
- NSArray gids = (NSArray)rels.objectForKey(relName);
+ String relName = (String) relEnum.nextElement();
+ NSArray gids = (NSArray) rels.objectForKey(relName);
recordSnapshotForSourceGlobalID(gids, gid, relName);
}
}
@@ -203,7 +203,7 @@ public class EODatabase {
}
public NSArray resultCacheForEntityNamed(String name) {
- return (NSArray)_resultCache.objectForKey(name);
+ return (NSArray) _resultCache.objectForKey(name);
}
public void setResultCache(NSArray cache, String entityName) {
@@ -215,7 +215,7 @@ public class EODatabase {
}
public NSDictionary snapshotForGlobalID(EOGlobalID gid) {
- return (NSDictionary)_snapshots.objectForKey(gid);
+ return (NSDictionary) _snapshots.objectForKey(gid);
}
public NSDictionary snapshotForGlobalID(EOGlobalID gid, long l) {
@@ -223,10 +223,10 @@ public class EODatabase {
}
public NSArray snapshotForSourceGlobalID(EOGlobalID gid, String name) {
- NSDictionary d = (NSDictionary)_snapshots.objectForKey(gid);
+ NSDictionary d = (NSDictionary) _snapshots.objectForKey(gid);
if (d == null)
return null;
- return (NSArray)d.objectForKey(name);
+ return (NSArray) d.objectForKey(name);
}
public NSDictionary snapshotForSourceGlobalID(EOGlobalID gid, String s, long l) {
@@ -247,21 +247,21 @@ public class EODatabase {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.2 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.1 2003/08/19 01:54:43 chochos
- * The EODatabase layer still needs a lot of work, but it's on its way...
+ * Revision 1.1 2003/08/19 01:54:43 chochos The EODatabase layer still needs a
+ * lot of work, but it's on its way...
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseChannel.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseChannel.java
index 10424e9..72427ef 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseChannel.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseChannel.java
@@ -27,11 +27,11 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EODatabaseChannel {
protected EODatabaseContext _context;
@@ -65,14 +65,15 @@ public class EODatabaseChannel {
EOGlobalID gid = _currEntity.globalIDForRow(r);
Object eo = _currEC.objectForGlobalID(gid);
if (eo == null) {
- eo = EOClassDescription.classDescriptionForEntityName(_currEntity.name()).createInstanceWithEditingContext(_currEC, gid);
+ eo = EOClassDescription.classDescriptionForEntityName(_currEntity.name())
+ .createInstanceWithEditingContext(_currEC, gid);
if (eo instanceof EOKeyValueCodingAdditions)
- ((EOKeyValueCodingAdditions)eo).takeValuesFromDictionary(r);
+ ((EOKeyValueCodingAdditions) eo).takeValuesFromDictionary(r);
else
EOKeyValueCodingAdditions.DefaultImplementation.takeValuesFromDictionary(eo, r);
} else {
if (isRefreshingObjects()) {
- //TODO: refresh object (how?)
+ // TODO: refresh object (how?)
}
}
return eo;
@@ -120,19 +121,19 @@ public class EODatabaseChannel {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/29 21:15:46 chochos
- * use EOEntity's globalIDForRow method.
+ * Revision 1.2 2003/08/29 21:15:46 chochos use EOEntity's globalIDForRow
+ * method.
*
- * Revision 1.1 2003/08/19 01:54:43 chochos
- * The EODatabase layer still needs a lot of work, but it's on its way...
+ * Revision 1.1 2003/08/19 01:54:43 chochos The EODatabase layer still needs a
+ * lot of work, but it's on its way...
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseContext.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseContext.java
index af696fe..6ee58a5 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseContext.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseContext.java
@@ -42,13 +42,12 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EODatabaseContext
- extends EOCooperatingObjectStore implements NSLocking {
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EODatabaseContext extends EOCooperatingObjectStore implements NSLocking {
private static Class _contextClass;
protected EODatabase _database;
@@ -79,7 +78,7 @@ public class EODatabaseContext
public EODatabaseChannel availableChannel() {
for (int i = 0; i < _channels.count(); i++) {
- EODatabaseChannel c = (EODatabaseChannel)_channels.objectAtIndex(i);
+ EODatabaseChannel c = (EODatabaseChannel) _channels.objectAtIndex(i);
if (!c.isFetchInProgress())
return c;
}
@@ -94,6 +93,7 @@ public class EODatabaseContext
public static void setContextClassToRegister(Class contextClass) {
_contextClass = contextClass;
}
+
public static Class contextClassToRegister() {
if (_contextClass == null)
_contextClass = EODatabaseContext.class;
@@ -109,21 +109,28 @@ public class EODatabaseContext
}
public void handleDroppedConnection() {
- //TODO: unregister channels
+ // TODO: unregister channels
adaptorContext().handleDroppedConnection();
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#ownsGlobalID(net.wotonomy.control.EOGlobalID)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOCooperatingObjectStore#ownsGlobalID(net.wotonomy.
+ * control.EOGlobalID)
*/
public boolean ownsGlobalID(EOGlobalID gid) {
if (!(gid instanceof EOKeyGlobalID))
return false;
- return (database().entityNamed(((EOKeyGlobalID)gid).entityName()) != null);
+ return (database().entityNamed(((EOKeyGlobalID) gid).entityName()) != null);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#ownsObject(net.wotonomy.control.EOEnterpriseObject)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOCooperatingObjectStore#ownsObject(net.wotonomy.control
+ * .EOEnterpriseObject)
*/
public boolean ownsObject(EOEnterpriseObject eo) {
if (eo.entityName() == null)
@@ -131,8 +138,12 @@ public class EODatabaseContext
return (database().entityNamed(eo.entityName()) != null);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#handlesFetchSpecification(net.wotonomy.control.EOFetchSpecification)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOCooperatingObjectStore#handlesFetchSpecification(net.
+ * wotonomy.control.EOFetchSpecification)
*/
public boolean handlesFetchSpecification(EOFetchSpecification fspec) {
String ename = fspec.entityName();
@@ -143,8 +154,13 @@ public class EODatabaseContext
return adaptorContext().hasBusyChannels();
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#prepareForSaveWithCoordinator(net.wotonomy.control.EOObjectStoreCoordinator, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOCooperatingObjectStore#prepareForSaveWithCoordinator(
+ * net.wotonomy.control.EOObjectStoreCoordinator,
+ * net.wotonomy.control.EOEditingContext)
*/
public void prepareForSaveWithCoordinator(EOObjectStoreCoordinator coord, EOEditingContext ec) {
// TODO Auto-generated method stub
@@ -152,15 +168,21 @@ public class EODatabaseContext
_currEC = ec;
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#recordChangesInEditingContext()
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOCooperatingObjectStore#recordChangesInEditingContext()
*/
public void recordChangesInEditingContext() {
// TODO insert, delete, update
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#recordUpdateForObject(net.wotonomy.control.EOEnterpriseObject, net.wotonomy.foundation.NSDictionary)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOCooperatingObjectStore#recordUpdateForObject(net.
+ * wotonomy.control.EOEnterpriseObject, net.wotonomy.foundation.NSDictionary)
*/
public void recordUpdateForObject(EOEnterpriseObject eo, NSDictionary changes) {
// TODO Auto-generated method stub
@@ -175,7 +197,7 @@ public class EODatabaseContext
public void recordSnapshotForSourceGlobalID(NSArray gids, EOGlobalID gid, String relationName) {
if (_manySnaps == null)
throw new IllegalArgumentException("Attempt to record a snapshot without a transaction in progress");
- NSMutableDictionary d = (NSMutableDictionary)_manySnaps.objectForKey(gid);
+ NSMutableDictionary d = (NSMutableDictionary) _manySnaps.objectForKey(gid);
if (d == null) {
d = new NSMutableDictionary();
_manySnaps.setObjectForKey(d, gid);
@@ -187,13 +209,12 @@ public class EODatabaseContext
if (_simpleSnaps == null)
throw new IllegalArgumentException("Attempt to record snapshots without a transaction in progress.");
_simpleSnaps.addEntriesFromDictionary(snaps);
- /* Make sure we don't need to do this instead
- Enumeration enumeration = snaps.keyEnumerator();
- while (enumeration.hasMoreElements()) {
- EOGlobalID g = (EOGlobalID)enumeration.nextElement();
- NSDictionary d = (NSDictionary)snaps.objectForKey(g);
- recordSnapshotForGlobalID(d, g);
- }*/
+ /*
+ * Make sure we don't need to do this instead Enumeration enumeration =
+ * snaps.keyEnumerator(); while (enumeration.hasMoreElements()) { EOGlobalID g =
+ * (EOGlobalID)enumeration.nextElement(); NSDictionary d =
+ * (NSDictionary)snaps.objectForKey(g); recordSnapshotForGlobalID(d, g); }
+ */
}
public void recordToManySnapshots(NSDictionary snaps) {
@@ -202,18 +223,20 @@ public class EODatabaseContext
Enumeration enumeration = snaps.keyEnumerator();
while (enumeration.hasMoreElements()) {
Object key = enumeration.nextElement();
- NSDictionary d = (NSDictionary)snaps.objectForKey(key);
- NSMutableDictionary d2 = (NSMutableDictionary)_manySnaps.objectForKey(key);
+ NSDictionary d = (NSDictionary) snaps.objectForKey(key);
+ NSMutableDictionary d2 = (NSMutableDictionary) _manySnaps.objectForKey(key);
if (d2 == null) {
d2 = new NSMutableDictionary();
_manySnaps.setObjectForKey(d2, key);
}
- //this could also be done with many calls to recordSnapshotForSourceGID
+ // this could also be done with many calls to recordSnapshotForSourceGID
d2.addEntriesFromDictionary(d);
}
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOCooperatingObjectStore#performChanges()
*/
public void performChanges() {
@@ -221,70 +244,92 @@ public class EODatabaseContext
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOCooperatingObjectStore#commitChanges()
*/
public void commitChanges() {
adaptorContext().commitTransaction();
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOCooperatingObjectStore#rollbackChanges()
*/
public void rollbackChanges() {
adaptorContext().rollbackTransaction();
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOCooperatingObjectStore#valuesForKeys(net.wotonomy.foundation.NSArray, net.wotonomy.control.EOEnterpriseObject)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOCooperatingObjectStore#valuesForKeys(net.wotonomy.
+ * foundation.NSArray, net.wotonomy.control.EOEnterpriseObject)
*/
public NSDictionary valuesForKeys(NSArray keys, EOEnterpriseObject eo) {
// TODO check snapshots; eo could be a fault
return eo.valuesForKeys(keys);
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.foundation.NSLocking#lock()
*/
public void lock() {
EOAccessLock.lock();
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.foundation.NSLocking#unlock()
*/
public void unlock() {
EOAccessLock.unlock();
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#arrayFaultWithSourceGlobalID(net.wotonomy.control.EOGlobalID, java.lang.String, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#arrayFaultWithSourceGlobalID(net.wotonomy.
+ * control.EOGlobalID, java.lang.String, net.wotonomy.control.EOEditingContext)
*/
- public NSArray arrayFaultWithSourceGlobalID(
- EOGlobalID gid, String relName, EOEditingContext ec) {
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID gid, String relName, EOEditingContext ec) {
if (!(gid instanceof EOKeyGlobalID))
throw new IllegalArgumentException("an EOKeyGlobalID is needed.");
- EOAccessArrayFaultHandler handler = new EOAccessArrayFaultHandler((EOKeyGlobalID)gid, relName, this, ec);
+ EOAccessArrayFaultHandler handler = new EOAccessArrayFaultHandler((EOKeyGlobalID) gid, relName, this, ec);
return new NSArray(handler);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#faultForGlobalID(net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#faultForGlobalID(net.wotonomy.control.
+ * EOGlobalID, net.wotonomy.control.EOEditingContext)
*/
- public /*EOEnterpriseObject*/Object faultForGlobalID(EOGlobalID gid, EOEditingContext ec) {
+ public /* EOEnterpriseObject */Object faultForGlobalID(EOGlobalID gid, EOEditingContext ec) {
if (!(gid instanceof EOKeyGlobalID))
throw new IllegalArgumentException("Cannot fault an object that doesn't have a key global ID.");
- EOAccessFaultHandler handler = new EOAccessFaultHandler((EOKeyGlobalID)gid, this, ec);
- EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
+ EOAccessFaultHandler handler = new EOAccessFaultHandler((EOKeyGlobalID) gid, this, ec);
+ EOEntity e = database().entityNamed(((EOKeyGlobalID) gid).entityName());
Object o = e.classDescriptionForInstances().createInstanceWithEditingContext(ec, gid);
EOFaultHandler.makeObjectIntoFault(o, handler);
return o;
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#faultForRawRow(java.util.Map, java.lang.String, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOObjectStore#faultForRawRow(java.util.Map,
+ * java.lang.String, net.wotonomy.control.EOEditingContext)
*/
- public /*EOEnterpriseObject*/ Object faultForRawRow(Map row, String entityName, EOEditingContext ec) {
+ public /* EOEnterpriseObject */ Object faultForRawRow(Map row, String entityName, EOEditingContext ec) {
EOEntity e = database().entityNamed(entityName);
EOGlobalID gid = e.globalIDForRow(row);
return faultForGlobalID(gid, ec);
@@ -299,74 +344,81 @@ public class EODatabaseContext
public void forgetSnapshotsForGlobalIDs(List gids) {
for (int i = 0; i < gids.size(); i++) {
- EOGlobalID g = (EOGlobalID)gids.get(i);
+ EOGlobalID g = (EOGlobalID) gids.get(i);
forgetSnapshotForGlobalID(g);
database().forgetSnapshotForGlobalID(g);
}
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#initializeObject(java.lang.Object, net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOObjectStore#initializeObject(java.lang.Object,
+ * net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
*/
- public void initializeObject(/*EOEnterpriseObject*/Object eo, EOGlobalID gid, EOEditingContext ec) {
+ public void initializeObject(/* EOEnterpriseObject */Object eo, EOGlobalID gid, EOEditingContext ec) {
if (gid.isTemporary())
return;
NSDictionary snap = snapshotForGlobalID(gid);
Object obj = ec.objectForGlobalID(gid);
- EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
+ EOEntity e = database().entityNamed(((EOKeyGlobalID) gid).entityName());
NSArray props = e.classProperties();
for (int i = 0; i < props.count(); i++) {
- EOProperty p = (EOProperty)props.objectAtIndex(i);
+ EOProperty p = (EOProperty) props.objectAtIndex(i);
Object val = snap.objectForKey(p.name());
if (p instanceof EOAttribute) {
- if ( eo instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)eo).takeValueForKey(val, p.name());
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( eo, val, p.name() );
- }
+ if (eo instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) eo).takeValueForKey(val, p.name());
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(eo, val, p.name());
+ }
} else if (p instanceof EORelationship) {
- if (((EORelationship)p).isToMany()) {
+ if (((EORelationship) p).isToMany()) {
val = arrayFaultWithSourceGlobalID(gid, p.name(), ec);
} else {
- EOEntity dest = ((EORelationship)p).destinationEntity();
- EOKeyGlobalID kgid = (EOKeyGlobalID)dest.globalIDForRow(snap);
+ EOEntity dest = ((EORelationship) p).destinationEntity();
+ EOKeyGlobalID kgid = (EOKeyGlobalID) dest.globalIDForRow(snap);
val = ec.objectForGlobalID(kgid);
if (val == null)
val = new EOAccessFaultHandler(kgid, this, ec);
}
if (val == EOKeyValueCoding.NullValue)
val = null;
- if ( eo instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)eo).takeValueForKey(val, p.name());
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( eo, val, p.name() );
- }
+ if (eo instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) eo).takeValueForKey(val, p.name());
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(eo, val, p.name());
+ }
}
}
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOObjectStore#invalidateAllObjects()
*/
public void invalidateAllObjects() {
invalidateObjectsWithGlobalIDs(database().snapshots().allKeys());
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#invalidateObjectsWithGlobalIDs(java.util.List)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#invalidateObjectsWithGlobalIDs(java.util.
+ * List)
*/
public void invalidateObjectsWithGlobalIDs(List aList) {
forgetSnapshotsForGlobalIDs(aList);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#isObjectLockedWithGlobalID(net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#isObjectLockedWithGlobalID(net.wotonomy.
+ * control.EOGlobalID, net.wotonomy.control.EOEditingContext)
*/
public boolean isObjectLockedWithGlobalID(EOGlobalID gid, EOEditingContext ec) {
return isObjectLockedWithGlobalID(gid);
@@ -376,8 +428,11 @@ public class EODatabaseContext
return _lockedObjects.containsObject(gid);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#lockObjectWithGlobalID(net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOObjectStore#lockObjectWithGlobalID(net.wotonomy.
+ * control.EOGlobalID, net.wotonomy.control.EOEditingContext)
*/
public void lockObjectWithGlobalID(EOGlobalID gid, EOEditingContext ec) {
NSDictionary snap = snapshotForGlobalID(gid);
@@ -385,7 +440,7 @@ public class EODatabaseContext
return;
if (!(gid instanceof EOKeyGlobalID))
return;
- EOEntity e = database().entityNamed(((EOKeyGlobalID)gid).entityName());
+ EOEntity e = database().entityNamed(((EOKeyGlobalID) gid).entityName());
EOQualifier q = e.qualifierForPrimaryKey(snap);
EOFetchSpecification fspec = new EOFetchSpecification(e.name(), q, null);
fspec.setLocksObjects(true);
@@ -394,48 +449,53 @@ public class EODatabaseContext
throw new IllegalStateException("Cannot lock object with Global ID " + gid);
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#objectsForSourceGlobalID(net.wotonomy.control.EOGlobalID, java.lang.String, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#objectsForSourceGlobalID(net.wotonomy.
+ * control.EOGlobalID, java.lang.String, net.wotonomy.control.EOEditingContext)
*/
- public NSArray objectsForSourceGlobalID(
- EOGlobalID gid, String relationName, EOEditingContext ec) {
- EOEnterpriseObject eo = (EOEnterpriseObject)ec.objectForGlobalID(gid);
+ public NSArray objectsForSourceGlobalID(EOGlobalID gid, String relationName, EOEditingContext ec) {
+ EOEnterpriseObject eo = (EOEnterpriseObject) ec.objectForGlobalID(gid);
if (eo == null)
- throw new IllegalStateException("Cannot find object for global ID " + gid + " in specified editing context.");
- //Get the source object
+ throw new IllegalStateException(
+ "Cannot find object for global ID " + gid + " in specified editing context.");
+ // Get the source object
EOEnterpriseObject source = (EOEnterpriseObject) faultForGlobalID(gid, ec);
if (source == null)
throw new IllegalStateException("There is no snapshot for source global ID " + gid);
- //Check if there is already a value here
- NSArray value = (NSArray)source.valueForKey(relationName);
+ // Check if there is already a value here
+ NSArray value = (NSArray) source.valueForKey(relationName);
EOAccessArrayFaultHandler handler = null;
if (value != null) {
if (EOFaultHandler.isFault(value)) {
- handler = new EOAccessArrayFaultHandler((EOKeyGlobalID)gid, relationName, this, ec);
- //TODO: fire the fault an return the value
+ handler = new EOAccessArrayFaultHandler((EOKeyGlobalID) gid, relationName, this, ec);
+ // TODO: fire the fault an return the value
} else
return value;
}
- //Get the relationship
+ // Get the relationship
EOEntity entity = database().entityNamed(eo.entityName());
EORelationship rel = entity.relationshipNamed(relationName);
if (rel == null)
- throw new IllegalStateException("Cannot find relationship named " + relationName + " in entity " + entity.name());
+ throw new IllegalStateException(
+ "Cannot find relationship named " + relationName + " in entity " + entity.name());
- //create a fetch specification for this
+ // create a fetch specification for this
EOQualifier q = null;
NSArray joins = rel.joins();
NSMutableArray subq = new NSMutableArray(joins.count());
for (int i = 0; i < joins.count(); i++) {
- EOJoin j = (EOJoin)joins.objectAtIndex(i);
+ EOJoin j = (EOJoin) joins.objectAtIndex(i);
String key = j.destinationAttribute().name();
Object val = eo.valueForKey(j.sourceAttribute().name());
subq.addObject(new EOKeyValueQualifier(key, EOQualifier.QualifierOperatorEqual, val));
}
if (subq.count() == 1) {
- q = (EOQualifier)subq.objectAtIndex(0);
+ q = (EOQualifier) subq.objectAtIndex(0);
} else {
q = new EOAndQualifier(subq);
}
@@ -448,8 +508,12 @@ public class EODatabaseContext
return res;
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#objectsWithFetchSpecification(net.wotonomy.control.EOFetchSpecification, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#objectsWithFetchSpecification(net.wotonomy
+ * .control.EOFetchSpecification, net.wotonomy.control.EOEditingContext)
*/
public NSArray objectsWithFetchSpecification(EOFetchSpecification fspec, EOEditingContext ec) {
EODatabaseChannel channel = availableChannel();
@@ -464,21 +528,28 @@ public class EODatabaseContext
return arr;
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#refaultObject(java.lang.Object, net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOObjectStore#refaultObject(java.lang.Object,
+ * net.wotonomy.control.EOGlobalID, net.wotonomy.control.EOEditingContext)
*/
public void refaultObject(Object obj, EOGlobalID gid, EOEditingContext ec) {
if (!(gid instanceof EOKeyGlobalID))
throw new IllegalArgumentException("GlobalID must be an EOKeyGlobalID");
if (obj instanceof EOFaulting)
- //check if it's already a fault
- if (!EOFaultHandler.isFault(obj)) {
- ((EOFaulting)obj).turnIntoFault(EOFaultHandler.handlerForFault(obj));
- }
+ // check if it's already a fault
+ if (!EOFaultHandler.isFault(obj)) {
+ ((EOFaulting) obj).turnIntoFault(EOFaultHandler.handlerForFault(obj));
+ }
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOObjectStore#saveChangesInEditingContext(net.wotonomy.control.EOEditingContext)
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.wotonomy.control.EOObjectStore#saveChangesInEditingContext(net.wotonomy.
+ * control.EOEditingContext)
*/
public void saveChangesInEditingContext(EOEditingContext ec) {
prepareForSaveWithCoordinator(null, ec);
@@ -508,7 +579,7 @@ public class EODatabaseContext
public NSDictionary snapshotForGlobalID(EOGlobalID gid) {
NSDictionary d = null;
if (_simpleSnaps != null) {
- d = (NSDictionary)_simpleSnaps.objectForKey(gid);
+ d = (NSDictionary) _simpleSnaps.objectForKey(gid);
}
if (d == null)
d = database().snapshotForGlobalID(gid);
@@ -518,8 +589,8 @@ public class EODatabaseContext
public NSArray snapshotForSourceGlobalID(EOGlobalID gid, String name) {
NSArray a = null;
if (_manySnaps != null) {
- NSDictionary d = (NSDictionary)_manySnaps.objectForKey(gid);
- a = (NSArray)d.objectForKey(name);
+ NSDictionary d = (NSDictionary) _manySnaps.objectForKey(gid);
+ a = (NSArray) d.objectForKey(name);
}
if (a == null)
a = database().snapshotForSourceGlobalID(gid, name);
@@ -536,33 +607,32 @@ public class EODatabaseContext
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.5 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.4 2003/12/18 15:37:38 mpowers
- * Changes to retain ability to work with objects that don't necessarily
- * implement EOEnterpriseObject. I would still like to preserve this case
- * for general usage, however the access package is free to assume that
- * those objects will be EOs and cast appropriately.
+ * Revision 1.4 2003/12/18 15:37:38 mpowers Changes to retain ability to work
+ * with objects that don't necessarily implement EOEnterpriseObject. I would
+ * still like to preserve this case for general usage, however the access
+ * package is free to assume that those objects will be EOs and cast
+ * appropriately.
*
- * Revision 1.3 2003/08/29 21:14:44 chochos
- * implement a couple more methods.
+ * Revision 1.3 2003/08/29 21:14:44 chochos implement a couple more methods.
*
- * Revision 1.2 2003/08/20 01:16:22 chochos
- * more methods have code now, but there's no way to test this yet. The core is still pending.
+ * Revision 1.2 2003/08/20 01:16:22 chochos more methods have code now, but
+ * there's no way to test this yet. The core is still pending.
*
- * Revision 1.1 2003/08/19 01:54:43 chochos
- * The EODatabase layer still needs a lot of work, but it's on its way...
+ * Revision 1.1 2003/08/19 01:54:43 chochos The EODatabase layer still needs a
+ * lot of work, but it's on its way...
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseOperation.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseOperation.java
index 596180e..d8bd726 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseOperation.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EODatabaseOperation.java
@@ -18,11 +18,11 @@
package net.wotonomy.access;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class EODatabaseOperation {
public static final int AdaptorLockOperator = 0;
@@ -38,11 +38,10 @@ public class EODatabaseOperation {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 00:38:47 chochos
- * for the moment, this only contains some constants needed by EOAdaptorChannel and EOAdaptorOperation.
+ * Revision 1.1 2003/08/13 00:38:47 chochos for the moment, this only contains
+ * some constants needed by EOAdaptorChannel and EOAdaptorOperation.
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java
index 4adc4a1..47a31c0 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java
@@ -42,14 +42,14 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSPropertyListSerialization;
/**
-* An EOEntity is a mapping between a Java class and a database table or view.
-* It indicates which attributes should be fetched from the table/view, what
-* attributes are part of the primary key, what class the entity should map to.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * An EOEntity is a mapping between a Java class and a database table or view.
+ * It indicates which attributes should be fetched from the table/view, what
+ * attributes are part of the primary key, what class the entity should map to.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOEntity implements EOPropertyListEncoding {
protected NSMutableDictionary _attributes = new NSMutableDictionary();
@@ -80,55 +80,55 @@ public class EOEntity implements EOPropertyListEncoding {
public EOEntity(NSDictionary dict, Object obj) {
super();
- _model = (EOModel)obj;
- setName((String)dict.objectForKey("name"));
- setExternalName((String)dict.objectForKey("externalName"));
- setClassName((String)dict.objectForKey("className"));
+ _model = (EOModel) obj;
+ setName((String) dict.objectForKey("name"));
+ setExternalName((String) dict.objectForKey("externalName"));
+ setClassName((String) dict.objectForKey("className"));
if (dict.objectForKey("internalInfo") != null)
- _internalInfo = (NSDictionary)dict.objectForKey("internalInfo");
+ _internalInfo = (NSDictionary) dict.objectForKey("internalInfo");
if (dict.objectForKey("userInfo") != null)
- _userInfo = (NSDictionary)dict.objectForKey("userInfo");
+ _userInfo = (NSDictionary) dict.objectForKey("userInfo");
- //Read the attributes
- NSArray atr = (NSArray)dict.objectForKey("attributes");
+ // Read the attributes
+ NSArray atr = (NSArray) dict.objectForKey("attributes");
for (int i = 0; i < atr.count(); i++) {
- NSDictionary d = (NSDictionary)atr.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) atr.objectAtIndex(i);
EOAttribute atrib = new EOAttribute(d, this);
addAttribute(atrib);
}
- //Set the primary key
- atr = (NSArray)dict.objectForKey("primaryKeyAttributes");
+ // Set the primary key
+ atr = (NSArray) dict.objectForKey("primaryKeyAttributes");
NSMutableArray pka = new NSMutableArray();
for (int i = 0; i < atr.count(); i++) {
- EOAttribute a = attributeNamed((String)atr.objectAtIndex(i));
+ EOAttribute a = attributeNamed((String) atr.objectAtIndex(i));
pka.addObject(a);
}
_pkAttributes = new NSArray(pka);
_pkAttributeNames = atr;
- //attributes used for locking
+ // attributes used for locking
_lockingAttributes.removeAllObjects();
- atr = (NSArray)dict.objectForKey("attributesUsedForLocking");
+ atr = (NSArray) dict.objectForKey("attributesUsedForLocking");
for (int i = 0; i < atr.count(); i++) {
- String x = (String)atr.objectAtIndex(i);
+ String x = (String) atr.objectAtIndex(i);
EOAttribute a = attributeNamed(x);
_lockingAttributes.addObject(a);
}
- //class properties
- atr = (NSArray)dict.objectForKey("classProperties");
+ // class properties
+ atr = (NSArray) dict.objectForKey("classProperties");
if (atr != null) {
for (int i = 0; i < atr.count(); i++)
if (!_classPropertyNames.containsObject((atr.objectAtIndex(i))))
_classPropertyNames.addObject(atr.objectAtIndex(i));
}
- //Read the relationships
- atr = (NSArray)dict.objectForKey("relationships");
+ // Read the relationships
+ atr = (NSArray) dict.objectForKey("relationships");
if (atr != null) {
for (int i = 0; i < atr.count(); i++) {
- NSDictionary d = (NSDictionary)atr.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) atr.objectAtIndex(i);
EORelationship rel = new EORelationship(d, this);
addRelationship(rel);
}
@@ -169,7 +169,7 @@ public class EOEntity implements EOPropertyListEncoding {
public EOFetchSpecification fetchSpecificationNamed(String name) {
loadFetchSpecifications();
- return (EOFetchSpecification)_fetchSpecs.objectForKey(name);
+ return (EOFetchSpecification) _fetchSpecs.objectForKey(name);
}
public NSArray fetchSpecificationNames() {
@@ -177,8 +177,8 @@ public class EOEntity implements EOPropertyListEncoding {
return _fetchSpecs.allKeys();
}
- /** Loads fetch specifications from the .fspec file,
- * if one exists.
+ /**
+ * Loads fetch specifications from the .fspec file, if one exists.
*/
private void loadFetchSpecifications() {
if (_loadedFetchSpecs)
@@ -187,7 +187,7 @@ public class EOEntity implements EOPropertyListEncoding {
if (model().path() == null)
return;
File f = new File(model().path());
- //Read the fetch specification file, if it exists
+ // Read the fetch specification file, if it exists
f = new File(f, name() + ".fspec");
if (!f.exists())
return;
@@ -207,11 +207,11 @@ public class EOEntity implements EOPropertyListEncoding {
throw new IllegalArgumentException("Cannot read dictionary from " + f);
NSArray keys = fdict.allKeys();
- //Unarchive the fetch specification
+ // Unarchive the fetch specification
EOKeyValueUnarchiver unarch = new EOKeyValueUnarchiver(fdict);
for (int i = 0; i < keys.count(); i++) {
- String k = (String)keys.objectAtIndex(i);
- EOFetchSpecification fs = (EOFetchSpecification)unarch.decodeObjectForKey(k);
+ String k = (String) keys.objectAtIndex(i);
+ EOFetchSpecification fs = (EOFetchSpecification) unarch.decodeObjectForKey(k);
if (fs != null)
_fetchSpecs.setObjectForKey(fs, k);
}
@@ -222,7 +222,7 @@ public class EOEntity implements EOPropertyListEncoding {
}
public EOAttribute attributeNamed(String name) {
- return (EOAttribute)_attributes.objectForKey(name);
+ return (EOAttribute) _attributes.objectForKey(name);
}
public NSArray flattenedAttributes() {
@@ -232,6 +232,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setClassName(String name) {
_className = name;
}
+
public String className() {
return _className;
}
@@ -239,6 +240,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setName(String name) {
_name = name;
}
+
public String name() {
return _name;
}
@@ -246,6 +248,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setExternalName(String name) {
_externalName = name;
}
+
public String externalName() {
return _externalName;
}
@@ -274,7 +277,9 @@ public class EOEntity implements EOPropertyListEncoding {
_classPropertyOneRelationships.removeObject(rel);
}
- /** Returns the relationships from this entity to other entities.
+ /**
+ * Returns the relationships from this entity to other entities.
+ *
* @return An array of the relationships of this entity.
*/
public NSArray relationships() {
@@ -282,8 +287,9 @@ public class EOEntity implements EOPropertyListEncoding {
}
public EORelationship relationshipNamed(String name) {
- return (EORelationship)_relations.objectForKey(name);
+ return (EORelationship) _relations.objectForKey(name);
}
+
public EOModel model() {
return _model;
}
@@ -291,6 +297,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setPrimaryKeyAtributes(NSArray pk) {
_pkAttributes = pk;
}
+
public NSArray primaryKeyAttributes() {
return _pkAttributes;
}
@@ -299,7 +306,7 @@ public class EOEntity implements EOPropertyListEncoding {
if (_pkAttributeNames.count() != _pkAttributes.count()) {
NSMutableArray arr = new NSMutableArray();
for (int i = 0; i < _pkAttributes.count(); i++) {
- EOAttribute a = (EOAttribute)_pkAttributes.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) _pkAttributes.objectAtIndex(i);
arr.addObject(a.name());
}
_pkAttributeNames = new NSArray(arr);
@@ -319,6 +326,7 @@ public class EOEntity implements EOPropertyListEncoding {
_lockingAttributes.removeAllObjects();
_lockingAttributes.addObjectsFromArray(value);
}
+
public NSArray attributesUsedForLocking() {
return new NSArray(_lockingAttributes);
}
@@ -331,18 +339,19 @@ public class EOEntity implements EOPropertyListEncoding {
_classPropertyOneRelationships.removeAllObjects();
_classPropertyManyRelationships.removeAllObjects();
for (int i = 0; i < value.count(); i++) {
- EOProperty o = (EOProperty)value.objectAtIndex(i);
+ EOProperty o = (EOProperty) value.objectAtIndex(i);
_classPropertyNames.addObject(o.name());
if (o instanceof EOAttribute) {
_classPropertyAttributes.addObject(o);
} else if (o instanceof EORelationship) {
- if (((EORelationship)o).isToMany())
+ if (((EORelationship) o).isToMany())
_classPropertyManyRelationships.addObject(o);
else
_classPropertyOneRelationships.addObject(o);
}
}
}
+
public NSArray classProperties() {
if (_classProperties == null) {
if (_classPropertyNames == null)
@@ -353,7 +362,7 @@ public class EOEntity implements EOPropertyListEncoding {
NSMutableArray ones = new NSMutableArray();
NSMutableArray manies = new NSMutableArray();
for (int i = 0; i < _classPropertyNames.count(); i++) {
- String name = (String)_classPropertyNames.objectAtIndex(i);
+ String name = (String) _classPropertyNames.objectAtIndex(i);
EOAttribute a = attributeNamed(name);
EORelationship r = relationshipNamed(name);
if (a != null) {
@@ -385,8 +394,8 @@ public class EOEntity implements EOPropertyListEncoding {
if (_classPropertyAttributes == null)
return NSArray.EmptyArray;
NSMutableArray arr = new NSMutableArray(_classPropertyAttributes.count());
- for (int i = 0 ; i < _classPropertyAttributes.count(); i++) {
- EOAttribute a = (EOAttribute)_classPropertyAttributes.objectAtIndex(i);
+ for (int i = 0; i < _classPropertyAttributes.count(); i++) {
+ EOAttribute a = (EOAttribute) _classPropertyAttributes.objectAtIndex(i);
arr.addObject(a.name());
}
return arr;
@@ -396,8 +405,8 @@ public class EOEntity implements EOPropertyListEncoding {
if (_classPropertyManyRelationships == null)
return NSArray.EmptyArray;
NSMutableArray arr = new NSMutableArray(_classPropertyManyRelationships.count());
- for (int i = 0 ; i < _classPropertyManyRelationships.count(); i++) {
- EOAttribute a = (EOAttribute)_classPropertyManyRelationships.objectAtIndex(i);
+ for (int i = 0; i < _classPropertyManyRelationships.count(); i++) {
+ EOAttribute a = (EOAttribute) _classPropertyManyRelationships.objectAtIndex(i);
arr.addObject(a.name());
}
return arr;
@@ -407,8 +416,8 @@ public class EOEntity implements EOPropertyListEncoding {
if (_classPropertyOneRelationships == null)
return NSArray.EmptyArray;
NSMutableArray arr = new NSMutableArray(_classPropertyOneRelationships.count());
- for (int i = 0 ; i < _classPropertyOneRelationships.count(); i++) {
- EOAttribute a = (EOAttribute)_classPropertyOneRelationships.objectAtIndex(i);
+ for (int i = 0; i < _classPropertyOneRelationships.count(); i++) {
+ EOAttribute a = (EOAttribute) _classPropertyOneRelationships.objectAtIndex(i);
arr.addObject(a.name());
}
return arr;
@@ -417,6 +426,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setIsAbstractEntity(boolean flag) {
_isAbstract = flag;
}
+
public boolean isAbstractEntity() {
return _isAbstract;
}
@@ -424,12 +434,14 @@ public class EOEntity implements EOPropertyListEncoding {
public void setReadOnly(boolean flag) {
_isReadOnly = flag;
}
+
public boolean isReadOnly() {
return _isReadOnly;
}
public void setStoredProcedure(EOStoredProcedure proc, String operation) {
}
+
public EOStoredProcedure storedProcedureForOperation(String operation) {
return null;
}
@@ -462,8 +474,9 @@ public class EOEntity implements EOPropertyListEncoding {
}
/**
- * Creates a global ID for a row. The row must have values
- * for all the primary key attributes.
+ * Creates a global ID for a row. The row must have values for all the primary
+ * key attributes.
+ *
* @param row A raw row for this entity.
* @return A key global ID to identify this row.
*/
@@ -471,7 +484,7 @@ public class EOEntity implements EOPropertyListEncoding {
NSArray pknames = primaryKeyAttributeNames();
EOKeyGlobalID gid = null;
if (pknames.count() == 1 && row.get(pknames.objectAtIndex(0)) instanceof Number) {
- Number n = (Number)row.get(pknames.objectAtIndex(0));
+ Number n = (Number) row.get(pknames.objectAtIndex(0));
gid = new EOIntegralKeyGlobalID(name(), n);
} else {
Object[] vals = new Object[pknames.count()];
@@ -485,15 +498,15 @@ public class EOEntity implements EOPropertyListEncoding {
}
/**
- * Returns a dictionary with the primary key values contained in
- * the global id.
+ * Returns a dictionary with the primary key values contained in the global id.
+ *
* @param gid A Key global ID.
* @return A dictionary with the primary key values for gid.
*/
public NSDictionary primaryKeyForGlobalID(EOGlobalID gid) {
if (!(gid instanceof EOKeyGlobalID))
return null;
- Object[] vals = ((EOKeyGlobalID)gid).keyValues();
+ Object[] vals = ((EOKeyGlobalID) gid).keyValues();
NSArray pknames = primaryKeyAttributeNames();
return new NSDictionary(vals, pknames.toArray());
}
@@ -503,14 +516,14 @@ public class EOEntity implements EOPropertyListEncoding {
EOQualifier q = null;
NSMutableArray subq = new NSMutableArray(pknames.count());
for (int i = 0; i < pknames.count(); i++) {
- String key = (String)pknames.objectAtIndex(i);
+ String key = (String) pknames.objectAtIndex(i);
Object v = pkey.get(key);
if (v == null || v == NSKeyValueCoding.NullValue)
throw new IllegalArgumentException("Primary key with null values.");
subq.addObject(new EOKeyValueQualifier(key, EOQualifier.QualifierOperatorEqual, v));
}
if (subq.count() == 1)
- q = (EOQualifier)subq.objectAtIndex(0);
+ q = (EOQualifier) subq.objectAtIndex(0);
else
q = new EOAndQualifier(subq);
return q;
@@ -519,6 +532,7 @@ public class EOEntity implements EOPropertyListEncoding {
public void setUserInfo(NSDictionary value) {
_userInfo = value;
}
+
public NSDictionary userInfo() {
return _userInfo;
}
@@ -531,20 +545,20 @@ public class EOEntity implements EOPropertyListEncoding {
dict.setObjectForKey(externalName(), "externalName");
dict.setObjectForKey(className(), "className");
- //Encode attributes
+ // Encode attributes
NSMutableArray arr = new NSMutableArray(_attributes.allValues());
for (int i = 0; i < _attributes.count(); i++) {
- EOAttribute a = (EOAttribute)arr.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) arr.objectAtIndex(i);
NSMutableDictionary d = new NSMutableDictionary();
a.encodeIntoPropertyList(d);
arr.replaceObjectAtIndex(i, d);
}
dict.setObjectForKey(arr, "attributes");
- //Encode relationships
+ // Encode relationships
if (_relations.count() > 0) {
arr = new NSMutableArray(_relations.allValues());
for (int i = 0; i < _relations.count(); i++) {
- EORelationship r = (EORelationship)arr.objectAtIndex(i);
+ EORelationship r = (EORelationship) arr.objectAtIndex(i);
NSMutableDictionary d = new NSMutableDictionary();
r.encodeIntoPropertyList(d);
arr.replaceObjectAtIndex(i, d);
@@ -552,29 +566,29 @@ public class EOEntity implements EOPropertyListEncoding {
dict.setObjectForKey(arr, "relationships");
}
- //Fetch specifications
+ // Fetch specifications
NSMutableDictionary d = new NSMutableDictionary();
loadFetchSpecifications();
java.util.Enumeration enumeration = _fetchSpecs.keyEnumerator();
while (enumeration.hasMoreElements()) {
- String k = (String)enumeration.nextElement();
- EOFetchSpecification f = (EOFetchSpecification)_fetchSpecs.objectForKey(k);
+ String k = (String) enumeration.nextElement();
+ EOFetchSpecification f = (EOFetchSpecification) _fetchSpecs.objectForKey(k);
EOKeyValueArchiver arch = new EOKeyValueArchiver();
f.encodeWithKeyValueArchiver(arch);
d.setObjectForKey(arch.dictionary(), k);
}
dict.setObjectForKey(d, "fetchSpecificationDictionary");
- //Other information
+ // Other information
dict.setObjectForKey(_classPropertyNames, "classProperties");
dict.setObjectForKey(_pkAttributeNames, "primaryKeyAttributes");
arr = new NSMutableArray(_lockingAttributes);
for (int i = 0; i < arr.count(); i++)
- arr.replaceObjectAtIndex(i, ((EOAttribute)arr.objectAtIndex(i)).name());
+ arr.replaceObjectAtIndex(i, ((EOAttribute) arr.objectAtIndex(i)).name());
dict.setObjectForKey(arr, "attributesUsedForLocking");
- if (_userInfo != null && _userInfo.count() > 0 )
+ if (_userInfo != null && _userInfo.count() > 0)
dict.setObjectForKey(_userInfo, "userInfo");
- if (_internalInfo != null && _internalInfo.count() > 0 )
+ if (_internalInfo != null && _internalInfo.count() > 0)
dict.setObjectForKey(_internalInfo, "internalInfo");
}
@@ -584,54 +598,54 @@ public class EOEntity implements EOPropertyListEncoding {
return null;
EORelationship r = null;
EOEntity e = this;
- for (int i = 0; i < comps.count()-1; i++) {
- String name = (String)comps.objectAtIndex(i);
+ for (int i = 0; i < comps.count() - 1; i++) {
+ String name = (String) comps.objectAtIndex(i);
r = e.relationshipNamed(name);
if (r == null)
return null;
e = r.destinationEntity();
}
- return e.attributeNamed((String)comps.lastObject());
+ return e.attributeNamed((String) comps.lastObject());
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.9 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.8 2003/08/19 19:47:58 chochos
- * added some methods to handle EOGlobalIDs and primary keys.
+ * Revision 1.8 2003/08/19 19:47:58 chochos added some methods to handle
+ * EOGlobalIDs and primary keys.
*
- * Revision 1.7 2003/08/14 02:13:56 chochos
- * implement and use _attributeForPath()
+ * Revision 1.7 2003/08/14 02:13:56 chochos implement and use
+ * _attributeForPath()
*
- * Revision 1.6 2003/08/11 19:38:27 chochos
- * Can now read from a file and re-write to another file.
+ * Revision 1.6 2003/08/11 19:38:27 chochos Can now read from a file and
+ * re-write to another file.
*
- * Revision 1.5 2003/08/11 18:19:33 chochos
- * encoding into property list seems to work fine now.
+ * Revision 1.5 2003/08/11 18:19:33 chochos encoding into property list seems to
+ * work fine now.
*
- * Revision 1.4 2003/08/09 01:39:04 chochos
- * better handling of class properties; use EOKeyValueArchiving to encode/decode fetch specifications; implement EOPropertyListEncoding
+ * Revision 1.4 2003/08/09 01:39:04 chochos better handling of class properties;
+ * use EOKeyValueArchiving to encode/decode fetch specifications; implement
+ * EOPropertyListEncoding
*
- * Revision 1.3 2003/08/08 05:52:21 chochos
- * gets the class description for the entity.
+ * Revision 1.3 2003/08/08 05:52:21 chochos gets the class description for the
+ * entity.
*
- * Revision 1.2 2003/08/08 02:14:20 chochos
- * now it can read stored procedures.
+ * Revision 1.2 2003/08/08 02:14:20 chochos now it can read stored procedures.
*
- * Revision 1.1 2003/08/07 02:38:33 chochos
- * implementation of EOEntity. What works for now is reading an entity from file.
+ * Revision 1.1 2003/08/07 02:38:33 chochos implementation of EOEntity. What
+ * works for now is reading an entity from file.
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntityClassDescription.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntityClassDescription.java
index a235c99..0485497 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntityClassDescription.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntityClassDescription.java
@@ -26,10 +26,10 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSMutableArray;
/**
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOEntityClassDescription extends EOClassDescription {
protected EOEntity _entity;
@@ -47,7 +47,7 @@ public class EOEntityClassDescription extends EOClassDescription {
NSArray arr = entity().attributes();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EOAttribute atrib = (EOAttribute)arr.objectAtIndex(i);
+ EOAttribute atrib = (EOAttribute) arr.objectAtIndex(i);
a.addObject(atrib);
}
return a;
@@ -61,7 +61,7 @@ public class EOEntityClassDescription extends EOClassDescription {
NSArray arr = entity().relationships();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EORelationship r = (EORelationship)arr.objectAtIndex(i);
+ EORelationship r = (EORelationship) arr.objectAtIndex(i);
if (r.isToMany())
a.addObject(r);
}
@@ -72,21 +72,21 @@ public class EOEntityClassDescription extends EOClassDescription {
NSArray arr = entity().relationships();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EORelationship r = (EORelationship)arr.objectAtIndex(i);
+ EORelationship r = (EORelationship) arr.objectAtIndex(i);
if (!r.isToMany())
a.addObject(r);
}
return a;
}
- /** Returns all attributes that correspond to columns
- * in a database table.
+ /**
+ * Returns all attributes that correspond to columns in a database table.
*/
public NSArray attributeKeys() {
NSArray arr = entity().attributes();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EOAttribute atrib = (EOAttribute)arr.objectAtIndex(i);
+ EOAttribute atrib = (EOAttribute) arr.objectAtIndex(i);
if (!atrib.isDerived())
a.addObject(atrib);
}
@@ -128,7 +128,7 @@ public class EOEntityClassDescription extends EOClassDescription {
NSArray arr = entity().relationships();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EORelationship r = (EORelationship)arr.objectAtIndex(i);
+ EORelationship r = (EORelationship) arr.objectAtIndex(i);
if (r.isToMany() && !r.isFlattened())
a.addObject(r);
}
@@ -139,7 +139,7 @@ public class EOEntityClassDescription extends EOClassDescription {
NSArray arr = entity().relationships();
NSMutableArray a = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- EORelationship r = (EORelationship)arr.objectAtIndex(i);
+ EORelationship r = (EORelationship) arr.objectAtIndex(i);
if (!r.isToMany() && !r.isFlattened())
a.addObject(r);
}
@@ -147,7 +147,7 @@ public class EOEntityClassDescription extends EOClassDescription {
}
public Object createInstanceWithEditingContext(EOEditingContext ec, EOGlobalID gid) {
- if (theClass == null) {
+ if (theClass == null) {
try {
theClass = Class.forName(entity().className());
} catch (ClassNotFoundException ex) {
@@ -161,25 +161,26 @@ public class EOEntityClassDescription extends EOClassDescription {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/19 01:55:54 chochos
- * the behavior is now more consistent with its Apple counterpart.
+ * Revision 1.4 2003/08/19 01:55:54 chochos the behavior is now more consistent
+ * with its Apple counterpart.
*
- * Revision 1.3 2003/08/09 01:40:31 chochos
- * use EOClassDescription's methods to get a destination entity's class description.
+ * Revision 1.3 2003/08/09 01:40:31 chochos use EOClassDescription's methods to
+ * get a destination entity's class description.
*
- * Revision 1.2 2003/08/08 05:51:59 chochos
- * createInstanceWithEditingContext now works. It sets theClass with the class from the entity className() before calling super.
+ * Revision 1.2 2003/08/08 05:51:59 chochos createInstanceWithEditingContext now
+ * works. It sets theClass with the class from the entity className() before
+ * calling super.
*
- * Revision 1.1 2003/08/08 00:36:19 chochos
- * concrete implementation of EOClassDescription that uses an EOEntity
+ * Revision 1.1 2003/08/08 00:36:19 chochos concrete implementation of
+ * EOClassDescription that uses an EOEntity
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOGeneralAdaptorException.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOGeneralAdaptorException.java
index 6c48a3f..435d6a1 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOGeneralAdaptorException.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOGeneralAdaptorException.java
@@ -20,12 +20,12 @@ package net.wotonomy.access;
import net.wotonomy.foundation.NSDictionary;
/**
-* Generic exception thrown by wotonomy.access.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * Generic exception thrown by wotonomy.access.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class EOGeneralAdaptorException extends RuntimeException implements java.io.Serializable {
private NSDictionary _userInfo;
@@ -41,9 +41,8 @@ public class EOGeneralAdaptorException extends RuntimeException implements java.
public EOGeneralAdaptorException(String selectorName, String className, String msg) {
super(msg);
- _userInfo = new NSDictionary(
- new Object[]{ selectorName, className },
- new Object[]{ "selectorName", "className" });
+ _userInfo = new NSDictionary(new Object[] { selectorName, className },
+ new Object[] { "selectorName", "className" });
}
public NSDictionary userInfo() {
@@ -52,11 +51,9 @@ public class EOGeneralAdaptorException extends RuntimeException implements java.
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 00:41:50 chochos
- * general adaptor exception
+ * Revision 1.1 2003/08/13 00:41:50 chochos general adaptor exception
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOJoin.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOJoin.java
index 693a7d0..01326ac 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOJoin.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOJoin.java
@@ -18,13 +18,13 @@
package net.wotonomy.access;
/**
-* An EOJoin represents a connection between two attributes in
-* different entities.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * An EOJoin represents a connection between two attributes in different
+ * entities.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class EOJoin {
protected EOAttribute _source;
@@ -45,12 +45,10 @@ public class EOJoin {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/07 02:41:04 chochos
- * these don't do much for now.
+ * Revision 1.1 2003/08/07 02:41:04 chochos these don't do much for now.
*
*/
}
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModel.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModel.java
index 46fc8d0..9c77d45 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModel.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModel.java
@@ -31,18 +31,18 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSPropertyListSerialization;
/**
-* An EOModel is a set of entities and stored procedures, along with a connection
-* dictionary to connect to a database.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * An EOModel is a set of entities and stored procedures, along with a
+ * connection dictionary to connect to a database.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOModel {
protected static final String IDX_NAME = "index.eomodeld";
- //This array contains dictionaries with "className" and "name"
+ // This array contains dictionaries with "className" and "name"
protected NSMutableArray _entities = new NSMutableArray();
protected NSMutableDictionary _entitiesByName = new NSMutableDictionary();
protected NSMutableDictionary _entitiesByClass = new NSMutableDictionary();
@@ -86,24 +86,25 @@ public class EOModel {
throw new IllegalArgumentException("Cannot read index.eomodeld");
}
NSDictionary d = NSPropertyListSerialization.dictionaryForString(x);
- String version = (String)d.objectForKey("EOModelVersion");
+ String version = (String) d.objectForKey("EOModelVersion");
if (version == null || !version.startsWith("2."))
throw new IllegalArgumentException("Invalid eomodel version: " + version);
- setAdaptorName((String)d.objectForKey("adaptorName"));
- setConnectionDictionary((NSDictionary)d.objectForKey("connectionDictionary"));
- _entities = ((NSArray)d.objectForKey("entities")).mutableClone();
+ setAdaptorName((String) d.objectForKey("adaptorName"));
+ setConnectionDictionary((NSDictionary) d.objectForKey("connectionDictionary"));
+ _entities = ((NSArray) d.objectForKey("entities")).mutableClone();
if (d.objectForKey("storedProcedures") != null)
- _storedProcedureNames.addObjectsFromArray((NSArray)d.objectForKey("storedProcedures"));
+ _storedProcedureNames.addObjectsFromArray((NSArray) d.objectForKey("storedProcedures"));
if (d.objectForKey("internalInfo") != null)
- _internalInfo = (NSDictionary)d.objectForKey("internalInfo");
+ _internalInfo = (NSDictionary) d.objectForKey("internalInfo");
if (d.objectForKey("userInfo") != null)
- _userInfo = (NSDictionary)d.objectForKey("userInfo");
+ _userInfo = (NSDictionary) d.objectForKey("userInfo");
entityNamed("EOPrototypes");
}
public void setConnectionDictionary(NSDictionary dict) {
_connectionDictionary = dict;
}
+
public NSDictionary connectionDictionary() {
return _connectionDictionary;
}
@@ -130,10 +131,10 @@ public class EOModel {
}
public EOStoredProcedure storedProcedureNamed(String name) {
- EOStoredProcedure proc = (EOStoredProcedure)_storedProcedures.objectForKey(name);
- //if we can't find it, check if we should load it
+ EOStoredProcedure proc = (EOStoredProcedure) _storedProcedures.objectForKey(name);
+ // if we can't find it, check if we should load it
if (proc == null && _path != null && _storedProcedureNames.containsObject(name)) {
- //try to read it from file
+ // try to read it from file
File f = new File(new File(_path), name + ".storedProcedure");
if (!f.exists())
return null;
@@ -149,9 +150,10 @@ public class EOModel {
}
NSDictionary plist = NSPropertyListSerialization.dictionaryForString(sdict);
if (plist == null)
- throw new IllegalArgumentException("File " + f + " does not contain a valid stored procedure property list.");
+ throw new IllegalArgumentException(
+ "File " + f + " does not contain a valid stored procedure property list.");
proc = new EOStoredProcedure(plist, this);
- //add it to our collection
+ // add it to our collection
_storedProcedures.setObjectForKey(proc, proc.name());
}
return proc;
@@ -159,8 +161,8 @@ public class EOModel {
public NSArray storedProcedures() {
if (_storedProcedures.count() < _storedProcedureNames.count()) {
- for (int i=0; i<_storedProcedureNames.count(); i++)
- storedProcedureNamed((String)_storedProcedureNames.objectAtIndex(i));
+ for (int i = 0; i < _storedProcedureNames.count(); i++)
+ storedProcedureNamed((String) _storedProcedureNames.objectAtIndex(i));
}
return _storedProcedures.allValues();
}
@@ -172,6 +174,7 @@ public class EOModel {
public void setAdaptorName(String value) {
_adaptorName = value;
}
+
public String adaptorName() {
return _adaptorName;
}
@@ -181,8 +184,8 @@ public class EOModel {
return _entitiesByName.allValues();
NSMutableArray es = new NSMutableArray();
for (int i = 0; i < _entities.count(); i++) {
- NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
- es.addObject(entityNamed((String)d.objectForKey("name")));
+ NSDictionary d = (NSDictionary) _entities.objectAtIndex(i);
+ es.addObject(entityNamed((String) d.objectForKey("name")));
}
return es;
}
@@ -192,18 +195,18 @@ public class EOModel {
return _entitiesByName.allKeys();
NSMutableArray names = new NSMutableArray();
for (int i = 0; i < _entities.count(); i++) {
- NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) _entities.objectAtIndex(i);
names.addObject(d.objectForKey("name"));
}
return names;
}
public EOEntity entityNamed(String name) {
- EOEntity e = (EOEntity)_entitiesByName.objectForKey(name);
+ EOEntity e = (EOEntity) _entitiesByName.objectForKey(name);
if (e == null && path() != null) {
boolean exists = false;
for (int i = 0; i < _entities.count(); i++) {
- NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) _entities.objectAtIndex(i);
if (d.objectForKey("name").equals(name))
exists = true;
}
@@ -242,6 +245,7 @@ public class EOModel {
public void setModelGroup(EOModelGroup group) {
_group = group;
}
+
public EOModelGroup modelGroup() {
return _group;
}
@@ -266,7 +270,8 @@ public class EOModel {
File[] kids = f.listFiles();
for (int i = 0; i < kids.length; i++) {
String fname = kids[i].getName();
- if (kids[i].isFile() && (fname.endsWith(".plist") || fname.endsWith(".eomodeld") || fname.endsWith(".fspec") || fname.endsWith(".storedProcedure")))
+ if (kids[i].isFile() && (fname.endsWith(".plist") || fname.endsWith(".eomodeld")
+ || fname.endsWith(".fspec") || fname.endsWith(".storedProcedure")))
kids[i].delete();
}
} else
@@ -275,7 +280,7 @@ public class EOModel {
f.mkdirs();
File kid = new File(f, "index.eomodeld");
- //encode the index file
+ // encode the index file
NSMutableDictionary d = new NSMutableDictionary();
d.setObjectForKey(_adaptorName, "adaptorName");
d.setObjectForKey("2.1", "EOModelVersion");
@@ -287,23 +292,24 @@ public class EOModel {
if (_storedProcedureNames.count() > 0)
d.setObjectForKey(_storedProcedureNames, "storedProcedures");
- //encode the entity list
+ // encode the entity list
entities();
storedProcedures();
NSMutableArray arr = new NSMutableArray(_entitiesByName.count());
Enumeration enumeration = _entitiesByName.keyEnumerator();
NSMutableDictionary md = new NSMutableDictionary();
while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- EOEntity ent = (EOEntity)_entitiesByName.objectForKey(key);
+ String key = (String) enumeration.nextElement();
+ EOEntity ent = (EOEntity) _entitiesByName.objectForKey(key);
md.removeAllObjects();
ent.encodeIntoPropertyList(md);
File plist;
- NSDictionary fetchSpecs = (NSDictionary)md.objectForKey("fetchSpecificationDictionary");
+ NSDictionary fetchSpecs = (NSDictionary) md.objectForKey("fetchSpecificationDictionary");
if (fetchSpecs != null) {
if (fetchSpecs.count() > 0) {
plist = new File(f, key + ".fspec");
- String ps = NSPropertyListSerialization.stringForPropertyList(md.objectForKey("fetchSpecificationDictionary"));
+ String ps = NSPropertyListSerialization
+ .stringForPropertyList(md.objectForKey("fetchSpecificationDictionary"));
try {
PrintStream stream = new PrintStream(new FileOutputStream(plist));
stream.println(ps);
@@ -321,14 +327,13 @@ public class EOModel {
stream.close();
} catch (IOException ex) {
}
- //add to the entity list for the index
- arr.addObject(new NSDictionary(
- new Object[]{ ent.name(), ent.className() },
- new Object[]{ "name", "className" }));
+ // add to the entity list for the index
+ arr.addObject(new NSDictionary(new Object[] { ent.name(), ent.className() },
+ new Object[] { "name", "className" }));
}
d.setObjectForKey(arr, "entities");
- //write the index file
+ // write the index file
String s = NSPropertyListSerialization.stringForPropertyList(d);
try {
PrintStream stream = new PrintStream(new FileOutputStream(kid));
@@ -338,9 +343,10 @@ public class EOModel {
throw new RuntimeException("Cannot write index.eomodeld");
}
- //write the stored procedures
+ // write the stored procedures
for (int i = 0; i < _storedProcedureNames.count(); i++) {
- EOStoredProcedure proc = (EOStoredProcedure)_storedProcedures.objectForKey(_storedProcedureNames.objectAtIndex(i));
+ EOStoredProcedure proc = (EOStoredProcedure) _storedProcedures
+ .objectForKey(_storedProcedureNames.objectAtIndex(i));
kid = new File(f, proc.name() + ".storedProcedure");
d.removeAllObjects();
proc.encodeIntoPropertyList(d);
@@ -358,39 +364,36 @@ public class EOModel {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.8 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.7 2003/08/13 20:46:12 chochos
- * entityNamed() only throws if the searched entity is in the entities array and not in a file.
+ * Revision 1.7 2003/08/13 20:46:12 chochos entityNamed() only throws if the
+ * searched entity is in the entities array and not in a file.
*
- * Revision 1.6 2003/08/12 01:45:04 chochos
- * added some code to handle prototypes
+ * Revision 1.6 2003/08/12 01:45:04 chochos added some code to handle prototypes
*
- * Revision 1.5 2003/08/11 19:38:27 chochos
- * Can now read from a file and re-write to another file.
+ * Revision 1.5 2003/08/11 19:38:27 chochos Can now read from a file and
+ * re-write to another file.
*
- * Revision 1.4 2003/08/11 18:20:08 chochos
- * saving to a file seems to work now.
+ * Revision 1.4 2003/08/11 18:20:08 chochos saving to a file seems to work now.
*
- * Revision 1.3 2003/08/08 02:16:55 chochos
- * can now read stored procedures from file.
+ * Revision 1.3 2003/08/08 02:16:55 chochos can now read stored procedures from
+ * file.
*
- * Revision 1.2 2003/08/08 00:37:00 chochos
- * add stored procedure functionality
+ * Revision 1.2 2003/08/08 00:37:00 chochos add stored procedure functionality
*
- * Revision 1.1 2003/08/07 02:42:28 chochos
- * EOModel can read an .eomodeld file. EOModelGroup doesn't do much for now.
+ * Revision 1.1 2003/08/07 02:42:28 chochos EOModel can read an .eomodeld file.
+ * EOModelGroup doesn't do much for now.
*
-*/ \ No newline at end of file
+ */ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModelGroup.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModelGroup.java
index dbab09d..70c1088 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModelGroup.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOModelGroup.java
@@ -24,14 +24,14 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A group of models that connect to the same database. Entities in
-* these models can have relationships that point to other entities
-* in any model of the same group.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * A group of models that connect to the same database. Entities in these models
+ * can have relationships that point to other entities in any model of the same
+ * group.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOModelGroup {
private static EOModelGroup _defaultGroup;
@@ -46,14 +46,14 @@ public class EOModelGroup {
if (model.name() == null)
throw new IllegalArgumentException("Cannot add an unnamed model to a group.");
if (_models.objectForKey(model.name()) != null)
- throw new IllegalArgumentException("Cannot add model " + model.name() +
- " to group because it already contains a model with the same name.");
+ throw new IllegalArgumentException("Cannot add model " + model.name()
+ + " to group because it already contains a model with the same name.");
NSArray ents = model.entityNames();
for (int i = 0; i < ents.count(); i++) {
- String ename = (String)ents.objectAtIndex(i);
+ String ename = (String) ents.objectAtIndex(i);
if (entityNamed(ename) != null)
- throw new IllegalArgumentException("Cannot add model " + model.name() +
- " to group because it contains entity named " + ename);
+ throw new IllegalArgumentException(
+ "Cannot add model " + model.name() + " to group because it contains entity named " + ename);
}
_models.setObjectForKey(model, model.name());
}
@@ -73,6 +73,7 @@ public class EOModelGroup {
public static void setDefaultGroup(EOModelGroup group) {
_defaultGroup = group;
}
+
public static EOModelGroup defaultGroup() {
if (_defaultGroup == null) {
_defaultGroup = globalModelGroup();
@@ -83,7 +84,7 @@ public class EOModelGroup {
public static EOModelGroup globalModelGroup() {
if (_globalGroup == null) {
_globalGroup = new EOModelGroup();
- //TODO: read all frameworks and get models from them
+ // TODO: read all frameworks and get models from them
}
return _globalGroup;
}
@@ -95,7 +96,7 @@ public class EOModelGroup {
public EOEntity entityNamed(String name) {
java.util.Enumeration enumeration = _models.objectEnumerator();
while (enumeration.hasMoreElements()) {
- EOModel m = (EOModel)enumeration.nextElement();
+ EOModel m = (EOModel) enumeration.nextElement();
if (m.entityNamed(name) != null)
return m.entityNamed(name);
}
@@ -103,7 +104,7 @@ public class EOModelGroup {
}
public EOModel modelNamed(String name) {
- return (EOModel)_models.objectForKey(name);
+ return (EOModel) _models.objectForKey(name);
}
public NSArray modelNames() {
@@ -117,7 +118,7 @@ public class EOModelGroup {
public EOModel modelWithPath(String path) {
java.util.Enumeration enumeration = _models.objectEnumerator();
while (enumeration.hasMoreElements()) {
- EOModel m = (EOModel)enumeration.nextElement();
+ EOModel m = (EOModel) enumeration.nextElement();
if (m.path() != null && m.path().equals(path))
return m;
}
@@ -127,7 +128,7 @@ public class EOModelGroup {
public EOStoredProcedure storedProcedureNamed(String name) {
java.util.Enumeration enumeration = _models.objectEnumerator();
while (enumeration.hasMoreElements()) {
- EOModel m = (EOModel)enumeration.nextElement();
+ EOModel m = (EOModel) enumeration.nextElement();
if (m.storedProcedureNamed(name) != null)
return m.storedProcedureNamed(name);
}
@@ -144,12 +145,12 @@ public class EOModelGroup {
public void loadAllModelObjects() {
java.util.Enumeration enumeration = _models.objectEnumerator();
while (enumeration.hasMoreElements()) {
- EOModel m = (EOModel)enumeration.nextElement();
- //this causes all entities to be loaded
+ EOModel m = (EOModel) enumeration.nextElement();
+ // this causes all entities to be loaded
NSArray ents = m.entities();
- for (int i=0; i<ents.count(); i++) {
- EOEntity e = (EOEntity)ents.objectAtIndex(i);
- //this loads all the fetch specifications
+ for (int i = 0; i < ents.count(); i++) {
+ EOEntity e = (EOEntity) ents.objectAtIndex(i);
+ // this loads all the fetch specifications
e.fetchSpecificationNamed("whatever");
}
}
@@ -160,39 +161,39 @@ public class EOModelGroup {
d.setObjectForKey(group, "ModelGroup");
coord.setUserInfo(d);
}
+
public static EOModelGroup modelGroupForObjectStoreCoordinator(EOObjectStoreCoordinator coord) {
NSDictionary d = coord.userInfo();
if (d == null)
return defaultGroup();
Object g = d.objectForKey("ModelGroup");
if (g != null && g instanceof EOModelGroup)
- return (EOModelGroup)g;
+ return (EOModelGroup) g;
return defaultGroup();
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.4 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.3 2003/08/08 00:44:04 chochos
- * manage model groups for object store coordinators.
+ * Revision 1.3 2003/08/08 00:44:04 chochos manage model groups for object store
+ * coordinators.
*
- * Revision 1.2 2003/08/08 00:36:41 chochos
- * add a little more functionality
+ * Revision 1.2 2003/08/08 00:36:41 chochos add a little more functionality
*
- * Revision 1.1 2003/08/07 02:42:28 chochos
- * EOModel can read an .eomodeld file. EOModelGroup doesn't do much for now.
+ * Revision 1.1 2003/08/07 02:42:28 chochos EOModel can read an .eomodeld file.
+ * EOModelGroup doesn't do much for now.
*
-*/ \ No newline at end of file
+ */ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOProperty.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOProperty.java
index 89f1fea..10eaa74 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOProperty.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOProperty.java
@@ -18,12 +18,12 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.access;
/**
-* Abstract superclass of EOAttribute and EORelationship.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * Abstract superclass of EOAttribute and EORelationship.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public abstract class EOProperty {
public EOProperty() {
@@ -36,11 +36,10 @@ public abstract class EOProperty {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/08 06:51:37 chochos
- * abstract superclass for relationships and attributes
+ * Revision 1.1 2003/08/08 06:51:37 chochos abstract superclass for
+ * relationships and attributes
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOPropertyListEncoding.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOPropertyListEncoding.java
index af456d2..2b7e9cf 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOPropertyListEncoding.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOPropertyListEncoding.java
@@ -21,13 +21,13 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* Implemented by classes that are read from property lists and that
-* can be written back to property lists.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * Implemented by classes that are read from property lists and that can be
+ * written back to property lists.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public interface EOPropertyListEncoding {
public abstract void awakeWithPropertyList(NSDictionary plist);
@@ -36,18 +36,16 @@ public interface EOPropertyListEncoding {
}
-/* $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+/*
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
-/* Revision 1.1 2006/02/16 13:19:57 cgruber
-/* Check in all sources in eclipse-friendly maven-enabled packages.
-/*
-/* Revision 1.1 2003/08/09 01:34:43 chochos
-/* an interface to provide property list encoding capabilities
-/*
+ * /* Revision 1.1 2006/02/16 13:19:57 cgruber /* Check in all sources in
+ * eclipse-friendly maven-enabled packages. /* /* Revision 1.1 2003/08/09
+ * 01:34:43 chochos /* an interface to provide property list encoding
+ * capabilities /*
*
*/
- \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOQualifierSQLGeneration.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOQualifierSQLGeneration.java
index 4627f76..e7dff0f 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOQualifierSQLGeneration.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOQualifierSQLGeneration.java
@@ -27,15 +27,14 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public interface EOQualifierSQLGeneration {
- public EOQualifier qualifierMigratedFromEntityRelationshipPath(
- EOEntity entity, String path);
+ public EOQualifier qualifierMigratedFromEntityRelationshipPath(EOEntity entity, String path);
public EOQualifier schemaBasedQualifierWithRootEntity(EOEntity entity);
@@ -60,8 +59,9 @@ public interface EOQualifierSQLGeneration {
public static void setSupportForClass(Support sup, Class aClass) {
_classes.setObjectForKey(sup, aClass.getName());
}
+
public static Support supportForClass(Class aClass) {
- return (Support)_classes.objectForKey(aClass.getName());
+ return (Support) _classes.objectForKey(aClass.getName());
}
public abstract String sqlStringForSQLExpression(EOQualifier q, EOSQLExpression exp);
@@ -79,7 +79,7 @@ public interface EOQualifierSQLGeneration {
}
public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression exp) {
- EOKeyValueQualifier q = (EOKeyValueQualifier)qualifier;
+ EOKeyValueQualifier q = (EOKeyValueQualifier) qualifier;
String sql1 = exp.sqlStringForAttributeNamed(q.key());
String sql2 = exp.sqlStringForSelector(q.selector(), q.value());
String sql3 = exp.sqlStringForValue(q.value(), q.key());
@@ -87,7 +87,7 @@ public interface EOQualifierSQLGeneration {
return exp.sqlStringForCaseInsensitiveLike(sql1, sql3);
else if (q.selector() == EOQualifier.QualifierOperatorLike)
sql3 = exp.sqlPatternFromShellPattern(sql3);
- return sql1 + sql2 + sql3;
+ return sql1 + sql2 + sql3;
}
public EOQualifier schemaBasedQualifierWithRootEntity(EOQualifier q, EOEntity e) {
@@ -107,10 +107,9 @@ public interface EOQualifierSQLGeneration {
}
public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression exp) {
- EOKeyComparisonQualifier q = (EOKeyComparisonQualifier)qualifier;
- return exp.sqlStringForAttributeNamed(q.leftKey()) +
- exp.sqlStringForSelector(q.selector(), null) +
- exp.sqlStringForAttributeNamed(q.rightKey());
+ EOKeyComparisonQualifier q = (EOKeyComparisonQualifier) qualifier;
+ return exp.sqlStringForAttributeNamed(q.leftKey()) + exp.sqlStringForSelector(q.selector(), null)
+ + exp.sqlStringForAttributeNamed(q.rightKey());
}
public EOQualifier schemaBasedQualifierWithRootEntity(EOQualifier q, EOEntity e) {
@@ -130,18 +129,21 @@ public interface EOQualifierSQLGeneration {
}
public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression exp) {
- EONotQualifier q = (EONotQualifier)qualifier;
- return "NOT (" + EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass()).sqlStringForSQLExpression(q.qualifier(), exp) + ")";
+ EONotQualifier q = (EONotQualifier) qualifier;
+ return "NOT (" + EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass())
+ .sqlStringForSQLExpression(q.qualifier(), exp) + ")";
}
public EOQualifier schemaBasedQualifierWithRootEntity(EOQualifier qualifier, EOEntity e) {
- EONotQualifier q = (EONotQualifier)qualifier;
- return new EONotQualifier(EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass()).schemaBasedQualifierWithRootEntity(q.qualifier(), e));
+ EONotQualifier q = (EONotQualifier) qualifier;
+ return new EONotQualifier(EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass())
+ .schemaBasedQualifierWithRootEntity(q.qualifier(), e));
}
public EOQualifier qualifierMigratedFromEntityRelationshipPath(EOQualifier qualifier, EOEntity e, String path) {
- EONotQualifier q = (EONotQualifier)qualifier;
- return new EONotQualifier(EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass()).qualifierMigratedFromEntityRelationshipPath(q.qualifier(), e, path));
+ EONotQualifier q = (EONotQualifier) qualifier;
+ return new EONotQualifier(EOQualifierSQLGeneration.Support.supportForClass(q.qualifier().getClass())
+ .qualifierMigratedFromEntityRelationshipPath(q.qualifier(), e, path));
}
}
@@ -153,16 +155,16 @@ public interface EOQualifierSQLGeneration {
}
public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression exp) {
- EOAndQualifier q = (EOAndQualifier)qualifier;
+ EOAndQualifier q = (EOAndQualifier) qualifier;
NSArray qus = q.qualifiers();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < qus.count(); i++) {
- EOQualifier sub = (EOQualifier)qus.objectAtIndex(i);
+ EOQualifier sub = (EOQualifier) qus.objectAtIndex(i);
EOQualifierSQLGeneration.Support sup = EOQualifierSQLGeneration.Support.supportForClass(sub.getClass());
if (sup == null)
throw new IllegalStateException("Cannot find support class for " + sub.getClass().getName());
buf.append(sup.sqlStringForSQLExpression(sub, exp));
- if (i < qus.count()-1)
+ if (i < qus.count() - 1)
buf.append(" AND ");
}
if (qus.count() > 1) {
@@ -189,16 +191,16 @@ public interface EOQualifierSQLGeneration {
}
public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression exp) {
- EOOrQualifier q = (EOOrQualifier)qualifier;
+ EOOrQualifier q = (EOOrQualifier) qualifier;
NSArray qus = q.qualifiers();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < qus.count(); i++) {
- EOQualifier sub = (EOQualifier)qus.objectAtIndex(i);
+ EOQualifier sub = (EOQualifier) qus.objectAtIndex(i);
EOQualifierSQLGeneration.Support sup = EOQualifierSQLGeneration.Support.supportForClass(sub.getClass());
if (sup == null)
throw new IllegalStateException("Cannot find support class for " + sub.getClass().getName());
buf.append(sup.sqlStringForSQLExpression(sub, exp));
- if (i < qus.count()-1)
+ if (i < qus.count() - 1)
buf.append(" OR ");
}
if (qus.count() > 1) {
@@ -220,22 +222,23 @@ public interface EOQualifierSQLGeneration {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/14 02:13:10 chochos
- * KeyValueQualifierSupport generates proper SQL
+ * Revision 1.3 2003/08/14 02:13:10 chochos KeyValueQualifierSupport generates
+ * proper SQL
*
- * Revision 1.2 2003/08/14 01:05:51 chochos
- * added abstract Support inner class, with incomplete implementations for the main qualifiers (not, and, or, key-value, key-comparison)
+ * Revision 1.2 2003/08/14 01:05:51 chochos added abstract Support inner class,
+ * with incomplete implementations for the main qualifiers (not, and, or,
+ * key-value, key-comparison)
*
- * Revision 1.1 2003/08/12 01:45:49 chochos
- * interface to be implemented by qualifiers (or support classes) to indicate they can generate SQL
+ * Revision 1.1 2003/08/12 01:45:49 chochos interface to be implemented by
+ * qualifiers (or support classes) to indicate they can generate SQL
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EORelationship.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EORelationship.java
index a5a207f..4efd068 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EORelationship.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EORelationship.java
@@ -21,13 +21,15 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
+
/**
-* Represents a relationship from one entity to another. Relationships are unidirectional.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * Represents a relationship from one entity to another. Relationships are
+ * unidirectional.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EORelationship extends EOProperty implements EOPropertyListEncoding {
public static final int InnerJoin = 0;
@@ -60,14 +62,14 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public EORelationship(NSDictionary dict, Object obj) {
super();
- _entity = (EOEntity)obj;
- setName((String)dict.objectForKey("name"));
+ _entity = (EOEntity) obj;
+ setName((String) dict.objectForKey("name"));
setToMany("Y".equals(dict.objectForKey("isToMany")));
setPropagatesPrimaryKey("Y".equals(dict.objectForKey("propagatesPrimaryKey")));
setIsMandatory("Y".equals(dict.objectForKey("isMandatory")));
setOwnsDestination("Y".equals(dict.objectForKey("ownsDestination")));
- setDefinition((String)dict.objectForKey("definition"));
- String delrule = (String)dict.objectForKey("deleteRule");
+ setDefinition((String) dict.objectForKey("definition"));
+ String delrule = (String) dict.objectForKey("deleteRule");
if (delrule != null) {
if (delrule.equals("EODeleteRuleCascade"))
setDeleteRule(0);
@@ -78,7 +80,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
else if (delrule.equals("EODeleteRuleNullify"))
setDeleteRule(0);
}
- delrule = (String)dict.objectForKey("joinSemantic");
+ delrule = (String) dict.objectForKey("joinSemantic");
if (delrule != null) {
if (delrule.equals("EOInnerJoin"))
setJoinSemantic(InnerJoin);
@@ -89,13 +91,13 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
else if (delrule.equals("EORightOuterJoin"))
setJoinSemantic(RightOuterJoin);
}
- delrule = (String)dict.objectForKey("batchCount");
+ delrule = (String) dict.objectForKey("batchCount");
if (delrule != null)
setNumberOfToManyFaultsToBatchFetch(Integer.parseInt(delrule));
- NSDictionary d = (NSDictionary)dict.objectForKey("userInfo");
+ NSDictionary d = (NSDictionary) dict.objectForKey("userInfo");
if (d != null)
_userInfo = d;
- d = (NSDictionary)dict.objectForKey("internalInfo");
+ d = (NSDictionary) dict.objectForKey("internalInfo");
if (d != null)
_internalInfo = d;
plist = dict;
@@ -104,6 +106,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setName(String name) {
_name = name;
}
+
public String name() {
return _name;
}
@@ -125,7 +128,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
if (_destination == null && plist != null) {
EOModel model = _entity.model();
EOModelGroup group = model.modelGroup();
- String destEntity = (String)plist.objectForKey("destination");
+ String destEntity = (String) plist.objectForKey("destination");
if (group != null)
_destination = group.entityNamed(destEntity);
else
@@ -137,6 +140,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setOwnsDestination(boolean flag) {
_ownsDestination = flag;
}
+
public boolean ownsDestination() {
return _ownsDestination;
}
@@ -144,6 +148,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setToMany(boolean flag) {
_isToMany = flag;
}
+
public boolean isToMany() {
return _isToMany;
}
@@ -151,6 +156,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setIsMandatory(boolean flag) {
_isMandatory = flag;
}
+
public boolean isMandatory() {
return _isMandatory;
}
@@ -158,6 +164,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setPropagatesPrimaryKey(boolean flag) {
_propagatesPrimaryKey = flag;
}
+
public boolean propagatesPrimaryKey() {
return _propagatesPrimaryKey;
}
@@ -165,6 +172,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setDeleteRule(int value) {
_deleteRule = value;
}
+
public int deleteRule() {
return _deleteRule;
}
@@ -172,6 +180,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setJoinSemantic(int value) {
_joinSemantic = value;
}
+
public int joinSemantic() {
return _joinSemantic;
}
@@ -179,17 +188,18 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setNumberOfToManyFaultsToBatchFetch(int count) {
_batchCount = count;
}
+
public int numberOfToManyFaultsToBatchFetch() {
return _batchCount;
}
public NSArray joins() {
if (_joins.count() == 0 && plist != null) {
- NSArray joins = (NSArray)plist.objectForKey("joins");
+ NSArray joins = (NSArray) plist.objectForKey("joins");
for (int i = 0; i < joins.count(); i++) {
- NSDictionary d = (NSDictionary)joins.objectAtIndex(i);
- String srcName = (String)d.objectForKey("sourceAttribute");
- String dstName = (String)d.objectForKey("destinationAttribute");
+ NSDictionary d = (NSDictionary) joins.objectAtIndex(i);
+ String srcName = (String) d.objectForKey("sourceAttribute");
+ String dstName = (String) d.objectForKey("destinationAttribute");
EOAttribute a1 = _entity.attributeNamed(srcName);
EOAttribute a2 = destinationEntity().attributeNamed(dstName);
EOJoin j = new EOJoin(a1, a2);
@@ -202,6 +212,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setDefinition(String def) {
_definition = def;
}
+
public String definition() {
return _definition;
}
@@ -218,7 +229,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
EORelationship r = null;
EOEntity e = entity();
for (int i = 0; i < comps.count(); i++) {
- String name = (String)comps.objectAtIndex(i);
+ String name = (String) comps.objectAtIndex(i);
r = e.relationshipNamed(name);
if (r == null)
return false;
@@ -242,6 +253,7 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
public void setUserInfo(NSDictionary value) {
_userInfo = value;
}
+
public NSDictionary userInfo() {
return _userInfo;
}
@@ -260,18 +272,18 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
if (isToMany())
dict.setObjectForKey("Y", "isToMany");
switch (_joinSemantic) {
- case InnerJoin:
- dict.setObjectForKey("EOInnerJoin", "joinSemantic");
- break;
- case FullOuterJoin:
- dict.setObjectForKey("EOFullOuterJoin", "joinSemantic");
- break;
- case LeftOuterJoin:
- dict.setObjectForKey("EOLefOuterJoin", "joinSemantic");
- break;
- case RightOuterJoin:
- dict.setObjectForKey("EORightOuterJoin", "joinSemantic");
- break;
+ case InnerJoin:
+ dict.setObjectForKey("EOInnerJoin", "joinSemantic");
+ break;
+ case FullOuterJoin:
+ dict.setObjectForKey("EOFullOuterJoin", "joinSemantic");
+ break;
+ case LeftOuterJoin:
+ dict.setObjectForKey("EOLefOuterJoin", "joinSemantic");
+ break;
+ case RightOuterJoin:
+ dict.setObjectForKey("EORightOuterJoin", "joinSemantic");
+ break;
}
if (_batchCount > 0)
dict.setObjectForKey(new Integer(_batchCount), "batchCount");
@@ -280,10 +292,10 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
else {
NSMutableArray jarr = new NSMutableArray(joins().count());
for (int i = 0; i < _joins.count(); i++) {
- EOJoin j = (EOJoin)_joins.objectAtIndex(i);
+ EOJoin j = (EOJoin) _joins.objectAtIndex(i);
NSDictionary d = new NSDictionary(
- new Object[]{ j.sourceAttribute().name(), j.destinationAttribute().name() },
- new Object[]{ "sourceAttribute", "destinationAttribute" });
+ new Object[] { j.sourceAttribute().name(), j.destinationAttribute().name() },
+ new Object[] { "sourceAttribute", "destinationAttribute" });
jarr.addObject(d);
}
dict.setObjectForKey(jarr, "joins");
@@ -292,28 +304,25 @@ public class EORelationship extends EOProperty implements EOPropertyListEncoding
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:13 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:13 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/11 19:38:27 chochos
- * Can now read from a file and re-write to another file.
+ * Revision 1.5 2003/08/11 19:38:27 chochos Can now read from a file and
+ * re-write to another file.
*
- * Revision 1.4 2003/08/09 01:35:35 chochos
- * implement EOPropertyListEncoding
+ * Revision 1.4 2003/08/09 01:35:35 chochos implement EOPropertyListEncoding
*
- * Revision 1.3 2003/08/08 06:51:53 chochos
- * isFlattened() works
+ * Revision 1.3 2003/08/08 06:51:53 chochos isFlattened() works
*
- * Revision 1.2 2003/08/08 02:17:43 chochos
- * main accessors are in place.
+ * Revision 1.2 2003/08/08 02:17:43 chochos main accessors are in place.
*
- * Revision 1.1 2003/08/07 02:41:30 chochos
- * a relationship that for the moment can be created from a property list.
+ * Revision 1.1 2003/08/07 02:41:30 chochos a relationship that for the moment
+ * can be created from a property list.
*
-*/ \ No newline at end of file
+ */ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpression.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpression.java
index 4cb15e5..c2b6e76 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpression.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpression.java
@@ -37,10 +37,10 @@ import net.wotonomy.foundation.NSTimestamp;
import net.wotonomy.foundation.NSTimestampFormatter;
/**
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public abstract class EOSQLExpression {
public static final String BindVariableAttributeKey = "BindVariableAttribute";
@@ -54,9 +54,8 @@ public abstract class EOSQLExpression {
private static final int _DefaultOrderByStringLength = 128;
private static final int _DefaultPathLength = 128;
private static final int _DefaultTableListLength = 128;
- protected static final char[] _hexChars = new char[]{
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
+ protected static final char[] _hexChars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F' };
private static final int _ValueLengthLimit = 40;
protected NSMutableDictionary _aliasesByRelationshipPath;
protected NSMutableDictionary _aliasesByEntityName;
@@ -77,7 +76,7 @@ public abstract class EOSQLExpression {
private EOSQLExpression() {
super();
}
-
+
public EOSQLExpression(EOEntity entity) {
super();
_entity = entity;
@@ -88,7 +87,7 @@ public abstract class EOSQLExpression {
}
public String _aliasForRelationshipPath(String path) {
- return (String)_aliasesByRelationshipPath.objectForKey(path);
+ return (String) _aliasesByRelationshipPath.objectForKey(path);
}
protected NSTimestampFormatter _defaultDateFormatter() {
@@ -115,7 +114,7 @@ public abstract class EOSQLExpression {
_entity = value;
}
- public String _sqlStringForJoinSemanticMatchSemantic(int semantic,int match) {
+ public String _sqlStringForJoinSemanticMatchSemantic(int semantic, int match) {
return null;
}
@@ -129,11 +128,13 @@ public abstract class EOSQLExpression {
return _valueListString;
}
- public void addBindVariableDictionary( NSDictionary dict ) {
+ public void addBindVariableDictionary(NSDictionary dict) {
}
- /** Adds the SQL to create the attribute to the attribute list.
- * The appended text is of the form attr_name attr_type allow_null
+ /**
+ * Adds the SQL to create the attribute to the attribute list. The appended text
+ * is of the form attr_name attr_type allow_null
+ *
* @param attr The attribute to create the SQL for.
*/
public void addCreateClauseForAttribute(EOAttribute attr) {
@@ -158,9 +159,11 @@ public abstract class EOSQLExpression {
public void addOrderByAttributeOrdering(EOSortOrdering order) {
String sql = sqlStringForAttributeNamed(order.key());
- if (order.selector().equals(EOSortOrdering.CompareCaseInsensitiveAscending) || order.selector().equals(EOSortOrdering.CompareCaseInsensitiveDescending))
+ if (order.selector().equals(EOSortOrdering.CompareCaseInsensitiveAscending)
+ || order.selector().equals(EOSortOrdering.CompareCaseInsensitiveDescending))
sql = "UPPER(" + sql + ")";
- if (order.selector().equals(EOSortOrdering.CompareCaseInsensitiveAscending) || order.selector().equals(EOSortOrdering.CompareAscending))
+ if (order.selector().equals(EOSortOrdering.CompareCaseInsensitiveAscending)
+ || order.selector().equals(EOSortOrdering.CompareAscending))
sql += " ASC";
else
sql += " DESC";
@@ -205,8 +208,8 @@ public abstract class EOSQLExpression {
return s;
}
- public String assembleInsertStatementWithRow(NSDictionary row,
- String tableList, String columnList, String valueList) {
+ public String assembleInsertStatementWithRow(NSDictionary row, String tableList, String columnList,
+ String valueList) {
String sql = "INSERT INTO " + tableList;
if (columnList != null)
sql += " (" + columnList + ")";
@@ -223,9 +226,9 @@ public abstract class EOSQLExpression {
return leftName + op + rightName;
}
- public String assembleSelectStatementWithAttributes(NSArray attributes,
- boolean lock, EOQualifier q, NSArray fetchOrder, String selectString, String columnList,
- String tableList, String whereClause, String joinClause, String orderByClause, String lockClause) {
+ public String assembleSelectStatementWithAttributes(NSArray attributes, boolean lock, EOQualifier q,
+ NSArray fetchOrder, String selectString, String columnList, String tableList, String whereClause,
+ String joinClause, String orderByClause, String lockClause) {
String sql = selectString + " " + columnList + " FROM " + tableList;
if (lockClause != null)
sql += " " + lockClause;
@@ -242,7 +245,8 @@ public abstract class EOSQLExpression {
return sql;
}
- public String assembleUpdateStatementWithRow(NSDictionary row, EOQualifier q, String tableList, String updateList, String whereClause) {
+ public String assembleUpdateStatementWithRow(NSDictionary row, EOQualifier q, String tableList, String updateList,
+ String whereClause) {
String s = "UPDATE " + tableList + " SET " + updateList;
if (whereClause != null && whereClause.length() > 0)
s += " WHERE " + whereClause;
@@ -280,14 +284,14 @@ public abstract class EOSQLExpression {
}
/**
- * Returns the received string wrapped in single quotes,
- * with any quotes or escape chars found inside it
- * properly escaped.
+ * Returns the received string wrapped in single quotes, with any quotes or
+ * escape chars found inside it properly escaped.
+ *
* @param s The string to format.
*/
public String formatStringValue(String s) {
StringBuffer buf = new StringBuffer(s);
- for (int i = buf.length()-1; i >= 0; i--) {
+ for (int i = buf.length() - 1; i >= 0; i--) {
if (buf.charAt(i) == sqlEscapeChar()) {
buf.insert(i, sqlEscapeChar());
i++;
@@ -306,10 +310,10 @@ public abstract class EOSQLExpression {
if (value == null || value == NSKeyValueCoding.NullValue)
return "NULL";
if (value instanceof String)
- return formatStringValue((String)value);
+ return formatStringValue((String) value);
if (value instanceof Number)
- return sqlStringForNumber((Number)value);
- //TODO: format timestamps
+ return sqlStringForNumber((Number) value);
+ // TODO: format timestamps
return value.toString();
}
@@ -338,7 +342,7 @@ public abstract class EOSQLExpression {
}
public String orderByString() {
- if (_orderByString == null)
+ if (_orderByString == null)
return null;
return _orderByString.toString();
}
@@ -356,7 +360,7 @@ public abstract class EOSQLExpression {
StringBuffer values = new StringBuffer("(");
Enumeration enumeration = row.keyEnumerator();
while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
+ String key = (String) enumeration.nextElement();
EOAttribute a = _entity.attributeNamed(key);
cols.append(a.columnName());
values.append(formatValueForAttribute(row.objectForKey(key), a));
@@ -379,30 +383,31 @@ public abstract class EOSQLExpression {
q = fspec.qualifier();
order = fspec.sortOrderings();
}
- //Assemble the column list (this yields the alias list)
+ // Assemble the column list (this yields the alias list)
for (int i = 0; i < atts.count(); i++)
- addSelectListAttribute((EOAttribute)atts.objectAtIndex(i));
- //assemble the where string
+ addSelectListAttribute((EOAttribute) atts.objectAtIndex(i));
+ // assemble the where string
if (q != null) {
if (q instanceof EOQualifierSQLGeneration)
- setWhereClauseString(sqlStringForQualifier((EOQualifierSQLGeneration)q));
+ setWhereClauseString(sqlStringForQualifier((EOQualifierSQLGeneration) q));
else {
EOQualifierSQLGeneration.Support sup = EOQualifierSQLGeneration.Support.supportForClass(q.getClass());
setWhereClauseString(sup.sqlStringForSQLExpression(q, this));
}
}
- //assemble the join string
+ // assemble the join string
joinExpression();
- //assemble the order by string
+ // assemble the order by string
if (order != null && order.count() > 0) {
for (int i = 0; i < order.count(); i++) {
- EOSortOrdering so = (EOSortOrdering)order.objectAtIndex(i);
+ EOSortOrdering so = (EOSortOrdering) order.objectAtIndex(i);
addOrderByAttributeOrdering(so);
}
}
- //create the statement
+ // create the statement
setStatement(assembleSelectStatementWithAttributes(atts, lock, q, order, "SELECT", listString(),
- tableListWithRootEntity(_entity), whereClauseString(), joinClauseString(), orderByString(), lockClause()));
+ tableListWithRootEntity(_entity), whereClauseString(), joinClauseString(), orderByString(),
+ lockClause()));
}
/** Build an UPDATE statement with the given information. */
@@ -410,10 +415,11 @@ public abstract class EOSQLExpression {
StringBuffer buf = new StringBuffer();
Enumeration enumeration = row.keyEnumerator();
while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
+ String key = (String) enumeration.nextElement();
EOAttribute a = _entity.attributeNamed(key);
if (a == null)
- throw new EOGeneralAdaptorException("Cannot find attribute named " + key + " in entity " + _entity.name());
+ throw new EOGeneralAdaptorException(
+ "Cannot find attribute named " + key + " in entity " + _entity.name());
buf.append(a.columnName());
buf.append('=');
buf.append(formatValueForAttribute(row.objectForKey(key), a));
@@ -423,7 +429,8 @@ public abstract class EOSQLExpression {
if (q != null) {
setWhereClauseString(sqlStringForQualifier(null));
}
- setStatement(assembleUpdateStatementWithRow(row, q, _entity.externalName(), buf.toString(), whereClauseString()));
+ setStatement(
+ assembleUpdateStatementWithRow(row, q, _entity.externalName(), buf.toString(), whereClauseString()));
}
public void setStatement(String statement) {
@@ -453,6 +460,7 @@ public abstract class EOSQLExpression {
public static void setUseQuotedExternalNames(boolean flag) {
_quoteExternalNames = flag;
}
+
/** @deprecated Use the instance method externalNameQuoteCharacter instead. */
public static boolean useQuotedExternalNames() {
return _quoteExternalNames;
@@ -481,33 +489,33 @@ public abstract class EOSQLExpression {
public String sqlPatternFromShellPatternWithEscapeCharacter(String pattern, char escape) {
StringBuffer buf = new StringBuffer(pattern);
int idx = 0;
- //escape all '%'
+ // escape all '%'
do {
idx = buf.indexOf("%");
if (idx == 0)
buf.insert(escape, 0);
- else if (idx > 0 && buf.charAt(idx-1) != escape)
+ else if (idx > 0 && buf.charAt(idx - 1) != escape)
buf.insert(escape, idx);
} while (idx >= 0);
- //escape all '_'
+ // escape all '_'
do {
idx = buf.indexOf("_");
if (idx == 0)
buf.insert(escape, 0);
- else if (idx > 0 && buf.charAt(idx-1) != escape)
+ else if (idx > 0 && buf.charAt(idx - 1) != escape)
buf.insert(escape, idx);
} while (idx >= 0);
- //substitute all '*'
+ // substitute all '*'
do {
idx = buf.indexOf("*");
if (idx >= 0)
- buf.replace(idx, idx+1, "%");
+ buf.replace(idx, idx + 1, "%");
} while (idx >= 0);
- //substitute all '?'
+ // substitute all '?'
do {
idx = buf.indexOf("?");
if (idx >= 0)
- buf.replace(idx, idx+1, "_");
+ buf.replace(idx, idx + 1, "_");
} while (idx >= 0);
return buf.toString();
}
@@ -515,7 +523,7 @@ public abstract class EOSQLExpression {
public String sqlStringForAttribute(EOAttribute attr) {
if (_aliasesByEntityName == null)
_aliasesByEntityName = new NSMutableDictionary();
- String alias = (String)_aliasesByEntityName.objectForKey(attr.entity().name());
+ String alias = (String) _aliasesByEntityName.objectForKey(attr.entity().name());
if (alias == null) {
alias = "t" + (_aliasesByEntityName.count() + 1);
_aliasesByEntityName.setObjectForKey(alias, attr.entity().name());
@@ -531,20 +539,21 @@ public abstract class EOSQLExpression {
return sqlStringForAttribute(_entity._attributeForPath(name));
}
return sqlStringForAttribute(_entity.attributeNamed(name));
-
+
}
/**
- * Returns a string representing the path from the first
- * relationship in the array to the last one.
+ * Returns a string representing the path from the first relationship in the
+ * array to the last one.
+ *
* @param path An array of EORelationship objects.
- * @return A string consisting of the names of the relationships
- * separated by dots.
+ * @return A string consisting of the names of the relationships separated by
+ * dots.
*/
public String sqlStringForAttributePath(NSArray path) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < path.count(); i++) {
- EORelationship rel = (EORelationship)path.objectAtIndex(i);
+ EORelationship rel = (EORelationship) path.objectAtIndex(i);
if (i > 0)
buf.append('.');
buf.append(rel.name());
@@ -558,7 +567,8 @@ public abstract class EOSQLExpression {
public String sqlStringForConjoinedQualifiers(NSArray qualifiers) {
EOAndQualifier q = new EOAndQualifier(qualifiers);
- return EOQualifierSQLGeneration.Support.supportForClass(EOAndQualifier.class).sqlStringForSQLExpression(q, this);
+ return EOQualifierSQLGeneration.Support.supportForClass(EOAndQualifier.class).sqlStringForSQLExpression(q,
+ this);
}
public String sqlStringForData(NSData data) {
@@ -580,11 +590,13 @@ public abstract class EOSQLExpression {
}
public String sqlStringForKeyComparisonQualifier(EOKeyComparisonQualifier q) {
- return EOQualifierSQLGeneration.Support.supportForClass(EOKeyComparisonQualifier.class).sqlStringForSQLExpression(q, this);
+ return EOQualifierSQLGeneration.Support.supportForClass(EOKeyComparisonQualifier.class)
+ .sqlStringForSQLExpression(q, this);
}
public String sqlStringForKeyValueQualifier(EOKeyValueQualifier q) {
- return EOQualifierSQLGeneration.Support.supportForClass(EOKeyValueQualifier.class).sqlStringForSQLExpression(q, this);
+ return EOQualifierSQLGeneration.Support.supportForClass(EOKeyValueQualifier.class).sqlStringForSQLExpression(q,
+ this);
}
public String sqlStringForNegatedQualifier(EOQualifier q) {
@@ -622,7 +634,8 @@ public abstract class EOSQLExpression {
return "<=";
} else if (sel == EOQualifier.QualifierOperatorGreaterThanOrEqualTo) {
return ">=";
- } else if (sel == EOQualifier.QualifierOperatorLike || sel == EOQualifier.QualifierOperatorCaseInsensitiveLike) {
+ } else if (sel == EOQualifier.QualifierOperatorLike
+ || sel == EOQualifier.QualifierOperatorCaseInsensitiveLike) {
return " like ";
}
return sel.name();
@@ -646,7 +659,7 @@ public abstract class EOSQLExpression {
if (_aliasesByEntityName.count() > 0) {
Enumeration enumeration = _aliasesByEntityName.keyEnumerator();
while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
+ String key = (String) enumeration.nextElement();
if (!key.equals(root.name())) {
buf.append(", ");
buf.append(key);
@@ -668,30 +681,31 @@ public abstract class EOSQLExpression {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.5 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.4 2003/08/29 21:14:18 chochos
- * fix the algorithm in formatStringValue.
+ * Revision 1.4 2003/08/29 21:14:18 chochos fix the algorithm in
+ * formatStringValue.
*
- * Revision 1.3 2003/08/14 02:12:32 chochos
- * implemented use of (simple) qualifiers
+ * Revision 1.3 2003/08/14 02:12:32 chochos implemented use of (simple)
+ * qualifiers
*
- * Revision 1.2 2003/08/13 22:59:39 chochos
- * Can now generate simple one-entity select statements.
+ * Revision 1.2 2003/08/13 22:59:39 chochos Can now generate simple one-entity
+ * select statements.
*
- * Revision 1.1 2003/08/13 01:04:32 chochos
- * the SQL generation classes. EOSQLExpression still needs a lot of work, but the factory is pretty much done.
+ * Revision 1.1 2003/08/13 01:04:32 chochos the SQL generation classes.
+ * EOSQLExpression still needs a lot of work, but the factory is pretty much
+ * done.
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpressionFactory.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpressionFactory.java
index 6bdbffe..4e20a7a 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpressionFactory.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOSQLExpressionFactory.java
@@ -25,11 +25,11 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOSQLExpressionFactory {
protected EOAdaptor _adaptor;
@@ -49,8 +49,9 @@ public class EOSQLExpressionFactory {
}
/**
- * Creates an instance of the adaptor's expression class,
- * with entity assigned to it.
+ * Creates an instance of the adaptor's expression class, with entity assigned
+ * to it.
+ *
* @param entity The entity with which to initialize the expression.
* @return An EOSQLExpression.
*/
@@ -58,13 +59,14 @@ public class EOSQLExpressionFactory {
EOSQLExpression expr = null;
if (_instantiator == null) {
try {
- _instantiator = _expressionClass.getConstructor(new Class[]{ EOEntity.class });
+ _instantiator = _expressionClass.getConstructor(new Class[] { EOEntity.class });
} catch (Exception ex) {
- throw new IllegalArgumentException("The expression class " + _expressionClass.getName() + " has no constructor with an entity parameter.");
+ throw new IllegalArgumentException("The expression class " + _expressionClass.getName()
+ + " has no constructor with an entity parameter.");
}
}
try {
- expr = (EOSQLExpression)_instantiator.newInstance(new Object[]{ entity });
+ expr = (EOSQLExpression) _instantiator.newInstance(new Object[] { entity });
} catch (Exception ex) {
throw new IllegalArgumentException("Cannot create new expression of class " + _expressionClass.getName());
}
@@ -87,7 +89,8 @@ public class EOSQLExpressionFactory {
return expr;
}
- public EOSQLExpression selectStatementForAttributes(NSArray atts, boolean lock, EOFetchSpecification fspec, EOEntity entity) {
+ public EOSQLExpression selectStatementForAttributes(NSArray atts, boolean lock, EOFetchSpecification fspec,
+ EOEntity entity) {
EOSQLExpression expr = createExpression(entity);
expr.prepareSelectExpressionWithAttributes(atts, lock, fspec);
return expr;
@@ -102,7 +105,7 @@ public class EOSQLExpressionFactory {
public EOSQLExpression expressionForString(String sql) {
EOSQLExpression expr = null;
try {
- expr = (EOSQLExpression)_expressionClass.newInstance();
+ expr = (EOSQLExpression) _expressionClass.newInstance();
} catch (Exception e) {
return null;
}
@@ -116,16 +119,17 @@ public class EOSQLExpressionFactory {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/13 01:04:32 chochos
- * the SQL generation classes. EOSQLExpression still needs a lot of work, but the factory is pretty much done.
+ * Revision 1.1 2003/08/13 01:04:32 chochos the SQL generation classes.
+ * EOSQLExpression still needs a lot of work, but the factory is pretty much
+ * done.
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOStoredProcedure.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOStoredProcedure.java
index f38ec2a..6fab43a 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOStoredProcedure.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOStoredProcedure.java
@@ -22,13 +22,14 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
+
/**
-* Represents a stored procedure in a database.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * Represents a stored procedure in a database.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOStoredProcedure implements EOPropertyListEncoding {
protected String _name;
@@ -42,23 +43,23 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
public EOStoredProcedure(NSDictionary dict, Object obj) {
super();
if (obj instanceof EOModel)
- _model = (EOModel)obj;
- NSArray a = (NSArray)dict.objectForKey("arguments");
+ _model = (EOModel) obj;
+ NSArray a = (NSArray) dict.objectForKey("arguments");
if (a != null) {
NSMutableArray args = new NSMutableArray(a.count());
for (int i = 0; i < a.count(); i++) {
- NSDictionary ad = (NSDictionary)a.objectAtIndex(i);
+ NSDictionary ad = (NSDictionary) a.objectAtIndex(i);
EOAttribute arg = new EOAttribute(ad, this);
args.addObject(arg);
}
_arguments = args;
}
- setName((String)dict.objectForKey("name"));
- setExternalName((String)dict.objectForKey("externalName"));
+ setName((String) dict.objectForKey("name"));
+ setExternalName((String) dict.objectForKey("externalName"));
if (dict.objectForKey("userInfo") != null)
- setUserInfo((NSDictionary)dict.objectForKey("userInfo"));
+ setUserInfo((NSDictionary) dict.objectForKey("userInfo"));
if (dict.objectForKey("internalInfo") != null)
- _internalInfo = (NSDictionary)dict.objectForKey("internalInfo");
+ _internalInfo = (NSDictionary) dict.objectForKey("internalInfo");
}
public EOStoredProcedure(String withName) {
@@ -69,6 +70,7 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
public void setName(String value) {
_name = value;
}
+
public String name() {
return _name;
}
@@ -76,6 +78,7 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
public void setExternalName(String value) {
_externalName = value;
}
+
public String externalName() {
return _externalName;
}
@@ -83,6 +86,7 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
public void setArguments(NSArray value) {
_arguments = value;
}
+
public NSArray arguments() {
return _arguments;
}
@@ -94,6 +98,7 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
public void setUserInfo(NSDictionary info) {
_userInfo = info;
}
+
public NSDictionary userInfo() {
return _userInfo;
}
@@ -107,7 +112,7 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
NSMutableArray arr = new NSMutableArray(_arguments.count());
NSMutableDictionary d = null;
for (int i = 0; i < _arguments.count(); i++) {
- EOAttribute a = (EOAttribute)_arguments.objectAtIndex(i);
+ EOAttribute a = (EOAttribute) _arguments.objectAtIndex(i);
d = new NSMutableDictionary();
a.encodeIntoPropertyList(d);
arr.addObject(d);
@@ -117,25 +122,23 @@ public class EOStoredProcedure implements EOPropertyListEncoding {
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/11 19:38:27 chochos
- * Can now read from a file and re-write to another file.
+ * Revision 1.4 2003/08/11 19:38:27 chochos Can now read from a file and
+ * re-write to another file.
*
- * Revision 1.3 2003/08/09 01:36:32 chochos
- * implement EOPropertyListEncoding
+ * Revision 1.3 2003/08/09 01:36:32 chochos implement EOPropertyListEncoding
*
- * Revision 1.2 2003/08/08 02:14:43 chochos
- * can create a stored procedure from a property list. main accessors are in place.
+ * Revision 1.2 2003/08/08 02:14:43 chochos can create a stored procedure from a
+ * property list. main accessors are in place.
*
- * Revision 1.1 2003/08/07 02:41:04 chochos
- * these don't do much for now.
+ * Revision 1.1 2003/08/07 02:41:04 chochos these don't do much for now.
*
-*/ \ No newline at end of file
+ */ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/AbstractObjectStore.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/AbstractObjectStore.java
index ddaacf5..1989582 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/AbstractObjectStore.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/AbstractObjectStore.java
@@ -35,728 +35,638 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* An abstract implementation of object store that
-* implements common functionality. Subclasses must
-* implement data object creation, initialization, and
-* refault logic, as well as logic to commit an editing
-* context.
-*/
-public abstract class AbstractObjectStore extends EOObjectStore
-{
- private NSMutableArray insertedIDsBuffer;
- private NSMutableArray updatedIDsBuffer;
- private NSMutableArray deletedIDsBuffer;
- private NSMutableArray invalidatedIDsBuffer;
-
- private Map snapshots;
- private List exceptionList;
-
- /**
- * Constructs a new instance of this object store.
- */
- public AbstractObjectStore()
- {
- snapshots = new HashMap();
- exceptionList = null;
-
- insertedIDsBuffer = new NSMutableArray();
- updatedIDsBuffer = new NSMutableArray();
- deletedIDsBuffer = new NSMutableArray();
- invalidatedIDsBuffer = new NSMutableArray();
-
- // register for notifications
- NSSelector handleNotification =
- new NSSelector( "handleNotification",
- new Class[] { NSNotification.class } );
- NSNotificationCenter.defaultCenter().addObserver(
- this,
- handleNotification,
- EOClassDescription.ClassDescriptionNeededForEntityNameNotification,
- null );
- }
-
- /**
- * This implementation returns an appropriately configured array fault.
- */
- public NSArray arrayFaultWithSourceGlobalID( EOGlobalID aGlobalID,
- String aRelationship, EOEditingContext aContext )
- { // System.out.println( "arrayFaultWithSourceGlobalID: " + aGlobalID + " : " + aRelationship );
- return new ArrayFault(
- aGlobalID, aRelationship, aContext );
- }
-
- /**
- * This implementation returns the actual object for the specified id.
- */
- public /*EOEnterpriseObject*/Object faultForGlobalID( EOGlobalID aGlobalID,
- EOEditingContext aContext )
- { // System.out.println( "faultForGlobalID: " + aGlobalID );
- return /*(EOEnterpriseObject)*/createInstanceWithEditingContext( aGlobalID, aContext );
- }
-
- /**
- * Returns a fault representing an object of the specified entity type with
- * values from the specified dictionary. The fault should belong to the
- * specified editing context.
- * NOTE: Faults are not supported yet.
- */
- public /*EOEnterpriseObject*/Object faultForRawRow( Map aDictionary, String anEntityName,
- EOEditingContext aContext )
- {
- //TODO: raw rows are not yet supported
- throw new WotonomyException( "Faults are not yet supported." );
- }
-
- /**
- * Given a newly instantiated object, this method initializes its
- * properties to values appropriate for the specified id. The object
- * should belong to the specified editing context. This method is called
- * to populate faults.
- */
- public void initializeObject( Object anObject, EOGlobalID aGlobalID,
- EOEditingContext aContext )
- { //System.out.println( "initializeObject: " + aGlobalID );
- try
- {
- String entity = entityForGlobalIDOrObject( aGlobalID, null );
- EOClassDescription classDesc =
- EOClassDescription.classDescriptionForEntityName( entity );
- if ( classDesc == null )
- {
- throw new WotonomyException( "Unknown entity type: " + entity );
- }
-
- Collection attributes = classDesc.attributeKeys();
- Map data = readFromCache( aGlobalID, attributes );
- String key;
- Iterator iterator = attributes.iterator();
- while ( iterator.hasNext() )
- {
- key = iterator.next().toString();
-
- // write the snapshot's reference into the object
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).takeStoredValueForKey( data.get( key ), key );
- }
- else
- {
- EOKeyValueCodingSupport.takeStoredValueForKey( anObject, data.get( key ), key );
- }
-
- //NOTE: our objects are expected to make a copy
- // of their data before it is modified, so it's okay
- // to return them our copy of the data:
- // we trust that they will not modify it.
- }
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
- }
-
- /**
- * Reads the local data snapshot for the specified id.
- * If no snapshot exists, a new snapshot is created.
- * If the specified keys are not in the snapshot,
- * new data is fetched into the snapshot.
- * If null is specified, all known keys are returned.
- * Will not return null.
- * Result will have values for those keys and only
- * those keys requested. Missing keys indicate an
- * error occurred.
- */
- protected Map readFromCache( EOGlobalID aGlobalID, Collection keys )
- {
- Map snapshot = (Map) snapshots.get( aGlobalID );
-
- // if no snapshot for this id, create an empty one
- if ( snapshot == null )
- {
- snapshot = new HashMap();
- snapshots.put( aGlobalID, snapshot );
- }
-
- // if we don't have all the necessary keys
- if ( ( keys == null ) || ( ! snapshot.keySet().containsAll( keys ) ) )
- {
- // we need to make a server call
- try
- {
- Map data = readObject( aGlobalID, keys );
-
- // compare timestamps
- Comparable localTimestamp = (Comparable) timestampForData( snapshot );
- // if our local snapshot has an timestamp (new snapshots don't have timestamp)
- if ( localTimestamp != null )
- {
- Comparable incomingTimestamp = (Comparable) timestampForData( data );
- if ( incomingTimestamp == null )
- {
- // not allowed to happen
- new RuntimeException( "Server returned data without an timestamp" ).printStackTrace();
- // however, we can just assume it's a newer timestamp and continue
- }
-
- // if timestamps don't match
- if ( ( incomingTimestamp == null ) || ( ! incomingTimestamp.equals( localTimestamp ) ) )
- {
- // dump our existing snapshot's data
- snapshot.clear();
- // queue for a notification on this oid as updated
- //TODO: implement this
- }
- }
-
- // copy new data into our local snapshot
- snapshot.putAll( data );
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
- }
-
- // return just the requested keys from our updated snapshot
- Map result = new HashMap();
- if ( keys == null )
- {
- result.putAll( snapshot );
- }
- else
- {
- Object key;
- Iterator iterator = keys.iterator();
- while ( iterator.hasNext() )
- {
- key = iterator.next();
- result.put( key, snapshot.get( key ) );
- }
- }
- return snapshot;
- }
-
- /**
- * Returns a comparable object (typically a Date or Long) for
- * the given data map or snapshot. This is used to determine
- * whether a local snapshot should be dumped in favor of fetched
- * data from the server.
- * Returns null if no timestamp can be determined, in which
- * case the fetched data will assumed to be more recent than
- * any local snapshot.
- */
- abstract protected Comparable timestampForData( Map aDataMap );
-
- /**
- * Extracts the global id for the fetched data or snapshot.
- * Some entities have multi-attribute keys that would be
- * assembled into a single instance of EOGlobalID.
- */
- abstract protected EOGlobalID globalIDForData( Map aDataMap );
-
- /**
- * Returns the entity that corresponds to the specified global id
- * and/or object. Either may be null, but both will not be null.
- * //FIXME: This is less than elegant.
- */
- abstract protected String entityForGlobalIDOrObject(
- EOGlobalID aGlobalID, Object anObject );
-
- /**
- * Returns the keys that have changed on the specified object.
- * If null, all keys are presumed changed, including relationships.
- */
- abstract protected Collection changedKeysForObject( Object anObject );
-
- /**
- * Returns the data for the row corresponding to the specified id
- * containing at least the specified keys. Implementations are allowed
- * to return more data than requested, and callers are advised to take
- * advantage of the returned data.
- */
- abstract protected Map readObject( EOGlobalID aGlobalID, Collection keys );
-
- /**
- * Returns the data for the row corresponding to the specified id.
- * //TODO: Need a better return value? How to return invalidated list?
- */
- abstract protected Map insertObject( EOGlobalID aGlobalID, Map aDataMap );
-
- /**
- * Returns the data for the row corresponding to the specified id.
- * //TODO: Need a better return value? How to return invalidated list?
- */
- abstract protected Object updateObject( EOGlobalID aGlobalID, Map aDataMap );
-
- /**
- * Returns the data for the row corresponding to the specified id.
- * //TODO: Need a better return value? How to return invalidated list?
- */
- abstract protected Object deleteObject( EOGlobalID aGlobalID );
-
- /**
- * Creates a new instance of an object that corresponds to the
- * specified global id and is registered in the specified context.
- * This implementation extracts the entity type from getEntityForGlobaID
- * and construct a new instance from the class description that
- * corresponds to the entity type. Override to change this behavior.
- */
- protected Object createInstanceWithEditingContext(
- EOGlobalID aGlobalID, EOEditingContext aContext )
- {
- String entity = entityForGlobalIDOrObject( aGlobalID, null );
- EOClassDescription classDesc =
- EOClassDescription.classDescriptionForEntityName( entity );
- if ( classDesc == null )
- {
- throw new WotonomyException( "Unknown entity type: " + entity );
- }
-
- Object result = classDesc.createInstanceWithEditingContext( aContext, aGlobalID );
- if ( result instanceof EOFaulting )
- {
- ((EOFaulting)result).turnIntoFault( null );
- }
- return result;
- }
-
- /**
- * Dumps the snapshot corresponding to the specified id.
- */
- protected void invalidateObject( EOGlobalID aGlobalID )
- {
- snapshots.remove( aGlobalID );
- }
-
- /**
- * Dumps all snapshots.
- */
- protected void invalidateAllCache()
- {
- snapshots.clear();
- }
-
- /**
- * Remove all values from all objects in memory, turning them into faults,
- * and posts a notification that all objects have been invalidated.
- */
- public void invalidateAllObjects()
- {
- invalidateAllCache();
-
- // post notification
- NSNotificationQueue.defaultQueue().enqueueNotification(
- new NSNotification(
- InvalidatedAllObjectsInStoreNotification, this ),
- NSNotificationQueue.PostNow );
- }
-
- /**
- * Removes values with the specified ids from memory, turning them into
- * faults, and posts a notification that those objects have been invalidated.
- */
- public void invalidateObjectsWithGlobalIDs( List aList )
- {
- NSArray empty = new NSArray();
- NSMutableArray invalidated = new NSMutableArray();
-
- Object object;
- Iterator iterator = aList.iterator();
- while ( iterator.hasNext() )
- {
- object = iterator.next();
- invalidateObject( (EOGlobalID) object );
- invalidated.addObject( object );
- }
-
- NSMutableDictionary info = new NSMutableDictionary();
- info.setObjectForKey( empty, InsertedKey );
- info.setObjectForKey( empty, UpdatedKey );
- info.setObjectForKey( empty, DeletedKey );
- info.setObjectForKey( invalidated, InvalidatedKey );
-
- // post notification
- NSNotificationQueue.defaultQueue().
- enqueueNotificationWithCoalesceMaskForModes( new NSNotification(
- ObjectsChangedInStoreNotification, this, info ),
- NSNotificationQueue.PostNow,
- NSNotificationQueue.NotificationNoCoalescing, null );
- }
-
- /**
- * Returns false because locking is not currently permitted.
- */
- public boolean isObjectLockedWithGlobalID( EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- return false;
- }
-
- /**
- * Does nothing because locking is not currently permitted.
- */
- public void lockObjectWithGlobalID( EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- // does nothing
- }
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship. This method may not return an array fault
- * because array faults call this method to fetch on demand.
- * All objects must be registered the specified editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public NSArray objectsForSourceGlobalID( EOGlobalID aGlobalID,
- String aRelationship, EOEditingContext aContext )
- { // System.out.println( "objectsForSourceGlobalID: " + aGlobalID + " : " + aRelationship + " : " );
-
- Map snapshot = readFromCache( aGlobalID, new NSArray( aRelationship ) );
- Object value = snapshot.get( aRelationship );
- if ( value == null ) value = new NSArray(); // empty list
- if ( ! ( value instanceof Collection ) )
- {
- throw new RuntimeException( "Specified relationship is not a collection: "
- + aRelationship + " : " + aGlobalID + " : " + value );
- }
-
- NSArray result = new NSMutableArray();
-
- // get fault for each id
- EOGlobalID id;
- Object fault;
- Iterator iterator = ((Collection)value).iterator();
- while ( iterator.hasNext() )
- {
- id = (EOGlobalID) iterator.next();
-
- // get registered fault
- fault = aContext.faultForGlobalID( id, aContext );
-
- // assert fault
- if ( fault == null )
- {
- // this should never happen
- throw new RuntimeException(
- "Could not find fault for ID: " + id );
- }
-
- result.add( fault );
- }
-
- fireObjectsChangedInStore();
+ * An abstract implementation of object store that implements common
+ * functionality. Subclasses must implement data object creation,
+ * initialization, and refault logic, as well as logic to commit an editing
+ * context.
+ */
+public abstract class AbstractObjectStore extends EOObjectStore {
+ private NSMutableArray insertedIDsBuffer;
+ private NSMutableArray updatedIDsBuffer;
+ private NSMutableArray deletedIDsBuffer;
+ private NSMutableArray invalidatedIDsBuffer;
+
+ private Map snapshots;
+ private List exceptionList;
+
+ /**
+ * Constructs a new instance of this object store.
+ */
+ public AbstractObjectStore() {
+ snapshots = new HashMap();
+ exceptionList = null;
+
+ insertedIDsBuffer = new NSMutableArray();
+ updatedIDsBuffer = new NSMutableArray();
+ deletedIDsBuffer = new NSMutableArray();
+ invalidatedIDsBuffer = new NSMutableArray();
+
+ // register for notifications
+ NSSelector handleNotification = new NSSelector("handleNotification", new Class[] { NSNotification.class });
+ NSNotificationCenter.defaultCenter().addObserver(this, handleNotification,
+ EOClassDescription.ClassDescriptionNeededForEntityNameNotification, null);
+ }
+
+ /**
+ * This implementation returns an appropriately configured array fault.
+ */
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) { // System.out.println(
+ // "arrayFaultWithSourceGlobalID:
+ // "
+ // +
+ // aGlobalID
+ // +
+ // "
+ // :
+ // "
+ // +
+ // aRelationship
+ // );
+ return new ArrayFault(aGlobalID, aRelationship, aContext);
+ }
+
+ /**
+ * This implementation returns the actual object for the specified id.
+ */
+ public /* EOEnterpriseObject */Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) { // System.out.println(
+ // "faultForGlobalID:
+ // " +
+ // aGlobalID
+ // );
+ return /* (EOEnterpriseObject) */createInstanceWithEditingContext(aGlobalID, aContext);
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. The fault should belong to the
+ * specified editing context. NOTE: Faults are not supported yet.
+ */
+ public /* EOEnterpriseObject */Object faultForRawRow(Map aDictionary, String anEntityName,
+ EOEditingContext aContext) {
+ // TODO: raw rows are not yet supported
+ throw new WotonomyException("Faults are not yet supported.");
+ }
+
+ /**
+ * Given a newly instantiated object, this method initializes its properties to
+ * values appropriate for the specified id. The object should belong to the
+ * specified editing context. This method is called to populate faults.
+ */
+ public void initializeObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) { // System.out.println(
+ // "initializeObject:
+ // " + aGlobalID
+ // );
+ try {
+ String entity = entityForGlobalIDOrObject(aGlobalID, null);
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName(entity);
+ if (classDesc == null) {
+ throw new WotonomyException("Unknown entity type: " + entity);
+ }
+
+ Collection attributes = classDesc.attributeKeys();
+ Map data = readFromCache(aGlobalID, attributes);
+ String key;
+ Iterator iterator = attributes.iterator();
+ while (iterator.hasNext()) {
+ key = iterator.next().toString();
+
+ // write the snapshot's reference into the object
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).takeStoredValueForKey(data.get(key), key);
+ } else {
+ EOKeyValueCodingSupport.takeStoredValueForKey(anObject, data.get(key), key);
+ }
+
+ // NOTE: our objects are expected to make a copy
+ // of their data before it is modified, so it's okay
+ // to return them our copy of the data:
+ // we trust that they will not modify it.
+ }
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ }
+
+ /**
+ * Reads the local data snapshot for the specified id. If no snapshot exists, a
+ * new snapshot is created. If the specified keys are not in the snapshot, new
+ * data is fetched into the snapshot. If null is specified, all known keys are
+ * returned. Will not return null. Result will have values for those keys and
+ * only those keys requested. Missing keys indicate an error occurred.
+ */
+ protected Map readFromCache(EOGlobalID aGlobalID, Collection keys) {
+ Map snapshot = (Map) snapshots.get(aGlobalID);
+
+ // if no snapshot for this id, create an empty one
+ if (snapshot == null) {
+ snapshot = new HashMap();
+ snapshots.put(aGlobalID, snapshot);
+ }
+
+ // if we don't have all the necessary keys
+ if ((keys == null) || (!snapshot.keySet().containsAll(keys))) {
+ // we need to make a server call
+ try {
+ Map data = readObject(aGlobalID, keys);
+
+ // compare timestamps
+ Comparable localTimestamp = (Comparable) timestampForData(snapshot);
+ // if our local snapshot has an timestamp (new snapshots don't have timestamp)
+ if (localTimestamp != null) {
+ Comparable incomingTimestamp = (Comparable) timestampForData(data);
+ if (incomingTimestamp == null) {
+ // not allowed to happen
+ new RuntimeException("Server returned data without an timestamp").printStackTrace();
+ // however, we can just assume it's a newer timestamp and continue
+ }
+
+ // if timestamps don't match
+ if ((incomingTimestamp == null) || (!incomingTimestamp.equals(localTimestamp))) {
+ // dump our existing snapshot's data
+ snapshot.clear();
+ // queue for a notification on this oid as updated
+ // TODO: implement this
+ }
+ }
+
+ // copy new data into our local snapshot
+ snapshot.putAll(data);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ }
+
+ // return just the requested keys from our updated snapshot
+ Map result = new HashMap();
+ if (keys == null) {
+ result.putAll(snapshot);
+ } else {
+ Object key;
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ key = iterator.next();
+ result.put(key, snapshot.get(key));
+ }
+ }
+ return snapshot;
+ }
+
+ /**
+ * Returns a comparable object (typically a Date or Long) for the given data map
+ * or snapshot. This is used to determine whether a local snapshot should be
+ * dumped in favor of fetched data from the server. Returns null if no timestamp
+ * can be determined, in which case the fetched data will assumed to be more
+ * recent than any local snapshot.
+ */
+ abstract protected Comparable timestampForData(Map aDataMap);
+
+ /**
+ * Extracts the global id for the fetched data or snapshot. Some entities have
+ * multi-attribute keys that would be assembled into a single instance of
+ * EOGlobalID.
+ */
+ abstract protected EOGlobalID globalIDForData(Map aDataMap);
+
+ /**
+ * Returns the entity that corresponds to the specified global id and/or object.
+ * Either may be null, but both will not be null. //FIXME: This is less than
+ * elegant.
+ */
+ abstract protected String entityForGlobalIDOrObject(EOGlobalID aGlobalID, Object anObject);
+
+ /**
+ * Returns the keys that have changed on the specified object. If null, all keys
+ * are presumed changed, including relationships.
+ */
+ abstract protected Collection changedKeysForObject(Object anObject);
+
+ /**
+ * Returns the data for the row corresponding to the specified id containing at
+ * least the specified keys. Implementations are allowed to return more data
+ * than requested, and callers are advised to take advantage of the returned
+ * data.
+ */
+ abstract protected Map readObject(EOGlobalID aGlobalID, Collection keys);
+
+ /**
+ * Returns the data for the row corresponding to the specified id. //TODO: Need
+ * a better return value? How to return invalidated list?
+ */
+ abstract protected Map insertObject(EOGlobalID aGlobalID, Map aDataMap);
+
+ /**
+ * Returns the data for the row corresponding to the specified id. //TODO: Need
+ * a better return value? How to return invalidated list?
+ */
+ abstract protected Object updateObject(EOGlobalID aGlobalID, Map aDataMap);
+
+ /**
+ * Returns the data for the row corresponding to the specified id. //TODO: Need
+ * a better return value? How to return invalidated list?
+ */
+ abstract protected Object deleteObject(EOGlobalID aGlobalID);
+
+ /**
+ * Creates a new instance of an object that corresponds to the specified global
+ * id and is registered in the specified context. This implementation extracts
+ * the entity type from getEntityForGlobaID and construct a new instance from
+ * the class description that corresponds to the entity type. Override to change
+ * this behavior.
+ */
+ protected Object createInstanceWithEditingContext(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ String entity = entityForGlobalIDOrObject(aGlobalID, null);
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName(entity);
+ if (classDesc == null) {
+ throw new WotonomyException("Unknown entity type: " + entity);
+ }
+
+ Object result = classDesc.createInstanceWithEditingContext(aContext, aGlobalID);
+ if (result instanceof EOFaulting) {
+ ((EOFaulting) result).turnIntoFault(null);
+ }
+ return result;
+ }
+
+ /**
+ * Dumps the snapshot corresponding to the specified id.
+ */
+ protected void invalidateObject(EOGlobalID aGlobalID) {
+ snapshots.remove(aGlobalID);
+ }
+
+ /**
+ * Dumps all snapshots.
+ */
+ protected void invalidateAllCache() {
+ snapshots.clear();
+ }
+
+ /**
+ * Remove all values from all objects in memory, turning them into faults, and
+ * posts a notification that all objects have been invalidated.
+ */
+ public void invalidateAllObjects() {
+ invalidateAllCache();
+
+ // post notification
+ NSNotificationQueue.defaultQueue().enqueueNotification(
+ new NSNotification(InvalidatedAllObjectsInStoreNotification, this), NSNotificationQueue.PostNow);
+ }
+
+ /**
+ * Removes values with the specified ids from memory, turning them into faults,
+ * and posts a notification that those objects have been invalidated.
+ */
+ public void invalidateObjectsWithGlobalIDs(List aList) {
+ NSArray empty = new NSArray();
+ NSMutableArray invalidated = new NSMutableArray();
+
+ Object object;
+ Iterator iterator = aList.iterator();
+ while (iterator.hasNext()) {
+ object = iterator.next();
+ invalidateObject((EOGlobalID) object);
+ invalidated.addObject(object);
+ }
+
+ NSMutableDictionary info = new NSMutableDictionary();
+ info.setObjectForKey(empty, InsertedKey);
+ info.setObjectForKey(empty, UpdatedKey);
+ info.setObjectForKey(empty, DeletedKey);
+ info.setObjectForKey(invalidated, InvalidatedKey);
+
+ // post notification
+ NSNotificationQueue.defaultQueue().enqueueNotificationWithCoalesceMaskForModes(
+ new NSNotification(ObjectsChangedInStoreNotification, this, info), NSNotificationQueue.PostNow,
+ NSNotificationQueue.NotificationNoCoalescing, null);
+ }
+
+ /**
+ * Returns false because locking is not currently permitted.
+ */
+ public boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ return false;
+ }
+
+ /**
+ * Does nothing because locking is not currently permitted.
+ */
+ public void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ // does nothing
+ }
+
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship. This method may not return an array
+ * fault because array faults call this method to fetch on demand. All objects
+ * must be registered the specified editing context. The specified relationship
+ * key must produce a result of type Collection for the source object or an
+ * exception is thrown.
+ */
+ public NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) { // System.out.println(
+ // "objectsForSourceGlobalID:
+ // "
+ // +
+ // aGlobalID
+ // +
+ // "
+ // :
+ // "
+ // +
+ // aRelationship
+ // +
+ // "
+ // :
+ // "
+ // );
+
+ Map snapshot = readFromCache(aGlobalID, new NSArray(aRelationship));
+ Object value = snapshot.get(aRelationship);
+ if (value == null)
+ value = new NSArray(); // empty list
+ if (!(value instanceof Collection)) {
+ throw new RuntimeException(
+ "Specified relationship is not a collection: " + aRelationship + " : " + aGlobalID + " : " + value);
+ }
+
+ NSArray result = new NSMutableArray();
+
+ // get fault for each id
+ EOGlobalID id;
+ Object fault;
+ Iterator iterator = ((Collection) value).iterator();
+ while (iterator.hasNext()) {
+ id = (EOGlobalID) iterator.next();
+
+ // get registered fault
+ fault = aContext.faultForGlobalID(id, aContext);
+
+ // assert fault
+ if (fault == null) {
+ // this should never happen
+ throw new RuntimeException("Could not find fault for ID: " + id);
+ }
+
+ result.add(fault);
+ }
+
+ fireObjectsChangedInStore();
//System.out.println( "done" );
- return result;
- }
-
- /**
- * Returns a List of objects the meet the criteria of
- * the supplied specification. Faults are not allowed in the array.
- * Each object is registered with the specified editing context.
- * If any object is already fetched in the specified context,
- * it is not refetched and that object should be used in the array.
- */
- public NSArray objectsWithFetchSpecification(
- EOFetchSpecification aFetchSpec, EOEditingContext aContext )
- {
- NSMutableArray result = new NSMutableArray();
-
- //TODO: implement this
-
- return result;
- }
-
- /**
- * Fires ObjectsChangedInStoreNotification
- * with contents of buffers and then clears buffers.
- * If buffers are empty, does nothing.
- */
- private void fireObjectsChangedInStore()
- {
- // check for changes to broadcast
- if ( insertedIDsBuffer.size() + updatedIDsBuffer.size() +
- deletedIDsBuffer.size() + invalidatedIDsBuffer.size() == 0 )
- {
- return;
- }
-
- // broadcast ObjectsChangedInStoreNotification
- // for the benefit of child editing contexts
-
- NSMutableDictionary storeInfo = new NSMutableDictionary();
-
- storeInfo.setObjectForKey(
- new NSArray( (Collection) insertedIDsBuffer ),
- EOObjectStore.InsertedKey );
- storeInfo.setObjectForKey(
- new NSArray( (Collection) updatedIDsBuffer ),
- EOObjectStore.UpdatedKey );
- storeInfo.setObjectForKey(
- new NSArray( (Collection) deletedIDsBuffer ),
- EOObjectStore.DeletedKey );
- storeInfo.setObjectForKey(
- new NSArray( (Collection) invalidatedIDsBuffer ),
- EOObjectStore.InvalidatedKey );
-
- // clear buffers
-
- insertedIDsBuffer.removeAllObjects();
- updatedIDsBuffer.removeAllObjects();
- deletedIDsBuffer.removeAllObjects();
- invalidatedIDsBuffer.removeAllObjects();
-
- // post notification
- NSNotificationQueue.defaultQueue().
- enqueueNotificationWithCoalesceMaskForModes( new NSNotification(
- ObjectsChangedInStoreNotification, this, storeInfo ),
- NSNotificationQueue.PostNow,
- NSNotificationQueue.NotificationNoCoalescing, null );
- }
-
- /**
- * Removes all values from the specified object,
- * converting it into a fault for the specified id.
- * New or deleted objects should not be refaulted.
- */
- public void refaultObject( Object anObject, EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
+ return result;
+ }
+
+ /**
+ * Returns a List of objects the meet the criteria of the supplied
+ * specification. Faults are not allowed in the array. Each object is registered
+ * with the specified editing context. If any object is already fetched in the
+ * specified context, it is not refetched and that object should be used in the
+ * array.
+ */
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext) {
+ NSMutableArray result = new NSMutableArray();
+
+ // TODO: implement this
+
+ return result;
+ }
+
+ /**
+ * Fires ObjectsChangedInStoreNotification with contents of buffers and then
+ * clears buffers. If buffers are empty, does nothing.
+ */
+ private void fireObjectsChangedInStore() {
+ // check for changes to broadcast
+ if (insertedIDsBuffer.size() + updatedIDsBuffer.size() + deletedIDsBuffer.size()
+ + invalidatedIDsBuffer.size() == 0) {
+ return;
+ }
+
+ // broadcast ObjectsChangedInStoreNotification
+ // for the benefit of child editing contexts
+
+ NSMutableDictionary storeInfo = new NSMutableDictionary();
+
+ storeInfo.setObjectForKey(new NSArray((Collection) insertedIDsBuffer), EOObjectStore.InsertedKey);
+ storeInfo.setObjectForKey(new NSArray((Collection) updatedIDsBuffer), EOObjectStore.UpdatedKey);
+ storeInfo.setObjectForKey(new NSArray((Collection) deletedIDsBuffer), EOObjectStore.DeletedKey);
+ storeInfo.setObjectForKey(new NSArray((Collection) invalidatedIDsBuffer), EOObjectStore.InvalidatedKey);
+
+ // clear buffers
+
+ insertedIDsBuffer.removeAllObjects();
+ updatedIDsBuffer.removeAllObjects();
+ deletedIDsBuffer.removeAllObjects();
+ invalidatedIDsBuffer.removeAllObjects();
+
+ // post notification
+ NSNotificationQueue.defaultQueue().enqueueNotificationWithCoalesceMaskForModes(
+ new NSNotification(ObjectsChangedInStoreNotification, this, storeInfo), NSNotificationQueue.PostNow,
+ NSNotificationQueue.NotificationNoCoalescing, null);
+ }
+
+ /**
+ * Removes all values from the specified object, converting it into a fault for
+ * the specified id. New or deleted objects should not be refaulted.
+ */
+ public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
//System.out.println( "refaultObject: " + aGlobalID );
//new net.wotonomy.ui.swing.util.StackTraceInspector();
- if ( anObject instanceof EOFaulting )
- {
- ((EOFaulting)anObject).turnIntoFault( null );
- }
- }
-
- /**
- * Writes all changes in the specified editing context
- * to the respository.
- */
- public void saveChangesInEditingContext ( EOEditingContext aContext )
- {
- Object result; // need a container result?
- Map updateMap;
- Object object;
- EOGlobalID id;
- Iterator iterator;
-
- //TODO: the ordering of operations here
- // needs to be a lot more sophisticated.
-
- // process deletes first
- iterator = aContext.deletedObjects().iterator();
- while ( iterator.hasNext() )
- {
- object = iterator.next();
- id = aContext.globalIDForObject( object );
- try
- {
- result = deleteObject( id );
- }
- catch ( Exception exc )
- {
- System.out.println( "Error deleting object: " + id );
- exc.printStackTrace();
- }
- }
-
- // process inserts next
- iterator = aContext.insertedObjects().iterator();
- while ( iterator.hasNext() )
- {
- object = iterator.next();
- processInsert( aContext, object );
- }
-
- // process updates last
- iterator = aContext.updatedObjects().iterator();
- while ( iterator.hasNext() )
- {
- object = iterator.next();
- id = aContext.globalIDForObject( object );
- try
- {
- updateMap = getUpdateMap( aContext, object );
- result = updateObject( id, updateMap );
- }
- catch ( Exception exc )
- {
- System.out.println( "Error updating object: " + id );
- exc.printStackTrace();
- }
- }
-
- //aContext.invalidateAllObjects();
- }
-
- protected Object processInsert( EOEditingContext aContext, Object object )
- {
- Map result = null;
- EOGlobalID id = aContext.globalIDForObject( object );
- try
- {
- Map updateMap;
- updateMap = getUpdateMap( aContext, object );
- result = insertObject( id, updateMap );
- id = globalIDForData( result ); // read new permanent id
-
- // broadcast that the global id has changed.
- NSMutableDictionary userInfo = new NSMutableDictionary();
- userInfo.setObjectForKey( id, aContext.globalIDForObject( object ) );
- NSNotificationQueue.defaultQueue().enqueueNotification(
- new NSNotification( EOGlobalID.GlobalIDChangedNotification,
- null , userInfo ), NSNotificationQueue.PostNow );
-
- }
- catch ( Exception exc )
- {
- System.out.println( "Error inserting object: " + id );
- exc.printStackTrace();
- }
- return result;
- }
-
- /**
- * This method returns a map containing just the keys that are modified
- * for a given object, converting any to-one or to-many relationships
- * to id references.
- */
- protected Map getUpdateMap( EOEditingContext aContext, Object anObject )
- {
- Map result = new HashMap();
- EOEditingContext context = aContext;
-
- String entity = entityForGlobalIDOrObject( null, anObject );
- EOClassDescription classDesc =
- EOClassDescription.classDescriptionForEntityName( entity );
- if ( classDesc == null )
- {
- throw new WotonomyException( "Unknown entity type: " + entity );
- }
-
- NSArray oneKeys = classDesc.toOneRelationshipKeys();
- NSArray manyKeys = classDesc.toManyRelationshipKeys();
-
- String key;
- Object value;
- EOGlobalID id;
-
- Collection changedKeys = changedKeysForObject( anObject );
- if ( changedKeys == null )
- {
- // assume all keys changed
- changedKeys = classDesc.attributeKeys();
- changedKeys.addAll( oneKeys );
- changedKeys.addAll( manyKeys );
- }
- Iterator iterator = changedKeys.iterator();
- while ( iterator.hasNext() )
- {
- key = iterator.next().toString();
- if ( anObject instanceof EOKeyValueCoding )
- {
- value = ((EOKeyValueCoding)anObject).storedValueForKey( key );
- }
- else
- {
- value = EOKeyValueCodingSupport.storedValueForKey( anObject, key );
- }
-
- // convert to-one relationship to oid
- if ( oneKeys.contains( key ) )
- {
- id = context.globalIDForObject( value );
-
- // if this id hasn't been persisted, save it first
- // NOTE: this won't work for self-referential graphs of objects!
- if ( id.isTemporary() )
- {
- processInsert( aContext, value );
- id = context.globalIDForObject( value );
- }
-
- value = id;
- }
- else
- // convert to-many relationship list to oid list
- if ( manyKeys.contains( key ) )
- {
- //NOTE: we can assume that array faults that
- // are marked as changed have been fired.
- if ( value instanceof Collection )
- {
- Object object;
- Collection newValue = new LinkedList();
- Iterator jiterator = ((Collection)value).iterator();
- while ( jiterator.hasNext() )
- {
- object = jiterator.next();
- id = context.globalIDForObject( object );
-
- // if this id hasn't been persisted, save it first
- // NOTE: this won't work for self-referential graphs of objects!
- if ( id.isTemporary() )
- {
- processInsert( aContext, object );
- id = context.globalIDForObject( object );
- }
- newValue.add( id );
- }
- value = newValue;
- }
- else
- {
- // should never happen
- new RuntimeException(
- "Can't update to-many relationship because it's not a Collection." )
- .printStackTrace();
- }
- }
-
- // place value in map
- result.put( key, value );
- }
-
-System.out.println( result );
- return result;
- }
-
-/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
- *
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
- *
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
- *
- * Revision 1.5 2003/12/18 15:37:38 mpowers
- * Changes to retain ability to work with objects that don't necessarily
- * implement EOEnterpriseObject. I would still like to preserve this case
- * for general usage, however the access package is free to assume that
- * those objects will be EOs and cast appropriately.
- *
- * Revision 1.4 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
- *
- * Revision 1.3 2002/10/24 18:18:12 mpowers
- * NSArray's are now considered read-only, so we can return our internal
- * representation to reduce unnecessary object allocation.
- *
- * Revision 1.2 2002/01/19 17:27:49 mpowers
- * Implemented most of it.
- *
- * Revision 1.1 2001/11/25 22:44:02 mpowers
- * Contributing draft of AbstractObjectStore.
- *
- *
- */
+ if (anObject instanceof EOFaulting) {
+ ((EOFaulting) anObject).turnIntoFault(null);
+ }
+ }
+
+ /**
+ * Writes all changes in the specified editing context to the respository.
+ */
+ public void saveChangesInEditingContext(EOEditingContext aContext) {
+ Object result; // need a container result?
+ Map updateMap;
+ Object object;
+ EOGlobalID id;
+ Iterator iterator;
+
+ // TODO: the ordering of operations here
+ // needs to be a lot more sophisticated.
+
+ // process deletes first
+ iterator = aContext.deletedObjects().iterator();
+ while (iterator.hasNext()) {
+ object = iterator.next();
+ id = aContext.globalIDForObject(object);
+ try {
+ result = deleteObject(id);
+ } catch (Exception exc) {
+ System.out.println("Error deleting object: " + id);
+ exc.printStackTrace();
+ }
+ }
+
+ // process inserts next
+ iterator = aContext.insertedObjects().iterator();
+ while (iterator.hasNext()) {
+ object = iterator.next();
+ processInsert(aContext, object);
+ }
+
+ // process updates last
+ iterator = aContext.updatedObjects().iterator();
+ while (iterator.hasNext()) {
+ object = iterator.next();
+ id = aContext.globalIDForObject(object);
+ try {
+ updateMap = getUpdateMap(aContext, object);
+ result = updateObject(id, updateMap);
+ } catch (Exception exc) {
+ System.out.println("Error updating object: " + id);
+ exc.printStackTrace();
+ }
+ }
+
+ // aContext.invalidateAllObjects();
+ }
+
+ protected Object processInsert(EOEditingContext aContext, Object object) {
+ Map result = null;
+ EOGlobalID id = aContext.globalIDForObject(object);
+ try {
+ Map updateMap;
+ updateMap = getUpdateMap(aContext, object);
+ result = insertObject(id, updateMap);
+ id = globalIDForData(result); // read new permanent id
+
+ // broadcast that the global id has changed.
+ NSMutableDictionary userInfo = new NSMutableDictionary();
+ userInfo.setObjectForKey(id, aContext.globalIDForObject(object));
+ NSNotificationQueue.defaultQueue().enqueueNotification(
+ new NSNotification(EOGlobalID.GlobalIDChangedNotification, null, userInfo),
+ NSNotificationQueue.PostNow);
+
+ } catch (Exception exc) {
+ System.out.println("Error inserting object: " + id);
+ exc.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * This method returns a map containing just the keys that are modified for a
+ * given object, converting any to-one or to-many relationships to id
+ * references.
+ */
+ protected Map getUpdateMap(EOEditingContext aContext, Object anObject) {
+ Map result = new HashMap();
+ EOEditingContext context = aContext;
+
+ String entity = entityForGlobalIDOrObject(null, anObject);
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName(entity);
+ if (classDesc == null) {
+ throw new WotonomyException("Unknown entity type: " + entity);
+ }
+
+ NSArray oneKeys = classDesc.toOneRelationshipKeys();
+ NSArray manyKeys = classDesc.toManyRelationshipKeys();
+
+ String key;
+ Object value;
+ EOGlobalID id;
+
+ Collection changedKeys = changedKeysForObject(anObject);
+ if (changedKeys == null) {
+ // assume all keys changed
+ changedKeys = classDesc.attributeKeys();
+ changedKeys.addAll(oneKeys);
+ changedKeys.addAll(manyKeys);
+ }
+ Iterator iterator = changedKeys.iterator();
+ while (iterator.hasNext()) {
+ key = iterator.next().toString();
+ if (anObject instanceof EOKeyValueCoding) {
+ value = ((EOKeyValueCoding) anObject).storedValueForKey(key);
+ } else {
+ value = EOKeyValueCodingSupport.storedValueForKey(anObject, key);
+ }
+
+ // convert to-one relationship to oid
+ if (oneKeys.contains(key)) {
+ id = context.globalIDForObject(value);
+
+ // if this id hasn't been persisted, save it first
+ // NOTE: this won't work for self-referential graphs of objects!
+ if (id.isTemporary()) {
+ processInsert(aContext, value);
+ id = context.globalIDForObject(value);
+ }
+
+ value = id;
+ } else
+ // convert to-many relationship list to oid list
+ if (manyKeys.contains(key)) {
+ // NOTE: we can assume that array faults that
+ // are marked as changed have been fired.
+ if (value instanceof Collection) {
+ Object object;
+ Collection newValue = new LinkedList();
+ Iterator jiterator = ((Collection) value).iterator();
+ while (jiterator.hasNext()) {
+ object = jiterator.next();
+ id = context.globalIDForObject(object);
+
+ // if this id hasn't been persisted, save it first
+ // NOTE: this won't work for self-referential graphs of objects!
+ if (id.isTemporary()) {
+ processInsert(aContext, object);
+ id = context.globalIDForObject(object);
+ }
+ newValue.add(id);
+ }
+ value = newValue;
+ } else {
+ // should never happen
+ new RuntimeException("Can't update to-many relationship because it's not a Collection.")
+ .printStackTrace();
+ }
+ }
+
+ // place value in map
+ result.put(key, value);
+ }
+
+ System.out.println(result);
+ return result;
+ }
+
+ /*
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
+ *
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
+ *
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.5 2003/12/18 15:37:38 mpowers Changes to retain ability to work
+ * with objects that don't necessarily implement EOEnterpriseObject. I would
+ * still like to preserve this case for general usage, however the access
+ * package is free to assume that those objects will be EOs and cast
+ * appropriately.
+ *
+ * Revision 1.4 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
+ *
+ * Revision 1.3 2002/10/24 18:18:12 mpowers NSArray's are now considered
+ * read-only, so we can return our internal representation to reduce unnecessary
+ * object allocation.
+ *
+ * Revision 1.2 2002/01/19 17:27:49 mpowers Implemented most of it.
+ *
+ * Revision 1.1 2001/11/25 22:44:02 mpowers Contributing draft of
+ * AbstractObjectStore.
+ *
+ *
+ */
}
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ArrayFault.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ArrayFault.java
index 59e135b..3a2bcaf 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ArrayFault.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ArrayFault.java
@@ -25,195 +25,165 @@ import java.util.ListIterator;
import net.wotonomy.foundation.NSArray;
/**
-* A class that extends NSArray to intercept any accessor calls
-* in order to defer loading until the last possible moment.<br><br>
-*
-* Because ArrayFault inherits from NSArray which implements
-* List which implements Collection, data objects may declare
-* their relationships to be of type NSArray, List, or Collection.<br><br>
-*
-* This class should be returned by implementations of
-* EOObjectStore.arrayFaultForSourceGlobalID().
-*/
-public class ArrayFault extends NSArray
-{
- private EOEditingContext editingContext;
- private EOGlobalID sourceID;
- private String relationshipKey;
- private boolean fetched;
-
- public ArrayFault(
- EOGlobalID aSourceID,
- String aRelationshipKey,
- EOEditingContext aContext )
- {
- super();
- editingContext = aContext;
- sourceID = aSourceID;
- relationshipKey = aRelationshipKey;
- fetched = false;
- }
-
- public boolean isFetched()
- {
- return fetched;
- }
-
- protected void fireFault()
- {
- if ( !fetched )
- {
+ * A class that extends NSArray to intercept any accessor calls in order to
+ * defer loading until the last possible moment.<br>
+ * <br>
+ *
+ * Because ArrayFault inherits from NSArray which implements List which
+ * implements Collection, data objects may declare their relationships to be of
+ * type NSArray, List, or Collection.<br>
+ * <br>
+ *
+ * This class should be returned by implementations of
+ * EOObjectStore.arrayFaultForSourceGlobalID().
+ */
+public class ArrayFault extends NSArray {
+ private EOEditingContext editingContext;
+ private EOGlobalID sourceID;
+ private String relationshipKey;
+ private boolean fetched;
+
+ public ArrayFault(EOGlobalID aSourceID, String aRelationshipKey, EOEditingContext aContext) {
+ super();
+ editingContext = aContext;
+ sourceID = aSourceID;
+ relationshipKey = aRelationshipKey;
+ fetched = false;
+ }
+
+ public boolean isFetched() {
+ return fetched;
+ }
+
+ protected void fireFault() {
+ if (!fetched) {
//new net.wotonomy.ui.swing.util.StackTraceInspector();
//System.out.println( "ArrayFault.fireFault: before:" + this );
- fetched = true;
- super.protectedAddAll(
- editingContext.parentObjectStore().objectsForSourceGlobalID(
- sourceID,
- relationshipKey,
- editingContext ) );
+ fetched = true;
+ super.protectedAddAll(editingContext.parentObjectStore().objectsForSourceGlobalID(sourceID, relationshipKey,
+ editingContext));
//System.out.println( "ArrayFault.fireFault: after:" + this );
- }
- }
-
- public Object clone()
- {
- fireFault();
- return super.clone();
- }
-
- public boolean contains(Object elem)
- {
- fireFault();
- return super.contains( elem );
- }
-
- public boolean equals(Object o)
- {
- fireFault();
- return super.equals( o );
- }
-
- public Object get(int index)
- {
- fireFault();
- return super.get( index );
- }
-
- /**
- * Overridden to return the identity hash.
- * This somewhat violates the List contract,
- * but otherwise calling hash code would
- * fire the fault. Bottom line: don't use
- * array faults as keys in hash maps.
- */
- public int hashCode()
- {
- return System.identityHashCode( this );
- }
-
- public int indexOf(Object o)
- {
- fireFault();
- return super.indexOf( o );
- }
-
- public boolean isEmpty()
- {
- fireFault();
- return super.isEmpty();
- }
-
- public Iterator iterator()
- {
- fireFault();
- return super.iterator();
- }
-
- public int lastIndexOf(Object o)
- {
- fireFault();
- return super.lastIndexOf( o );
- }
-
- public ListIterator listIterator()
- {
- fireFault();
- return super.listIterator();
- }
-
- public ListIterator listIterator(int index)
- {
- fireFault();
- return super.listIterator( index );
- }
-
- public int size()
- {
- fireFault();
- return super.size();
- }
-
- public List subList(int fromIndex, int toIndex)
- {
- fireFault();
- return super.subList( fromIndex, toIndex );
- }
-
- public Object[] toArray()
- {
- fireFault();
- return super.toArray();
- }
-
- public Object[] toArray(Object[] a)
- {
- fireFault();
- return super.toArray( a );
- }
-
- /**
- * Overridden to display information about
- * the fault only if not fetched.
- * Calls to super if fetched.
- */
- public String toString()
- {
- if ( isFetched() )
- {
- return super.toString();
- }
- return "[ArrayFault@"+Integer.toHexString( System.identityHashCode( this ) )+":"+sourceID+":"+relationshipKey+"]";
- }
+ }
+ }
+
+ public Object clone() {
+ fireFault();
+ return super.clone();
+ }
+
+ public boolean contains(Object elem) {
+ fireFault();
+ return super.contains(elem);
+ }
+
+ public boolean equals(Object o) {
+ fireFault();
+ return super.equals(o);
+ }
+
+ public Object get(int index) {
+ fireFault();
+ return super.get(index);
+ }
+
+ /**
+ * Overridden to return the identity hash. This somewhat violates the List
+ * contract, but otherwise calling hash code would fire the fault. Bottom line:
+ * don't use array faults as keys in hash maps.
+ */
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ public int indexOf(Object o) {
+ fireFault();
+ return super.indexOf(o);
+ }
+
+ public boolean isEmpty() {
+ fireFault();
+ return super.isEmpty();
+ }
+
+ public Iterator iterator() {
+ fireFault();
+ return super.iterator();
+ }
+
+ public int lastIndexOf(Object o) {
+ fireFault();
+ return super.lastIndexOf(o);
+ }
+
+ public ListIterator listIterator() {
+ fireFault();
+ return super.listIterator();
+ }
+
+ public ListIterator listIterator(int index) {
+ fireFault();
+ return super.listIterator(index);
+ }
+
+ public int size() {
+ fireFault();
+ return super.size();
+ }
+
+ public List subList(int fromIndex, int toIndex) {
+ fireFault();
+ return super.subList(fromIndex, toIndex);
+ }
+
+ public Object[] toArray() {
+ fireFault();
+ return super.toArray();
+ }
+
+ public Object[] toArray(Object[] a) {
+ fireFault();
+ return super.toArray(a);
+ }
+
+ /**
+ * Overridden to display information about the fault only if not fetched. Calls
+ * to super if fetched.
+ */
+ public String toString() {
+ if (isFetched()) {
+ return super.toString();
+ }
+ return "[ArrayFault@" + Integer.toHexString(System.identityHashCode(this)) + ":" + sourceID + ":"
+ + relationshipKey + "]";
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/12/18 15:37:38 mpowers
- * Changes to retain ability to work with objects that don't necessarily
- * implement EOEnterpriseObject. I would still like to preserve this case
- * for general usage, however the access package is free to assume that
- * those objects will be EOs and cast appropriately.
+ * Revision 1.5 2003/12/18 15:37:38 mpowers Changes to retain ability to work
+ * with objects that don't necessarily implement EOEnterpriseObject. I would
+ * still like to preserve this case for general usage, however the access
+ * package is free to assume that those objects will be EOs and cast
+ * appropriately.
*
- * Revision 1.4 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ * Revision 1.4 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
*
- * Revision 1.3 2002/10/24 18:17:37 mpowers
- * ArrayFaults are now read-only.
+ * Revision 1.3 2002/10/24 18:17:37 mpowers ArrayFaults are now read-only.
*
- * Revision 1.2 2001/05/06 22:22:55 mpowers
- * Debugging.
+ * Revision 1.2 2001/05/06 22:22:55 mpowers Debugging.
*
- * Revision 1.1 2001/05/05 23:05:42 mpowers
- * Implemented Array Faults.
+ * Revision 1.1 2001/05/05 23:05:42 mpowers Implemented Array Faults.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ChildDataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ChildDataSource.java
index 8123668..1d62881 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ChildDataSource.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ChildDataSource.java
@@ -7,181 +7,137 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSMutableArray;
/**
-* A data source that automates the process of
-* creating a child editing context and copying
-* objects from a parent context into it.
-* Attach this data source to a display group
-* that represents a "detail" or "drill-down"
-* view. <br><br>
-*
-* Once created, editingContext() will return the
-* child context, and fetch() will return the objects
-* that were copied into the child context.
-*/
-public class ChildDataSource extends EODataSource
-{
- private EODataSource parent;
- private EOEditingContext context;
- private EOClassDescription classDescription;
- private NSMutableArray objects;
-
- /**
- * Creates a child editing context for the
- * specified parent's context and copies the
- * specified object into the child context.
- * The object must exist in the parent context.
- * fetch() will return the child's object.
- */
- public ChildDataSource(
- EODataSource aParentSource,
- Object anObject )
- {
- this( aParentSource, new NSArray( (Object) anObject ) );
+ * A data source that automates the process of creating a child editing context
+ * and copying objects from a parent context into it. Attach this data source to
+ * a display group that represents a "detail" or "drill-down" view. <br>
+ * <br>
+ *
+ * Once created, editingContext() will return the child context, and fetch()
+ * will return the objects that were copied into the child context.
+ */
+public class ChildDataSource extends EODataSource {
+ private EODataSource parent;
+ private EOEditingContext context;
+ private EOClassDescription classDescription;
+ private NSMutableArray objects;
+
+ /**
+ * Creates a child editing context for the specified parent's context and copies
+ * the specified object into the child context. The object must exist in the
+ * parent context. fetch() will return the child's object.
+ */
+ public ChildDataSource(EODataSource aParentSource, Object anObject) {
+ this(aParentSource, new NSArray((Object) anObject));
}
-
- /**
- * Creates a child editing context for the
- * specified parent's context and copies the
- * specified objects into the child context.
- * The objects must exist in the parent context.
- * The order of the parent's objects in the
- * collection will determine the order in
- * which the child objects are returned from
- * fetch().
- */
- public ChildDataSource(
- EODataSource aParentSource,
- Collection anObjectList )
- {
- EOEditingContext parentContext =
- aParentSource.editingContext();
-
- parent = aParentSource;
- context = new EOEditingContext( parentContext );
+
+ /**
+ * Creates a child editing context for the specified parent's context and copies
+ * the specified objects into the child context. The objects must exist in the
+ * parent context. The order of the parent's objects in the collection will
+ * determine the order in which the child objects are returned from fetch().
+ */
+ public ChildDataSource(EODataSource aParentSource, Collection anObjectList) {
+ EOEditingContext parentContext = aParentSource.editingContext();
+
+ parent = aParentSource;
+ context = new EOEditingContext(parentContext);
//!new net.wotonomy.ui.swing.util.ObjectInspector( context );
- objects = new NSMutableArray();
- classDescription = null;
-
- Object o;
- Object copy;
- boolean allSameClass = true;
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
-
- // determine class
- if ( allSameClass == true )
- {
- Class c = o.getClass();
- if ( classDescription == null )
- {
- classDescription =
- EOClassDescription.classDescriptionForClass( c );
- }
- else
- {
- if ( c != classDescription.getDescribedClass() )
- {
- allSameClass = false;
- classDescription = null;
- }
- }
- }
-
- // copy and add to list
- objects.addObject( parentContext.faultForGlobalID(
- parentContext.globalIDForObject( o ), context ) );
- }
+ objects = new NSMutableArray();
+ classDescription = null;
+
+ Object o;
+ Object copy;
+ boolean allSameClass = true;
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+
+ // determine class
+ if (allSameClass == true) {
+ Class c = o.getClass();
+ if (classDescription == null) {
+ classDescription = EOClassDescription.classDescriptionForClass(c);
+ } else {
+ if (c != classDescription.getDescribedClass()) {
+ allSameClass = false;
+ classDescription = null;
+ }
+ }
+ }
+
+ // copy and add to list
+ objects.addObject(parentContext.faultForGlobalID(parentContext.globalIDForObject(o), context));
+ }
}
-
- /**
- * Returns the editing context for this data source,
- * which was created in the constructor and whose
- * parent is the editing context specified in the
- * constructor.
- */
- public EOEditingContext editingContext()
- {
- return context;
- }
-
- /**
- * This implementation does nothing.
- */
- public void insertObject ( Object anObject )
- {
+ /**
+ * Returns the editing context for this data source, which was created in the
+ * constructor and whose parent is the editing context specified in the
+ * constructor.
+ */
+ public EOEditingContext editingContext() {
+ return context;
}
- /**
- * This implementation does nothing.
- */
- public void deleteObject ( Object anObject )
- {
+ /**
+ * This implementation does nothing.
+ */
+ public void insertObject(Object anObject) {
}
- /**
- * Returns a List containing the objects in this
- * data source. This implementation returns all
- * TestObjects that have been persisted to the
- * datastore in the data directory.
- */
- public NSArray fetchObjects ()
- {
- return new NSArray( (Collection) objects );
- }
-
- /**
- * Returns a data source that is capable of
- * manipulating objects of the type returned by
- * applying the specified key to objects
- * vended by this data source.
- * This implementation forwards the call to
- * the parent data source.
- * @see #qualifyWithRelationshipKey
- */
- public EODataSource
- dataSourceQualifiedByKey ( String aKey )
- {
- //FIXME: This is fundamentally broken.
- // Objects vended from the returned source
- // are not registered in our editing context.
- // We probably need yet another utility data
- // source class that would wrap another source
- // and convert vended objects into a different
- // context.
-
- return parent.dataSourceQualifiedByKey( aKey );
+ /**
+ * This implementation does nothing.
+ */
+ public void deleteObject(Object anObject) {
+
}
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- * This implementation forwards the call to
- * the parent data source.
- */
- public void
- qualifyWithRelationshipKey (
- String aKey, Object anObject )
- {
- parent.qualifyWithRelationshipKey( aKey, anObject );
+ /**
+ * Returns a List containing the objects in this data source. This
+ * implementation returns all TestObjects that have been persisted to the
+ * datastore in the data directory.
+ */
+ public NSArray fetchObjects() {
+ return new NSArray((Collection) objects);
}
- /**
- * Returns the description of the class of the
- * objects that is vended by this data source,
- * or null if this cannot be determined.
- * This implementation returns the class of the
- * objects passed to the constructor if they are
- * all the same class, otherwise returns null.
- */
- public EOClassDescription
- classDescriptionForObjects ()
- {
- return classDescription;
- }
+ /**
+ * Returns a data source that is capable of manipulating objects of the type
+ * returned by applying the specified key to objects vended by this data source.
+ * This implementation forwards the call to the parent data source.
+ *
+ * @see #qualifyWithRelationshipKey
+ */
+ public EODataSource dataSourceQualifiedByKey(String aKey) {
+ // FIXME: This is fundamentally broken.
+ // Objects vended from the returned source
+ // are not registered in our editing context.
+ // We probably need yet another utility data
+ // source class that would wrap another source
+ // and convert vended objects into a different
+ // context.
+
+ return parent.dataSourceQualifiedByKey(aKey);
+ }
+
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object. This implementation forwards the call
+ * to the parent data source.
+ */
+ public void qualifyWithRelationshipKey(String aKey, Object anObject) {
+ parent.qualifyWithRelationshipKey(aKey, anObject);
+ }
+
+ /**
+ * Returns the description of the class of the objects that is vended by this
+ * data source, or null if this cannot be determined. This implementation
+ * returns the class of the objects passed to the constructor if they are all
+ * the same class, otherwise returns null.
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ return classDescription;
+ }
}
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOAndQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOAndQualifier.java
index 049eb33..9d8eb96 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOAndQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOAndQualifier.java
@@ -28,88 +28,75 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOAndQualifier contains other EOQualifiers,
-* evaluating as true only if all of the contained
-* qualifiers evaluate as true.
-*
-* @author michael@mpowers.net
-* @author yjcheung@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOAndQualifier extends EOQualifier
- implements EOKeyValueArchiving, EOQualifierEvaluation
-{
- private List qualifiers;
-
- public EOAndQualifier(
- List aQualifierList )
- {
- qualifiers = new LinkedList( aQualifierList );
- }
-
- /**
- * Returns a List of qualifiers contained by this qualifier.
- */
- public NSArray qualifiers()
- {
- return new NSArray( qualifiers );
- }
-
- /**
- * Add a new qualifier to the list.
- */
- public void addQualifier(EOQualifier qualifier)
- {
- qualifiers.add(qualifier);
- }
-
- /**
- * Evaluates this qualifier for the specified object,
- * and returns whether the object is qualified.
- * selector() is invoked on the value for key() on the
- * specified object, with value() as the parameter.
- *
- * Note: this has the lazy "and" implementation. Ex.
- * Qal1 and Qal2. If the Qal1 is evaluated to be false, then it returns
- * false without evaluating Qa12.
- */
- public boolean evaluateWithObject( Object anObject )
- {
- boolean retVal = true;
- Iterator it = qualifiers.iterator();
- while (it.hasNext() && retVal)
- {
- retVal = ((EOQualifier) it.next()).evaluateWithObject(anObject);
- }
- return retVal;
- }
-
- /**
- * Returns a string representation of this qualifier.
- */
- public String toString()
- {
- StringBuffer myBuf = new StringBuffer("(");
- Iterator it = qualifiers.iterator();
- while (it.hasNext())
- {
- myBuf = myBuf.append(((EOQualifier) it.next()).toString()).append(" and ");
- }
- String myStr = myBuf.toString();
- myStr = myStr.substring(0, myStr.lastIndexOf(" and")).concat(")");
- return myStr;
- }
+ * EOAndQualifier contains other EOQualifiers, evaluating as true only if all of
+ * the contained qualifiers evaluate as true.
+ *
+ * @author michael@mpowers.net
+ * @author yjcheung@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOAndQualifier extends EOQualifier implements EOKeyValueArchiving, EOQualifierEvaluation {
+ private List qualifiers;
+
+ public EOAndQualifier(List aQualifierList) {
+ qualifiers = new LinkedList(aQualifierList);
+ }
+
+ /**
+ * Returns a List of qualifiers contained by this qualifier.
+ */
+ public NSArray qualifiers() {
+ return new NSArray(qualifiers);
+ }
+
+ /**
+ * Add a new qualifier to the list.
+ */
+ public void addQualifier(EOQualifier qualifier) {
+ qualifiers.add(qualifier);
+ }
+
+ /**
+ * Evaluates this qualifier for the specified object, and returns whether the
+ * object is qualified. selector() is invoked on the value for key() on the
+ * specified object, with value() as the parameter.
+ *
+ * Note: this has the lazy "and" implementation. Ex. Qal1 and Qal2. If the Qal1
+ * is evaluated to be false, then it returns false without evaluating Qa12.
+ */
+ public boolean evaluateWithObject(Object anObject) {
+ boolean retVal = true;
+ Iterator it = qualifiers.iterator();
+ while (it.hasNext() && retVal) {
+ retVal = ((EOQualifier) it.next()).evaluateWithObject(anObject);
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns a string representation of this qualifier.
+ */
+ public String toString() {
+ StringBuffer myBuf = new StringBuffer("(");
+ Iterator it = qualifiers.iterator();
+ while (it.hasNext()) {
+ myBuf = myBuf.append(((EOQualifier) it.next()).toString()).append(" and ");
+ }
+ String myStr = myBuf.toString();
+ myStr = myStr.substring(0, myStr.lastIndexOf(" and")).concat(")");
+ return myStr;
+ }
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
- NSArray a = (NSArray)arch.decodeObjectForKey("qualifiers");
+ NSArray a = (NSArray) arch.decodeObjectForKey("qualifiers");
if (a == null)
return null;
NSMutableArray l = new NSMutableArray();
for (int i = 0; i < a.count(); i++) {
- NSDictionary d = (NSDictionary)a.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) a.objectAtIndex(i);
EOKeyValueUnarchiver ua = new EOKeyValueUnarchiver(d);
- EOQualifier q = (EOQualifier)EOQualifier.decodeWithKeyValueUnarchiver(ua);
+ EOQualifier q = (EOQualifier) EOQualifier.decodeWithKeyValueUnarchiver(ua);
if (q != null)
l.addObject(q);
}
@@ -119,11 +106,11 @@ public class EOAndQualifier extends EOQualifier
public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
arch.encodeObject("EOAndQualifier", "class");
NSMutableArray arr = new NSMutableArray(qualifiers.size());
- for (int i = 0; i < qualifiers.size(); i++) {
- EOQualifier q = (EOQualifier)qualifiers.get(i);
+ for (int i = 0; i < qualifiers.size(); i++) {
+ EOQualifier q = (EOQualifier) qualifiers.get(i);
if (q instanceof EOKeyValueArchiving) {
EOKeyValueArchiver ar2 = new EOKeyValueArchiver();
- ((EOKeyValueArchiving)q).encodeWithKeyValueArchiver(ar2);
+ ((EOKeyValueArchiving) q).encodeWithKeyValueArchiver(ar2);
arr.addObject(ar2.dictionary());
} else
throw new WotonomyException("Cannot archive instance of " + q.getClass().getName());
@@ -134,34 +121,31 @@ public class EOAndQualifier extends EOQualifier
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/12 01:43:04 chochos
- * formally implement EOQualifierEvaluation
+ * Revision 1.6 2003/08/12 01:43:04 chochos formally implement
+ * EOQualifierEvaluation
*
- * Revision 1.5 2003/08/09 01:22:51 chochos
- * qualifiers implement EOKeyValueArchiving
+ * Revision 1.5 2003/08/09 01:22:51 chochos qualifiers implement
+ * EOKeyValueArchiving
*
- * Revision 1.4 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.4 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.3 2001/10/31 15:25:14 mpowers
- * Cleanup of qualifiers.
+ * Revision 1.3 2001/10/31 15:25:14 mpowers Cleanup of qualifiers.
*
- * Revision 1.2 2001/10/30 22:57:28 mpowers
- * EOQualifier framework is now working.
+ * Revision 1.2 2001/10/30 22:57:28 mpowers EOQualifier framework is now
+ * working.
*
- * Revision 1.1 2001/09/13 15:25:56 mpowers
- * Started implementation of the EOQualifier framework.
+ * Revision 1.1 2001/09/13 15:25:56 mpowers Started implementation of the
+ * EOQualifier framework.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOClassDescription.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOClassDescription.java
index cd07ebb..79019de 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOClassDescription.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOClassDescription.java
@@ -28,574 +28,476 @@ import net.wotonomy.foundation.internal.Introspector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOClassDescription provides meta-information about a class
-* and is used to customize certain behaviors within wotonomy
-* and specifically within editing contexts and object stores.
-* <br><br>
-*
-* The default implementation works for most well-formed java beans,
-* but you will want to create your own subclass most typically
-* to customize the toOne and toMany relationships for your
-* class to ensure that an entire graph of objects is not
-* persisted in order to perist a single object.
-* <br><br>
-*
-* The easiest way to register your subclass is to create it
-* in the same package as the class it describes but with
-* a "ClassDesc" suffix. For example, "my.package.MyEntity"
-* would be described by "my.package.MyEntityClassDesc". <br><br>
-*
-* Note that while the interface is the same, the implementation
-* of this class differs substantially from the specification
-* in order to be more useful for java classes.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 900 $
-*/
-public class EOClassDescription
-{
- /**
- * A delete rule specifying that object(s) that reference
- * this object should have those references set to null
- * when this object is deleted.
- */
- public static final int DeleteRuleNullify = 0;
-
- /**
- * A delete rule specifying that object(s) referenced by
- * this object should also be deleted when this object
- * is deleted.
- */
- public static final int DeleteRuleCascade = 1;
-
- /**
- * A delete rule specicying that this object should
- * not be allowed to be deleted if it references any
- * object(s).
- */
- public static final int DeleteRuleDeny = 2;
-
- /**
- * A delete rule specifying that no action be taken
- * when this object is deleted. This is the default.
- */
- public static final int DeleteRuleNoAction = 3;
-
- /**
- * Notification fired when a class description has been requested
- * for a class. Observers should watch for this notification and
- * call registerClassDescription so that class descriptions can be
- * loaded on-demand.
- * The notification's object is the requested class and the
- * user info dictionary is null.
- */
- public static final String ClassDescriptionNeededForClassNotification =
- "ClassDescriptionNeededForClassNotification";
-
- /**
- * Notification fired when a class description has been requested
- * for an entity name. Observers should watch for this notification and
- * call registerClassDescription so that class descriptions can be
- * loaded on-demand.
- * The notification's object is the requested name and the
- * user info dictionary is null.
- */
- public static final String ClassDescriptionNeededForEntityNameNotification =
- "ClassDescriptionNeededForEntityNameNotification";
+ * EOClassDescription provides meta-information about a class and is used to
+ * customize certain behaviors within wotonomy and specifically within editing
+ * contexts and object stores. <br>
+ * <br>
+ *
+ * The default implementation works for most well-formed java beans, but you
+ * will want to create your own subclass most typically to customize the toOne
+ * and toMany relationships for your class to ensure that an entire graph of
+ * objects is not persisted in order to perist a single object. <br>
+ * <br>
+ *
+ * The easiest way to register your subclass is to create it in the same package
+ * as the class it describes but with a "ClassDesc" suffix. For example,
+ * "my.package.MyEntity" would be described by "my.package.MyEntityClassDesc".
+ * <br>
+ * <br>
+ *
+ * Note that while the interface is the same, the implementation of this class
+ * differs substantially from the specification in order to be more useful for
+ * java classes.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 900 $
+ */
+public class EOClassDescription {
+ /**
+ * A delete rule specifying that object(s) that reference this object should
+ * have those references set to null when this object is deleted.
+ */
+ public static final int DeleteRuleNullify = 0;
+
+ /**
+ * A delete rule specifying that object(s) referenced by this object should also
+ * be deleted when this object is deleted.
+ */
+ public static final int DeleteRuleCascade = 1;
+
+ /**
+ * A delete rule specicying that this object should not be allowed to be deleted
+ * if it references any object(s).
+ */
+ public static final int DeleteRuleDeny = 2;
+
+ /**
+ * A delete rule specifying that no action be taken when this object is deleted.
+ * This is the default.
+ */
+ public static final int DeleteRuleNoAction = 3;
+
+ /**
+ * Notification fired when a class description has been requested for a class.
+ * Observers should watch for this notification and call
+ * registerClassDescription so that class descriptions can be loaded on-demand.
+ * The notification's object is the requested class and the user info dictionary
+ * is null.
+ */
+ public static final String ClassDescriptionNeededForClassNotification = "ClassDescriptionNeededForClassNotification";
+
+ /**
+ * Notification fired when a class description has been requested for an entity
+ * name. Observers should watch for this notification and call
+ * registerClassDescription so that class descriptions can be loaded on-demand.
+ * The notification's object is the requested name and the user info dictionary
+ * is null.
+ */
+ public static final String ClassDescriptionNeededForEntityNameNotification = "ClassDescriptionNeededForEntityNameNotification";
public EOClassDescription() {
super();
}
- /**
- * Returns the class description that corresponds to the specified class.
- * If the class description has not already been loaded, a
- * ClassDescriptionNeededForClassNotification is posted.
- * If the class description is still not found, the class' loader
- * is consulted for a class in the same package and named the same as the
- * specified class but appended with "ClassDesc", e.g. "EmployeeObjectClassDesc".
- * If the class description is still not found, a class description is
- * returned that uses java bean introspection to provide reasonable values.
- */
- public static EOClassDescription classDescriptionForClass(
- Class aClass )
- {
- if ( classMap == null ) classMap = new HashMap();
- EOClassDescription result = (EOClassDescription) classMap.get( aClass );
- if ( result == null )
- {
- // if not found, post notification
- NSNotificationCenter.defaultCenter().postNotification(
- ClassDescriptionNeededForClassNotification, aClass, null );
- result = (EOClassDescription) classMap.get( aClass );
- }
- if ( result == null )
- {
- // if not found, look for similarly named class
- String className = aClass.getName() + ClassNameSuffix;
- Class classDesc;
- try
- {
- classDesc = aClass.getClassLoader().loadClass( className );
- if ( classDesc != null )
- {
- result = (EOClassDescription) classDesc.newInstance();
- registerClassDescription( result, aClass );
- }
- }
- catch ( Exception exc )
- {
- // ignore exceptions and resume
- }
- }
- if ( result == null )
- {
- // if not found, default to this class
- result = new EOClassDescription( aClass );
- registerClassDescription( result, aClass );
- }
- return result;
- }
-
- /**
- * Returns the class description that corresponds to the specified
- * entity name. If the class description has not already been
- * loaded, a ClassDescriptionNeededForEntityNameNotification is posted.
- * Returns null if no class description can be found for the entity name.
- */
- public static EOClassDescription classDescriptionForEntityName(
- String aName )
- {
- if ( entityMap == null ) entityMap = new HashMap();
- EOClassDescription result = (EOClassDescription) entityMap.get( aName );
- if ( result == null )
- {
- // if not found, post notification
- NSNotificationCenter.defaultCenter().postNotification(
- ClassDescriptionNeededForEntityNameNotification, aName, null );
- result = (EOClassDescription) entityMap.get( aName );
- }
- return result;
- }
-
- /**
- * Clears all cached class descriptions so that new requests
- * for class descriptions will be re-loaded on-demand.
- */
- public static void invalidateClassDescriptionCache()
- {
- classMap.clear();
- entityMap.clear();
- }
-
- /**
- * Registers the specified class descriptiong for the specified class.
- * Nulls are not allowed - to clear the cache call invalidateClassDescriptionCache().
- */
- public static void registerClassDescription(
- EOClassDescription description,
- Class aClass )
- {
- if ( classMap == null ) classMap = new HashMap();
- if ( entityMap == null ) entityMap = new HashMap();
- description.theClass = aClass;
- classMap.put( aClass, description );
- entityMap.put( description.entityName(), description );
- }
+ /**
+ * Returns the class description that corresponds to the specified class. If the
+ * class description has not already been loaded, a
+ * ClassDescriptionNeededForClassNotification is posted. If the class
+ * description is still not found, the class' loader is consulted for a class in
+ * the same package and named the same as the specified class but appended with
+ * "ClassDesc", e.g. "EmployeeObjectClassDesc". If the class description is
+ * still not found, a class description is returned that uses java bean
+ * introspection to provide reasonable values.
+ */
+ public static EOClassDescription classDescriptionForClass(Class aClass) {
+ if (classMap == null)
+ classMap = new HashMap();
+ EOClassDescription result = (EOClassDescription) classMap.get(aClass);
+ if (result == null) {
+ // if not found, post notification
+ NSNotificationCenter.defaultCenter().postNotification(ClassDescriptionNeededForClassNotification, aClass,
+ null);
+ result = (EOClassDescription) classMap.get(aClass);
+ }
+ if (result == null) {
+ // if not found, look for similarly named class
+ String className = aClass.getName() + ClassNameSuffix;
+ Class classDesc;
+ try {
+ classDesc = aClass.getClassLoader().loadClass(className);
+ if (classDesc != null) {
+ result = (EOClassDescription) classDesc.newInstance();
+ registerClassDescription(result, aClass);
+ }
+ } catch (Exception exc) {
+ // ignore exceptions and resume
+ }
+ }
+ if (result == null) {
+ // if not found, default to this class
+ result = new EOClassDescription(aClass);
+ registerClassDescription(result, aClass);
+ }
+ return result;
+ }
-/*
- public static Object classDelegate()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- public static void setClassDelegate(
- Object aDelegate)
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-*/
-
- /**
- * The string appended to the java class name when
- * searching the class path for an appropriate description.
- */
- private final static String ClassNameSuffix = "ClassDesc";
-
- private static Map classMap;
- private static Map entityMap;
-
- protected Class theClass;
- private NSMutableArray attributes;
-
- /**
- * Constructor may only be called by subclasses.
- */
- protected EOClassDescription( Class aClass )
- {
- theClass = aClass;
- }
-
- /**
- * Returns a List of all the attributes for this class.
- * This implementation reflects on the java class to produce
- * a list of attributes, and then removes those keys that
- * are returned by toOneRelationshipKeys and toManyRelationhipKeys.
- */
- public NSArray attributeKeys()
- {
- if ( attributes == null )
- {
- NSMutableArray readProperties = new NSMutableArray();
- String[] read = Introspector.getReadPropertiesForClass( theClass );
- for ( int i = 0; i < read.length; i++ )
- {
- readProperties.addObject( read[i] );
- }
-
- attributes = new NSMutableArray();
- String[] write = Introspector.getWritePropertiesForClass( theClass );
- for ( int i = 0; i < write.length; i++ )
- {
- attributes.addObject( write[i] );
- }
-
- // only use properties on both lists: read/write
- attributes.retainAll( readProperties );
-
- // remove relationship keys
- attributes.removeAll( toOneRelationshipKeys() );
- attributes.removeAll( toManyRelationshipKeys() );
- }
- return attributes;
- }
-
- /**
- * This method is called when the specified object has been
- * fetched into the specified editing context. Fetch means
- * an object was fetched using a fetch specification - it is
- * not the same thing as an insertion.
- * This implementation does nothing.
- */
- public void awakeObjectFromFetch(
- Object object,
- EOEditingContext anEditingContext )
- {
- }
-
- /**
- * This method is called when the specified object has been
- * inserted into the specified editing context. Insertion
- * means an object was inserted by a display group - it does
- * not mean the same thing as a fetch.
- * This implementation does nothing.
- */
- public void awakeObjectFromInsertion(
- Object object,
- EOEditingContext anEditingContext )
- {
- // does nothing
- }
-
- /**
- * Returns the class decription for the object referenced
- * by the specified relationship key, or null if the
- * class description cannot be determined for that key.
- * This implementation returns null.
- */
- public EOClassDescription classDescriptionForDestinationKey(
- String detailKey )
- {
- return null;
- }
-
- /**
- * Creates a new instance of the class represented by this
- * class description, registering it with the specified
- * editing context and global id. The class description
- * may not keep references to the newly created object.
- * The editing context and/or the id may be null.
- * This implementation constructs a new instance of the class
- * and registers it with the specified editing context.
- * If the global id is specified, the object will be populated
- * with the appropriate data, otherwise the object will be
- * treated as a newly inserted object.
- * If no editing context is specified, the global id is
- * ignored and the new instance of the class is returned.
- */
- public Object createInstanceWithEditingContext(
- EOEditingContext anEditingContext,
- EOGlobalID globalID )
- {
+ /**
+ * Returns the class description that corresponds to the specified entity name.
+ * If the class description has not already been loaded, a
+ * ClassDescriptionNeededForEntityNameNotification is posted. Returns null if no
+ * class description can be found for the entity name.
+ */
+ public static EOClassDescription classDescriptionForEntityName(String aName) {
+ if (entityMap == null)
+ entityMap = new HashMap();
+ EOClassDescription result = (EOClassDescription) entityMap.get(aName);
+ if (result == null) {
+ // if not found, post notification
+ NSNotificationCenter.defaultCenter().postNotification(ClassDescriptionNeededForEntityNameNotification,
+ aName, null);
+ result = (EOClassDescription) entityMap.get(aName);
+ }
+ return result;
+ }
+
+ /**
+ * Clears all cached class descriptions so that new requests for class
+ * descriptions will be re-loaded on-demand.
+ */
+ public static void invalidateClassDescriptionCache() {
+ classMap.clear();
+ entityMap.clear();
+ }
+
+ /**
+ * Registers the specified class descriptiong for the specified class. Nulls are
+ * not allowed - to clear the cache call invalidateClassDescriptionCache().
+ */
+ public static void registerClassDescription(EOClassDescription description, Class aClass) {
+ if (classMap == null)
+ classMap = new HashMap();
+ if (entityMap == null)
+ entityMap = new HashMap();
+ description.theClass = aClass;
+ classMap.put(aClass, description);
+ entityMap.put(description.entityName(), description);
+ }
+
+ /*
+ * public static Object classDelegate() { throw new WotonomyException(
+ * "Not implemented yet." ); }
+ *
+ * public static void setClassDelegate( Object aDelegate) { throw new
+ * WotonomyException( "Not implemented yet." ); }
+ */
+
+ /**
+ * The string appended to the java class name when searching the class path for
+ * an appropriate description.
+ */
+ private final static String ClassNameSuffix = "ClassDesc";
+
+ private static Map classMap;
+ private static Map entityMap;
+
+ protected Class theClass;
+ private NSMutableArray attributes;
+
+ /**
+ * Constructor may only be called by subclasses.
+ */
+ protected EOClassDescription(Class aClass) {
+ theClass = aClass;
+ }
+
+ /**
+ * Returns a List of all the attributes for this class. This implementation
+ * reflects on the java class to produce a list of attributes, and then removes
+ * those keys that are returned by toOneRelationshipKeys and
+ * toManyRelationhipKeys.
+ */
+ public NSArray attributeKeys() {
+ if (attributes == null) {
+ NSMutableArray readProperties = new NSMutableArray();
+ String[] read = Introspector.getReadPropertiesForClass(theClass);
+ for (int i = 0; i < read.length; i++) {
+ readProperties.addObject(read[i]);
+ }
+
+ attributes = new NSMutableArray();
+ String[] write = Introspector.getWritePropertiesForClass(theClass);
+ for (int i = 0; i < write.length; i++) {
+ attributes.addObject(write[i]);
+ }
+
+ // only use properties on both lists: read/write
+ attributes.retainAll(readProperties);
+
+ // remove relationship keys
+ attributes.removeAll(toOneRelationshipKeys());
+ attributes.removeAll(toManyRelationshipKeys());
+ }
+ return attributes;
+ }
+
+ /**
+ * This method is called when the specified object has been fetched into the
+ * specified editing context. Fetch means an object was fetched using a fetch
+ * specification - it is not the same thing as an insertion. This implementation
+ * does nothing.
+ */
+ public void awakeObjectFromFetch(Object object, EOEditingContext anEditingContext) {
+ }
+
+ /**
+ * This method is called when the specified object has been inserted into the
+ * specified editing context. Insertion means an object was inserted by a
+ * display group - it does not mean the same thing as a fetch. This
+ * implementation does nothing.
+ */
+ public void awakeObjectFromInsertion(Object object, EOEditingContext anEditingContext) {
+ // does nothing
+ }
+
+ /**
+ * Returns the class decription for the object referenced by the specified
+ * relationship key, or null if the class description cannot be determined for
+ * that key. This implementation returns null.
+ */
+ public EOClassDescription classDescriptionForDestinationKey(String detailKey) {
+ return null;
+ }
+
+ /**
+ * Creates a new instance of the class represented by this class description,
+ * registering it with the specified editing context and global id. The class
+ * description may not keep references to the newly created object. The editing
+ * context and/or the id may be null. This implementation constructs a new
+ * instance of the class and registers it with the specified editing context. If
+ * the global id is specified, the object will be populated with the appropriate
+ * data, otherwise the object will be treated as a newly inserted object. If no
+ * editing context is specified, the global id is ignored and the new instance
+ * of the class is returned.
+ */
+ public Object createInstanceWithEditingContext(EOEditingContext anEditingContext, EOGlobalID globalID) {
//System.out.println( "createInstanceWithEditingContext: " + this + " : " + theClass );
- Object result = null;
- try
- {
- result = theClass.newInstance();
- if ( anEditingContext != null )
- {
- if ( globalID != null )
- {
- if ( result instanceof EOEnterpriseObject )
- {
- ((EOEnterpriseObject)result).awakeFromFetch( anEditingContext );
- }
- // register in editing context
- anEditingContext.recordObject( result, globalID );
- }
- else // no global id specified
- {
- if ( result instanceof EOEnterpriseObject )
- {
- ((EOEnterpriseObject)result).awakeFromInsertion( anEditingContext );
- }
- // register as new object in editing context
- anEditingContext.insertObject( result );
- }
- }
- }
- catch ( Exception exc )
- {
- // error instantiating
- throw new WotonomyException( exc );
- }
- return result;
- }
-
-/*
- public NSFormatter defaultFormatterForKey(
- String key )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-*/
-
- /**
- * Returns the delete rule to be used for the specified
- * relationship key.
- * This implementation returns DeleteRuleNoAction.
- */
- public int deleteRuleForRelationshipKey(
- String relationshipKey )
- {
- return DeleteRuleNoAction;
- }
-
- /**
- * Returns a human-readable title for the specified key.
- * For example, displayNameForKey( "firstName" ) might
- * return "First Name".
- * This implementation attempts to construct such a string
- * from the key, uppercasing the first character and
- * inserting spaces before subsequent uppercase characters.
- */
- public String displayNameForKey(
- String key )
- {
- if ( key == null ) return "";
- if ( key.length() == 0 ) return "";
-
- StringBuffer result = new StringBuffer();
- result.append( Character.toUpperCase( key.charAt(0) ) );
-
- char c;
- int len = key.length();
- for ( int i = 1; i < len; i++ )
- {
- c = key.charAt(i);
- if ( Character.isUpperCase( c ) )
- {
- result.append( ' ' );
- }
- result.append( c );
- }
-
- return result.toString();
- }
-
- /**
- * Returns a human-readable title for the class of objects
- * that this class description represents. For example,
- * class CustomerObject might return "Customer".
- * This implementation returns the class name.
- */
- public String entityName()
- {
- String result = theClass.getName();
- int index = result.lastIndexOf( "." );
- if ( index == -1 ) return result;
- return result.substring( index+1 );
- }
-
- /**
- * Returns the fetch specification associated with this
- * class description that corresponds to the specified name,
- * or null if not found.
- * This implementation returns null.
- */
- public EOFetchSpecification fetchSpecificationNamed(
- String aString )
- {
- return null;
- }
-
- /**
- * Returns the relationship key by which the object at the
- * other end of the specified relationship key refers to
- * this object, or null if not found.
- * This implementation returns null.
- */
- public String inverseForRelationshipKey(
- String relationshipKey )
- {
- return null;
- }
-
- public boolean ownsDestinationObjectsForRelationshipKey(
- String relationshipKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Called when this object has been deleted from the
- * specified editing context. The delete rules for this
- * object's relationships should be executed.
- */
- public void propagateDeleteForObject(
- Object object,
- EOEditingContext anEditingContext )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a List of the "to many" relationships for
- * this class.
- * This implementation returns an empty list.
- */
- public NSArray toManyRelationshipKeys()
- {
- return NSArray.EmptyArray;
- }
-
- /**
- * Returns a List of the "to one" relationships for
- * this class.
- * This implementation returns an empty list.
- */
- public NSArray toOneRelationshipKeys()
- {
- return NSArray.EmptyArray;
- }
-
- /**
- * Returns a human-readable description of the specified object
- * that should not exceed 60 characters.
- * This implementation returns anObject.toString().
- */
- public String userPresentableDescriptionForObject(
- Object anObject )
- {
- return anObject.toString();
- }
-
- /**
- * Verifies that the specified object may be deleted.
- * Throws an exception with a user-readable error message
- * if the delete operation should not be allowed.
- * This implementation does nothing.
- */
- public void validateObjectForDelete(
- Object object )
- {
- // does nothing
- }
-
- /**
- * Verifies that the specified object may be saved.
- * Throws an exception with a user-readable error message
- * if the save operation should not be allowed.
- * This implementation does nothing.
- */
- public void validateObjectForSave(
- Object object )
- {
- // does nothing
- }
-
- /**
- * Validates the specified value for the specified key on this
- * this class. Returns null if the value is acceptable, or
- * returns an object that should be used in place of the specified
- * object, or throws an exception with a user-readable error message
- * if no acceptable value can be determined.
- * This implementation returns null.
- */
- public Object validateValueForKey( Object value, String key)
- {
- return null;
- }
-
- /**
- * Returns the Java Class that this description describes.
- * NOTE: This method is not in the specification.
- */
- public Class getDescribedClass()
- {
- return theClass;
- }
-
+ Object result = null;
+ try {
+ result = theClass.newInstance();
+ if (anEditingContext != null) {
+ if (globalID != null) {
+ if (result instanceof EOEnterpriseObject) {
+ ((EOEnterpriseObject) result).awakeFromFetch(anEditingContext);
+ }
+ // register in editing context
+ anEditingContext.recordObject(result, globalID);
+ } else // no global id specified
+ {
+ if (result instanceof EOEnterpriseObject) {
+ ((EOEnterpriseObject) result).awakeFromInsertion(anEditingContext);
+ }
+ // register as new object in editing context
+ anEditingContext.insertObject(result);
+ }
+ }
+ } catch (Exception exc) {
+ // error instantiating
+ throw new WotonomyException(exc);
+ }
+ return result;
+ }
+
+ /*
+ * public NSFormatter defaultFormatterForKey( String key ) { throw new
+ * WotonomyException( "Not implemented yet." ); }
+ */
+
+ /**
+ * Returns the delete rule to be used for the specified relationship key. This
+ * implementation returns DeleteRuleNoAction.
+ */
+ public int deleteRuleForRelationshipKey(String relationshipKey) {
+ return DeleteRuleNoAction;
+ }
+
+ /**
+ * Returns a human-readable title for the specified key. For example,
+ * displayNameForKey( "firstName" ) might return "First Name". This
+ * implementation attempts to construct such a string from the key, uppercasing
+ * the first character and inserting spaces before subsequent uppercase
+ * characters.
+ */
+ public String displayNameForKey(String key) {
+ if (key == null)
+ return "";
+ if (key.length() == 0)
+ return "";
+
+ StringBuffer result = new StringBuffer();
+ result.append(Character.toUpperCase(key.charAt(0)));
+
+ char c;
+ int len = key.length();
+ for (int i = 1; i < len; i++) {
+ c = key.charAt(i);
+ if (Character.isUpperCase(c)) {
+ result.append(' ');
+ }
+ result.append(c);
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Returns a human-readable title for the class of objects that this class
+ * description represents. For example, class CustomerObject might return
+ * "Customer". This implementation returns the class name.
+ */
+ public String entityName() {
+ String result = theClass.getName();
+ int index = result.lastIndexOf(".");
+ if (index == -1)
+ return result;
+ return result.substring(index + 1);
+ }
+
+ /**
+ * Returns the fetch specification associated with this class description that
+ * corresponds to the specified name, or null if not found. This implementation
+ * returns null.
+ */
+ public EOFetchSpecification fetchSpecificationNamed(String aString) {
+ return null;
+ }
+
+ /**
+ * Returns the relationship key by which the object at the other end of the
+ * specified relationship key refers to this object, or null if not found. This
+ * implementation returns null.
+ */
+ public String inverseForRelationshipKey(String relationshipKey) {
+ return null;
+ }
+
+ public boolean ownsDestinationObjectsForRelationshipKey(String relationshipKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Called when this object has been deleted from the specified editing context.
+ * The delete rules for this object's relationships should be executed.
+ */
+ public void propagateDeleteForObject(Object object, EOEditingContext anEditingContext) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a List of the "to many" relationships for this class. This
+ * implementation returns an empty list.
+ */
+ public NSArray toManyRelationshipKeys() {
+ return NSArray.EmptyArray;
+ }
+
+ /**
+ * Returns a List of the "to one" relationships for this class. This
+ * implementation returns an empty list.
+ */
+ public NSArray toOneRelationshipKeys() {
+ return NSArray.EmptyArray;
+ }
+
+ /**
+ * Returns a human-readable description of the specified object that should not
+ * exceed 60 characters. This implementation returns anObject.toString().
+ */
+ public String userPresentableDescriptionForObject(Object anObject) {
+ return anObject.toString();
+ }
+
+ /**
+ * Verifies that the specified object may be deleted. Throws an exception with a
+ * user-readable error message if the delete operation should not be allowed.
+ * This implementation does nothing.
+ */
+ public void validateObjectForDelete(Object object) {
+ // does nothing
+ }
+
+ /**
+ * Verifies that the specified object may be saved. Throws an exception with a
+ * user-readable error message if the save operation should not be allowed. This
+ * implementation does nothing.
+ */
+ public void validateObjectForSave(Object object) {
+ // does nothing
+ }
+
+ /**
+ * Validates the specified value for the specified key on this this class.
+ * Returns null if the value is acceptable, or returns an object that should be
+ * used in place of the specified object, or throws an exception with a
+ * user-readable error message if no acceptable value can be determined. This
+ * implementation returns null.
+ */
+ public Object validateValueForKey(Object value, String key) {
+ return null;
+ }
+
+ /**
+ * Returns the Java Class that this description describes. NOTE: This method is
+ * not in the specification.
+ */
+ public Class getDescribedClass() {
+ return theClass;
+ }
+
}
/*
- * $Log$
- * Revision 1.3 2006/02/18 22:46:44 cgruber
- * Add Surrogate map from .util into control's internal package, and fix imports.
+ * $Log$ Revision 1.3 2006/02/18 22:46:44 cgruber Add Surrogate map from .util
+ * into control's internal package, and fix imports.
*
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to "internal"
+ * packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.11 2003/08/08 05:50:32 chochos
- * theClass is protected instead of private
+ * Revision 1.11 2003/08/08 05:50:32 chochos theClass is protected instead of
+ * private
*
- * Revision 1.10 2003/08/08 00:37:44 chochos
- * default constructor is needed by subclasses
+ * Revision 1.10 2003/08/08 00:37:44 chochos default constructor is needed by
+ * subclasses
*
- * Revision 1.9 2001/12/20 18:55:46 mpowers
- * Hooks for awakeFromInsertion and awakeFromFetch.
+ * Revision 1.9 2001/12/20 18:55:46 mpowers Hooks for awakeFromInsertion and
+ * awakeFromFetch.
*
- * Revision 1.8 2001/12/01 23:51:45 mpowers
- * Corrected createWithEditingContext.
+ * Revision 1.8 2001/12/01 23:51:45 mpowers Corrected createWithEditingContext.
*
- * Revision 1.7 2001/11/25 22:43:38 mpowers
- * Corrected createInstanceWithEditingContext.
+ * Revision 1.7 2001/11/25 22:43:38 mpowers Corrected
+ * createInstanceWithEditingContext.
*
- * Revision 1.6 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
+ * Revision 1.6 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
*
- * Revision 1.5 2001/04/28 22:17:51 mpowers
- * Revised PropertyDataSource to be EOClassDescription-aware.
+ * Revision 1.5 2001/04/28 22:17:51 mpowers Revised PropertyDataSource to be
+ * EOClassDescription-aware.
*
- * Revision 1.4 2001/04/28 14:12:23 mpowers
- * Refactored cloning/copying into KeyValueCodingUtilities.
+ * Revision 1.4 2001/04/28 14:12:23 mpowers Refactored cloning/copying into
+ * KeyValueCodingUtilities.
*
- * Revision 1.3 2001/04/27 23:37:20 mpowers
- * Now using EOClassDescription in the EODataSource class, as we should.
+ * Revision 1.3 2001/04/27 23:37:20 mpowers Now using EOClassDescription in the
+ * EODataSource class, as we should.
*
- * Revision 1.2 2001/04/27 00:27:42 mpowers
- * Partial implementation.
+ * Revision 1.2 2001/04/27 00:27:42 mpowers Partial implementation.
*
- * Revision 1.1 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.1 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCooperatingObjectStore.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCooperatingObjectStore.java
index 072f867..98a8a60 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCooperatingObjectStore.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCooperatingObjectStore.java
@@ -24,59 +24,58 @@ package net.wotonomy.control;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSLocking;
+
/**
-* A representation of a channel of communication to the database.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * A representation of a channel of communication to the database.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
-public abstract class EOCooperatingObjectStore extends EOObjectStore
- implements NSLocking {
+public abstract class EOCooperatingObjectStore extends EOObjectStore implements NSLocking {
- public EOCooperatingObjectStore() {
- }
+ public EOCooperatingObjectStore() {
+ }
- public abstract boolean ownsGlobalID(EOGlobalID eoglobalid);
+ public abstract boolean ownsGlobalID(EOGlobalID eoglobalid);
- public abstract boolean ownsObject(EOEnterpriseObject eoenterpriseobject);
+ public abstract boolean ownsObject(EOEnterpriseObject eoenterpriseobject);
- public abstract boolean handlesFetchSpecification(EOFetchSpecification eofetchspecification);
+ public abstract boolean handlesFetchSpecification(EOFetchSpecification eofetchspecification);
- public abstract void prepareForSaveWithCoordinator(EOObjectStoreCoordinator eoobjectstorecoordinator, EOEditingContext eoeditingcontext);
+ public abstract void prepareForSaveWithCoordinator(EOObjectStoreCoordinator eoobjectstorecoordinator,
+ EOEditingContext eoeditingcontext);
- public abstract void recordChangesInEditingContext();
+ public abstract void recordChangesInEditingContext();
- public abstract void recordUpdateForObject(EOEnterpriseObject eoenterpriseobject, NSDictionary nsdictionary);
+ public abstract void recordUpdateForObject(EOEnterpriseObject eoenterpriseobject, NSDictionary nsdictionary);
- public abstract void performChanges();
+ public abstract void performChanges();
- public abstract void commitChanges();
+ public abstract void commitChanges();
- public abstract void rollbackChanges();
+ public abstract void rollbackChanges();
- public abstract NSDictionary valuesForKeys(NSArray nsarray, EOEnterpriseObject eoenterpriseobject);
+ public abstract NSDictionary valuesForKeys(NSArray nsarray, EOEnterpriseObject eoenterpriseobject);
- public abstract void lock();
+ public abstract void lock();
- public abstract void unlock();
+ public abstract void unlock();
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/07/14 21:59:06 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:59:06 mpowers Contributions from cgruber.
*
- * Revision 1.2 2002/06/21 22:14:30 cgruber
- * Add a log trail
+ * Revision 1.2 2002/06/21 22:14:30 cgruber Add a log trail
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCustomObject.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCustomObject.java
index 6b262cb..4c7ca40 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCustomObject.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOCustomObject.java
@@ -28,646 +28,540 @@ import net.wotonomy.foundation.NSSet;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOCustomObject implements all the necessary interfaces to
-* receive first-class treatment from the control framework.
-* The implementation delegates as much class meta-behavior as
-* possible to EOClassDescription, letting subclasses
-* focus exclusively on business logic while still allowing
-* them to customize as much class behavior as needed.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOCustomObject
- implements EOEnterpriseObject,
- EOKeyValueCodingAdditions,
- EODeferredFaulting,
- EORelationshipManipulation,
- EOValidation
-{
- private transient static EOClassDescription classDescription;
- private transient EOEditingContext editingContext;
-
- // static configuration
-
- /**
- * Specifies whether the implementation of EOKeyValueCoding
- * is permitted to access field directly. This implementation
- * returns true; subclasses may override to customize this behavior.
- */
- public static boolean canAccessFieldsDirectly()
- {
- return true;
- }
-
- /**
- * Specifies whether the implementation of EOKeyValueCoding
- * is permitted to access private accessors. This implementation
- * returns true; subclasses may override to customize this behavior.
- */
- public static boolean shouldUseStoredAccessors()
- {
- return true;
- }
-
- /**
- * Specifies whether deferred faults should be used. This implementation
- * returns false; subclasses may override to customize this behavior.
- */
- public static boolean usesDeferredFaultCreation()
- {
- return false;
- }
-
- // constructors
-
- /**
- * Default constructor initializes private state.
- * EditingContext and ClassDescription are set to null.
- */
- public EOCustomObject()
- {
- editingContext = null;
- classDescription = null;
- }
-
- /**
- * Preferred constructor, specifying an editing context,
- * a class description, and a global id, any or all of which
- * may be null. Subclasses should invoke this constructor.
- */
- public EOCustomObject(
- EOEditingContext aContext,
- EOClassDescription aClassDescription,
- EOGlobalID aGlobalID )
- {
- editingContext = aContext;
- classDescription = aClassDescription;
- }
-
- // interface EOEnterpriseObject
-
- /**
- * Returns a List of all property keys defined on this object.
- * This includes both attributes and relationships.
- * This implementation returns the union of attributeKeys,
- * toOneRelationshipKeys, and toManyRelationshipKeys.
- */
- public NSArray allPropertyKeys()
- {
- NSSet union = new NSSet();
- union.addAll( attributeKeys() );
- union.addAll( toOneRelationshipKeys() );
- union.addAll( toManyRelationshipKeys() );
- return new NSArray( (Collection) union );
- }
-
- /**
- * Returns a list of all attributes defined on this object.
- * Attributes are all properties that are not relationships.
- * This implementation retrieves the keys from the class
- * description.
- */
- public NSArray attributeKeys()
- {
- return classDescription().attributeKeys();
- }
-
- //void awakeFromClientUpdate(EOEditingContext aContext)
-
- /**
- * Called when the object has first been fetched into the
- * specified editing context. This implementation calls
- * awakeObjectFromFetch on the class description.
- */
- public void awakeFromFetch(EOEditingContext anEditingContext)
- {
- classDescription().awakeObjectFromFetch( this, anEditingContext );
- }
-
- /**
- * Called when the object has been inserted into the
- * specified editing context. This implementation calls
- * awakeObjectFromInsertion on the class description.
- */
- public void awakeFromInsertion(EOEditingContext anEditingContext)
- {
- classDescription().awakeObjectFromInsertion( this, anEditingContext );
- }
-
- /**
- * Returns a Map representing the delta of the current state
- * from the state represented in the specified snapshot.
- * The result will contain only the keys that have changed
- * and their values. Relationship keys will map to an NSArray
- * that contains an NSArray of added objects and an NSArray
- * of removed objects, in that order.
- */
- public NSDictionary changesFromSnapshot(NSDictionary snapshot)
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a class description for this object.
- * Calls EOClassDescription.classDescriptionForClass.
- */
- public EOClassDescription classDescription()
- {
- if ( classDescription == null )
- {
- classDescription = EOClassDescription.classDescriptionForClass( getClass() );
- if ( classDescription == null )
- {
- throw new WotonomyException(
- "No class description found for class: " + getClass() );
- }
- }
- return classDescription;
- }
-
- /**
- * Returns a class description for the object at the
- * other end of the specified relationship key.
- * This implementation calls to the classDescription.
- */
- public EOClassDescription classDescriptionForDestinationKey(String aKey)
- {
- return classDescription().classDescriptionForDestinationKey( aKey );
- }
-
- /**
- * Clears all property values for this object.
- * This method is called to clean-up an object that
- * will no longer be used, and implementations should
- * ensure that all references are set to null to
- * prevent problems with garbage-collection.
- */
- public void clearProperties()
- {
- //FIXME: clear properties here
- }
-
- /**
- * Returns the delete rule constant defined on EOClassDescription
- * for the relationship defined by the specified key.
- * This implementation calls to the classDescription.
- */
- public int deleteRuleForRelationshipKey(String aRelationshipKey)
- {
- return classDescription().deleteRuleForRelationshipKey( aRelationshipKey );
- }
-
- /**
- * Returns the editing context in which this object is registered.
- */
- public EOEditingContext editingContext()
- {
- return editingContext;
- }
-
- /**
- * Returns the name of the entity that this object represents.
- */
- public String entityName()
- {
- return classDescription().entityName();
- }
-
- /**
- * Returns a String containing all property keys and values for
- * this object. Relationships should be represented by calling
- * eoShallowDescription() on the object.
- */
- public String eoDescription()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a String containing all attribute keys and values for
- * this object. Relationships are not included.
- */
- public String eoShallowDescription()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns the key used to reference this object on the
- * object at the other end of the specified relationship.
- * This implementation calls to the class description.
- */
- public String inverseForRelationshipKey(String aRelationshipKey)
- {
- return classDescription().inverseForRelationshipKey( aRelationshipKey );
- }
-
- //Object invokeRemoteMethod(
- // String aMethodName, Class[] aTypeArray Object[] anArgumentArray)
-
- /**
- * Returns whether the specified relationship key represents
- * a to-many relationship.
- */
- public boolean isToManyKey(String aKey)
- {
- return toManyRelationshipKeys().containsObject( aKey );
- }
-
- /**
- * Returns whether the objects at the other end of the specified
- * relationship should be deleted when this object is deleted.
- * This implementation calls to the class description.
- */
- public boolean ownsDestinationObjectsForRelationshipKey(String aKey)
- {
- return classDescription().ownsDestinationObjectsForRelationshipKey( aKey );
- }
-
- //void prepareValuesForClient()
-
- /**
- * Called to perform the delete propagation for this object
- * on the specified editing context. All relationships
- * should be processed according to their corresponding
- * delete rule.
- * This implementation calls to the class description.
- */
- public void propagateDeleteWithEditingContext(EOEditingContext aContext)
- {
- classDescription().propagateDeleteForObject( this, aContext );
- }
-
- /**
- * Applies the changes from the specified snapshot to
- * this object.
- * @see #changesFromSnapshot(NSDictionary)
- */
- public void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot)
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a snapshot of the current state of this object.
- * All property keys are mapped to their values; nulls are
- * represented by NSNull.
- */
- public NSDictionary snapshot()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a List of the to-many relationship keys
- * for this object.
- * This implementation calls to the class description.
- */
- public NSArray toManyRelationshipKeys()
- {
- return classDescription().toManyRelationshipKeys();
- }
-
- /**
- * Returns a List of the to-one relationship keys
- * for this object.
- * This implementation calls to the class description.
- */
- public NSArray toOneRelationshipKeys()
- {
- return classDescription().toOneRelationshipKeys();
- }
-
- /**
- * Applies the specified snapshot to this object,
- * converting NSNulls to null and calling
- * takeStoredValueForKey for each key in the Map.
- */
- public void updateFromSnapshot(NSDictionary aSnapshot)
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a short, stateful string representation
- * of this object.
- * This implementation calls to the class description.
- */
- public String userPresentableDescription()
- {
- return classDescription().userPresentableDescriptionForObject( this );
- }
-
- /**
- * This method should be called by each setter method
- * on this object before changes are made to the
- * object's internal state. This implementation calls
- * EOObserverCenter.notifyObserversObjectWillChange( this ),
- */
- public void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- // interface EOKeyValueCoding
-
- /**
- * Returns the value for the specified property.
- * If the property does not exist, this method should
- * call handleQueryWithUnboundKey.
- */
- public Object valueForKey( String aKey )
- {
- return EOKeyValueCodingSupport.valueForKey( this, aKey );
- }
-
- /**
- * Sets the property to the specified value.
- * If the property does not exist, this method should
- * call handleTakeValueForUnboundKey.
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey.
- */
- public void takeValueForKey( Object aValue, String aKey )
- {
- EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
- }
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property.
- */
- public Object storedValueForKey( String aKey )
- {
- return EOKeyValueCodingSupport.storedValueForKey( this, aKey );
- }
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value.
- */
- public void takeStoredValueForKey( Object aValue, String aKey )
- {
- EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
- }
-
- /**
- * Called by valueForKey when the specified key is
- * not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- public Object handleQueryWithUnboundKey( String aKey )
- {
- return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- public void handleTakeValueForUnboundKey( Object aValue, String aKey )
- {
- EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types. Implementing
- * classes should handle this case appropriately
- * or otherwise throw an exception.
- */
- public void unableToSetNullForKey( String aKey )
- {
- EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- // interface EOKeyValueCodingAdditions
-
- /**
- * Returns the value for the specified key path, which is
- * a series of keys delimited by ".", for example:
- * "createTime.year.length".
- */
- public Object valueForKeyPath( String aKeyPath )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Sets the value for the specified key path, which is
- * a series of keys delimited by ".", for example:
- * "createTime.year.length".
- * The value is set for the last object referenced by
- * the key path.
- */
- public void takeValueForKeyPath( Object aValue, String aKeyPath )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map of the specified keys to their values,
- * each of which might be obtained by calling valueForKey.
- */
- public NSDictionary valuesForKeys( List aKeyList )
- {
- return KeyValueCodingUtilities.valuesForKeys( this, aKeyList );
- }
-
- /**
- * Takes the keys from the specified map as properties
- * and applies the corresponding values, each of which
- * might be set by calling takeValueForKey.
- */
- public void takeValuesFromDictionary( Map aMap )
- {
- KeyValueCodingUtilities.takeValuesFromDictionary( this, aMap );
- }
-
- // interface EOFaulting
-
- /**
- * Called by EOFaultHandler to prepare the object to be turned into a fault.
- */
- public void clearFault()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns this object's EOFaultHandler.
- */
- public EOFaultHandler faultHandler()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this object is currently a fault.
- * Returns true if this object has not yet retrieved any values.
- */
- public boolean isFault()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Turns this object into a fault using the specified fault handler.
- */
- public void turnIntoFault( EOFaultHandler aFaultHandler )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Called to completely fire the fault, reading all attributes.
- * This method may be implemented to call willRead(null).
- */
- public void willRead()
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Called to fire the fault for the specified key.
- * The fault manager is required to populate the specified key
- * with a value, and may populate any or all of the other values
- * on this object. A null key will populate all values on the object.
- * NOTE: This method is not part of the specification.
- */
- public void willRead( String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- // interface EODeferredFaulting
-
- /**
- * Returns a fault for the specified deferred fault.
- */
- public Object willReadRelationship( Object anObject )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- // interface EORelationshipManipulation
-
- /**
- * Adds the specified object to the relationship on this
- * object specified by the key. For to-one relationships,
- * this operation is the same as valueForKey.
- */
- public void addObjectToPropertyWithKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Removes the specified object from the relationship on
- * this object specified by the key. For to-one relationships,
- * this operation is the same as takeValueForKey with a null
- * value.
- */
- public void removeObjectFromPropertyWithKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * As addObjectToProperty with key, but also performs the
- * reciprocal operation on the other side of the relationship.
- */
- public void addObjectToBothSidesOfRelationshipWithKey(
- EORelationshipManipulation anObject, String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * As removeObjectFromPropertyWithKey with key, but also performs the
- * reciprocal operation on the other side of the relationship.
- */
- public void removeObjectFromBothSidesOfRelationshipWithKey(
- EORelationshipManipulation anObject, String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- // interface EOValidation
-
- /**
- * Validates this object for delete.
- * Throws an exception if this object cannot be deleted.
- * This implementation calls to the class description.
- */
- public void validateForDelete()
- {
- classDescription().validateObjectForDelete( this );
- }
-
- /**
- * Validates this object for insertion into the external store.
- * Throws an exception if this object cannot be inserted.
- * Validations here should be specific to insertion.
- * This implementation calls validateForSave().
- */
- public void validateForInsert()
- {
- validateForSave();
- }
-
- /**
- * Validates this object for a commit to the external store.
- * Throws an exception if this object cannot be committed.
- * Validations here are not specific to either inserts or updates.
- * This implementation calls to the class description.
- */
- public void validateForSave()
- {
- classDescription().validateObjectForSave( this );
- }
-
- /**
- * Validates this object for update to the external store.
- * Throws an exception if this object cannot be updated.
- * Validations here should be specific to updates.
- * This implementation calls validateForSave().
- */
- public void validateForUpdate()
- {
- validateForSave();
- }
+ * EOCustomObject implements all the necessary interfaces to receive first-class
+ * treatment from the control framework. The implementation delegates as much
+ * class meta-behavior as possible to EOClassDescription, letting subclasses
+ * focus exclusively on business logic while still allowing them to customize as
+ * much class behavior as needed.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOCustomObject implements EOEnterpriseObject, EOKeyValueCodingAdditions, EODeferredFaulting,
+ EORelationshipManipulation, EOValidation {
+ private transient static EOClassDescription classDescription;
+ private transient EOEditingContext editingContext;
+
+ // static configuration
+
+ /**
+ * Specifies whether the implementation of EOKeyValueCoding is permitted to
+ * access field directly. This implementation returns true; subclasses may
+ * override to customize this behavior.
+ */
+ public static boolean canAccessFieldsDirectly() {
+ return true;
+ }
+
+ /**
+ * Specifies whether the implementation of EOKeyValueCoding is permitted to
+ * access private accessors. This implementation returns true; subclasses may
+ * override to customize this behavior.
+ */
+ public static boolean shouldUseStoredAccessors() {
+ return true;
+ }
+
+ /**
+ * Specifies whether deferred faults should be used. This implementation returns
+ * false; subclasses may override to customize this behavior.
+ */
+ public static boolean usesDeferredFaultCreation() {
+ return false;
+ }
+
+ // constructors
+
+ /**
+ * Default constructor initializes private state. EditingContext and
+ * ClassDescription are set to null.
+ */
+ public EOCustomObject() {
+ editingContext = null;
+ classDescription = null;
+ }
+
+ /**
+ * Preferred constructor, specifying an editing context, a class description,
+ * and a global id, any or all of which may be null. Subclasses should invoke
+ * this constructor.
+ */
+ public EOCustomObject(EOEditingContext aContext, EOClassDescription aClassDescription, EOGlobalID aGlobalID) {
+ editingContext = aContext;
+ classDescription = aClassDescription;
+ }
+
+ // interface EOEnterpriseObject
+
+ /**
+ * Returns a List of all property keys defined on this object. This includes
+ * both attributes and relationships. This implementation returns the union of
+ * attributeKeys, toOneRelationshipKeys, and toManyRelationshipKeys.
+ */
+ public NSArray allPropertyKeys() {
+ NSSet union = new NSSet();
+ union.addAll(attributeKeys());
+ union.addAll(toOneRelationshipKeys());
+ union.addAll(toManyRelationshipKeys());
+ return new NSArray((Collection) union);
+ }
+
+ /**
+ * Returns a list of all attributes defined on this object. Attributes are all
+ * properties that are not relationships. This implementation retrieves the keys
+ * from the class description.
+ */
+ public NSArray attributeKeys() {
+ return classDescription().attributeKeys();
+ }
+
+ // void awakeFromClientUpdate(EOEditingContext aContext)
+
+ /**
+ * Called when the object has first been fetched into the specified editing
+ * context. This implementation calls awakeObjectFromFetch on the class
+ * description.
+ */
+ public void awakeFromFetch(EOEditingContext anEditingContext) {
+ classDescription().awakeObjectFromFetch(this, anEditingContext);
+ }
+
+ /**
+ * Called when the object has been inserted into the specified editing context.
+ * This implementation calls awakeObjectFromInsertion on the class description.
+ */
+ public void awakeFromInsertion(EOEditingContext anEditingContext) {
+ classDescription().awakeObjectFromInsertion(this, anEditingContext);
+ }
+
+ /**
+ * Returns a Map representing the delta of the current state from the state
+ * represented in the specified snapshot. The result will contain only the keys
+ * that have changed and their values. Relationship keys will map to an NSArray
+ * that contains an NSArray of added objects and an NSArray of removed objects,
+ * in that order.
+ */
+ public NSDictionary changesFromSnapshot(NSDictionary snapshot) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a class description for this object. Calls
+ * EOClassDescription.classDescriptionForClass.
+ */
+ public EOClassDescription classDescription() {
+ if (classDescription == null) {
+ classDescription = EOClassDescription.classDescriptionForClass(getClass());
+ if (classDescription == null) {
+ throw new WotonomyException("No class description found for class: " + getClass());
+ }
+ }
+ return classDescription;
+ }
+
+ /**
+ * Returns a class description for the object at the other end of the specified
+ * relationship key. This implementation calls to the classDescription.
+ */
+ public EOClassDescription classDescriptionForDestinationKey(String aKey) {
+ return classDescription().classDescriptionForDestinationKey(aKey);
+ }
+
+ /**
+ * Clears all property values for this object. This method is called to clean-up
+ * an object that will no longer be used, and implementations should ensure that
+ * all references are set to null to prevent problems with garbage-collection.
+ */
+ public void clearProperties() {
+ // FIXME: clear properties here
+ }
+
+ /**
+ * Returns the delete rule constant defined on EOClassDescription for the
+ * relationship defined by the specified key. This implementation calls to the
+ * classDescription.
+ */
+ public int deleteRuleForRelationshipKey(String aRelationshipKey) {
+ return classDescription().deleteRuleForRelationshipKey(aRelationshipKey);
+ }
+
+ /**
+ * Returns the editing context in which this object is registered.
+ */
+ public EOEditingContext editingContext() {
+ return editingContext;
+ }
+
+ /**
+ * Returns the name of the entity that this object represents.
+ */
+ public String entityName() {
+ return classDescription().entityName();
+ }
+
+ /**
+ * Returns a String containing all property keys and values for this object.
+ * Relationships should be represented by calling eoShallowDescription() on the
+ * object.
+ */
+ public String eoDescription() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a String containing all attribute keys and values for this object.
+ * Relationships are not included.
+ */
+ public String eoShallowDescription() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns the key used to reference this object on the object at the other end
+ * of the specified relationship. This implementation calls to the class
+ * description.
+ */
+ public String inverseForRelationshipKey(String aRelationshipKey) {
+ return classDescription().inverseForRelationshipKey(aRelationshipKey);
+ }
+
+ // Object invokeRemoteMethod(
+ // String aMethodName, Class[] aTypeArray Object[] anArgumentArray)
+
+ /**
+ * Returns whether the specified relationship key represents a to-many
+ * relationship.
+ */
+ public boolean isToManyKey(String aKey) {
+ return toManyRelationshipKeys().containsObject(aKey);
+ }
+
+ /**
+ * Returns whether the objects at the other end of the specified relationship
+ * should be deleted when this object is deleted. This implementation calls to
+ * the class description.
+ */
+ public boolean ownsDestinationObjectsForRelationshipKey(String aKey) {
+ return classDescription().ownsDestinationObjectsForRelationshipKey(aKey);
+ }
+
+ // void prepareValuesForClient()
+
+ /**
+ * Called to perform the delete propagation for this object on the specified
+ * editing context. All relationships should be processed according to their
+ * corresponding delete rule. This implementation calls to the class
+ * description.
+ */
+ public void propagateDeleteWithEditingContext(EOEditingContext aContext) {
+ classDescription().propagateDeleteForObject(this, aContext);
+ }
+
+ /**
+ * Applies the changes from the specified snapshot to this object.
+ *
+ * @see #changesFromSnapshot(NSDictionary)
+ */
+ public void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a snapshot of the current state of this object. All property keys are
+ * mapped to their values; nulls are represented by NSNull.
+ */
+ public NSDictionary snapshot() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a List of the to-many relationship keys for this object. This
+ * implementation calls to the class description.
+ */
+ public NSArray toManyRelationshipKeys() {
+ return classDescription().toManyRelationshipKeys();
+ }
+
+ /**
+ * Returns a List of the to-one relationship keys for this object. This
+ * implementation calls to the class description.
+ */
+ public NSArray toOneRelationshipKeys() {
+ return classDescription().toOneRelationshipKeys();
+ }
+
+ /**
+ * Applies the specified snapshot to this object, converting NSNulls to null and
+ * calling takeStoredValueForKey for each key in the Map.
+ */
+ public void updateFromSnapshot(NSDictionary aSnapshot) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a short, stateful string representation of this object. This
+ * implementation calls to the class description.
+ */
+ public String userPresentableDescription() {
+ return classDescription().userPresentableDescriptionForObject(this);
+ }
+
+ /**
+ * This method should be called by each setter method on this object before
+ * changes are made to the object's internal state. This implementation calls
+ * EOObserverCenter.notifyObserversObjectWillChange( this ),
+ */
+ public void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ // interface EOKeyValueCoding
+
+ /**
+ * Returns the value for the specified property. If the property does not exist,
+ * this method should call handleQueryWithUnboundKey.
+ */
+ public Object valueForKey(String aKey) {
+ return EOKeyValueCodingSupport.valueForKey(this, aKey);
+ }
+
+ /**
+ * Sets the property to the specified value. If the property does not exist,
+ * this method should call handleTakeValueForUnboundKey. If the property is of a
+ * type that cannot allow null (e.g. primitive types) and aValue is null, this
+ * method should call unableToSetNullForKey.
+ */
+ public void takeValueForKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.takeValueForKey(this, aValue, aKey);
+ }
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property.
+ */
+ public Object storedValueForKey(String aKey) {
+ return EOKeyValueCodingSupport.storedValueForKey(this, aKey);
+ }
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value.
+ */
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.takeStoredValueForKey(this, aValue, aKey);
+ }
+
+ /**
+ * Called by valueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return EOKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types. Implementing classes should
+ * handle this case appropriately or otherwise throw an exception.
+ */
+ public void unableToSetNullForKey(String aKey) {
+ EOKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ // interface EOKeyValueCodingAdditions
+
+ /**
+ * Returns the value for the specified key path, which is a series of keys
+ * delimited by ".", for example: "createTime.year.length".
+ */
+ public Object valueForKeyPath(String aKeyPath) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the value for the specified key path, which is a series of keys
+ * delimited by ".", for example: "createTime.year.length". The value is set for
+ * the last object referenced by the key path.
+ */
+ public void takeValueForKeyPath(Object aValue, String aKeyPath) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map of the specified keys to their values, each of which might be
+ * obtained by calling valueForKey.
+ */
+ public NSDictionary valuesForKeys(List aKeyList) {
+ return KeyValueCodingUtilities.valuesForKeys(this, aKeyList);
+ }
+
+ /**
+ * Takes the keys from the specified map as properties and applies the
+ * corresponding values, each of which might be set by calling takeValueForKey.
+ */
+ public void takeValuesFromDictionary(Map aMap) {
+ KeyValueCodingUtilities.takeValuesFromDictionary(this, aMap);
+ }
+
+ // interface EOFaulting
+
+ /**
+ * Called by EOFaultHandler to prepare the object to be turned into a fault.
+ */
+ public void clearFault() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns this object's EOFaultHandler.
+ */
+ public EOFaultHandler faultHandler() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this object is currently a fault. Returns true if this object
+ * has not yet retrieved any values.
+ */
+ public boolean isFault() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Turns this object into a fault using the specified fault handler.
+ */
+ public void turnIntoFault(EOFaultHandler aFaultHandler) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Called to completely fire the fault, reading all attributes. This method may
+ * be implemented to call willRead(null).
+ */
+ public void willRead() {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Called to fire the fault for the specified key. The fault manager is required
+ * to populate the specified key with a value, and may populate any or all of
+ * the other values on this object. A null key will populate all values on the
+ * object. NOTE: This method is not part of the specification.
+ */
+ public void willRead(String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ // interface EODeferredFaulting
+
+ /**
+ * Returns a fault for the specified deferred fault.
+ */
+ public Object willReadRelationship(Object anObject) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ // interface EORelationshipManipulation
+
+ /**
+ * Adds the specified object to the relationship on this object specified by the
+ * key. For to-one relationships, this operation is the same as valueForKey.
+ */
+ public void addObjectToPropertyWithKey(Object anObject, String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Removes the specified object from the relationship on this object specified
+ * by the key. For to-one relationships, this operation is the same as
+ * takeValueForKey with a null value.
+ */
+ public void removeObjectFromPropertyWithKey(Object anObject, String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * As addObjectToProperty with key, but also performs the reciprocal operation
+ * on the other side of the relationship.
+ */
+ public void addObjectToBothSidesOfRelationshipWithKey(EORelationshipManipulation anObject, String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * As removeObjectFromPropertyWithKey with key, but also performs the reciprocal
+ * operation on the other side of the relationship.
+ */
+ public void removeObjectFromBothSidesOfRelationshipWithKey(EORelationshipManipulation anObject, String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ // interface EOValidation
+
+ /**
+ * Validates this object for delete. Throws an exception if this object cannot
+ * be deleted. This implementation calls to the class description.
+ */
+ public void validateForDelete() {
+ classDescription().validateObjectForDelete(this);
+ }
+
+ /**
+ * Validates this object for insertion into the external store. Throws an
+ * exception if this object cannot be inserted. Validations here should be
+ * specific to insertion. This implementation calls validateForSave().
+ */
+ public void validateForInsert() {
+ validateForSave();
+ }
+
+ /**
+ * Validates this object for a commit to the external store. Throws an exception
+ * if this object cannot be committed. Validations here are not specific to
+ * either inserts or updates. This implementation calls to the class
+ * description.
+ */
+ public void validateForSave() {
+ classDescription().validateObjectForSave(this);
+ }
+
+ /**
+ * Validates this object for update to the external store. Throws an exception
+ * if this object cannot be updated. Validations here should be specific to
+ * updates. This implementation calls validateForSave().
+ */
+ public void validateForUpdate() {
+ validateForSave();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2001/12/06 16:42:29 mpowers
- * Added appropriate constructor.
+ * Revision 1.3 2001/12/06 16:42:29 mpowers Added appropriate constructor.
*
- * Revision 1.2 2001/11/24 17:37:29 mpowers
- * Implemented static methods.
+ * Revision 1.2 2001/11/24 17:37:29 mpowers Implemented static methods.
*
- * Revision 1.1 2001/11/17 17:18:15 mpowers
- * Initial implementation of EOCustomObject.
+ * Revision 1.1 2001/11/17 17:18:15 mpowers Initial implementation of
+ * EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODataSource.java
index c7e5284..9d3c255 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODataSource.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODataSource.java
@@ -21,144 +21,122 @@ package net.wotonomy.control;
import net.wotonomy.foundation.NSArray;
/**
-* EODataSource is used by EODisplayGroup.fetch() to retrieve
-* a list of objects to display. When a display group has a
-* data source, the display group will use the data source to
-* populate the object list and to create new objects to be
-* displayed in the list, and will update the data source when
-* objects are inserted or removed from the list. <br><br>
-*
-* In certain cases, as when a display group needs to populate
-* a child display group to show a one-to-many relationship,
-* the display group will call dataSourceQualifiedByKey to
-* return a new data source that can vend objects associated
-* with the specified key and then call qualifyWithRelationshipKey
-* to specify the object and key that are the source of the
-* child relationship. <br><br>
-*
-* Concrete subclasses are expected to override fetch() and
-* are required to override insertObject and removeObject.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public abstract class EODataSource
-{
- /**
- * Creates a new object. You should call
- * insertObject() to insert the new object into
- * this data source.
- * This implementation attempts to create a new
- * instance of the class returned by
- * classDescriptionForObjects().
- * Override to return an object specific to
- * your implementation.
- * @return The newly created object, or null if
- * new objects are not supported by this data source.
- * @see #classDescriptionForObjects
- */
- public Object createObject ()
- {
- Object result = null;
- EOClassDescription c = classDescriptionForObjects();
- if ( c != null )
- {
- result = c.createInstanceWithEditingContext( editingContext(), null );
- }
- return result;
- }
-
- /**
- * Inserts the specified object into this data source.
- */
- public abstract void insertObject ( Object anObject );
-
- /**
- * Deletes the specified object from this data source.
- */
- public abstract void deleteObject ( Object anObject );
-
- /**
- * Returns the editing context for this data source,
- * or null if no editing context is used.
- * This implementation returns null.
- */
- public EOEditingContext editingContext ()
- {
- return null;
- }
-
- /**
- * Returns a List containing the objects in this
- * data source. This implementation returns null.
- */
- public NSArray fetchObjects ()
- {
- return null;
- }
-
- /**
- * Returns a data source that is capable of
- * manipulating objects of the type returned by
- * applying the specified key to objects
- * vended by this data source.
- * @see #qualifyWithRelationshipKey
- */
- public abstract EODataSource
- dataSourceQualifiedByKey ( String aKey );
-
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- */
- public abstract void
- qualifyWithRelationshipKey (
- String aKey, Object anObject );
-
- /**
- * Returns the description of the class of the
- * objects that is vended by this data source,
- * or null if this cannot be determined.
- * This implementation returns null.
- */
- public EOClassDescription
- classDescriptionForObjects ()
- {
- return null;
- }
+ * EODataSource is used by EODisplayGroup.fetch() to retrieve a list of objects
+ * to display. When a display group has a data source, the display group will
+ * use the data source to populate the object list and to create new objects to
+ * be displayed in the list, and will update the data source when objects are
+ * inserted or removed from the list. <br>
+ * <br>
+ *
+ * In certain cases, as when a display group needs to populate a child display
+ * group to show a one-to-many relationship, the display group will call
+ * dataSourceQualifiedByKey to return a new data source that can vend objects
+ * associated with the specified key and then call qualifyWithRelationshipKey to
+ * specify the object and key that are the source of the child relationship.
+ * <br>
+ * <br>
+ *
+ * Concrete subclasses are expected to override fetch() and are required to
+ * override insertObject and removeObject.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public abstract class EODataSource {
+ /**
+ * Creates a new object. You should call insertObject() to insert the new object
+ * into this data source. This implementation attempts to create a new instance
+ * of the class returned by classDescriptionForObjects(). Override to return an
+ * object specific to your implementation.
+ *
+ * @return The newly created object, or null if new objects are not supported by
+ * this data source.
+ * @see #classDescriptionForObjects
+ */
+ public Object createObject() {
+ Object result = null;
+ EOClassDescription c = classDescriptionForObjects();
+ if (c != null) {
+ result = c.createInstanceWithEditingContext(editingContext(), null);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified object into this data source.
+ */
+ public abstract void insertObject(Object anObject);
+
+ /**
+ * Deletes the specified object from this data source.
+ */
+ public abstract void deleteObject(Object anObject);
+
+ /**
+ * Returns the editing context for this data source, or null if no editing
+ * context is used. This implementation returns null.
+ */
+ public EOEditingContext editingContext() {
+ return null;
+ }
+
+ /**
+ * Returns a List containing the objects in this data source. This
+ * implementation returns null.
+ */
+ public NSArray fetchObjects() {
+ return null;
+ }
+
+ /**
+ * Returns a data source that is capable of manipulating objects of the type
+ * returned by applying the specified key to objects vended by this data source.
+ *
+ * @see #qualifyWithRelationshipKey
+ */
+ public abstract EODataSource dataSourceQualifiedByKey(String aKey);
+
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object.
+ */
+ public abstract void qualifyWithRelationshipKey(String aKey, Object anObject);
+
+ /**
+ * Returns the description of the class of the objects that is vended by this
+ * data source, or null if this cannot be determined. This implementation
+ * returns null.
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ return null;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2001/05/21 14:02:44 mpowers
- * Corrected javadoc.
+ * Revision 1.5 2001/05/21 14:02:44 mpowers Corrected javadoc.
*
- * Revision 1.4 2001/04/27 23:37:20 mpowers
- * Now using EOClassDescription in the EODataSource class, as we should.
+ * Revision 1.4 2001/04/27 23:37:20 mpowers Now using EOClassDescription in the
+ * EODataSource class, as we should.
*
- * Revision 1.3 2001/02/27 23:11:07 mpowers
- * Removed object registration from createObject().
+ * Revision 1.3 2001/02/27 23:11:07 mpowers Removed object registration from
+ * createObject().
*
- * Revision 1.2 2001/02/16 18:34:19 mpowers
- * Implementing nested contexts.
+ * Revision 1.2 2001/02/16 18:34:19 mpowers Implementing nested contexts.
*
- * Revision 1.1.1.1 2000/12/21 15:46:38 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:38 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:34 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:34 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODatabaseDataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODatabaseDataSource.java
index 2e350f1..489d779 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODatabaseDataSource.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODatabaseDataSource.java
@@ -28,312 +28,267 @@ import net.wotonomy.foundation.NSSet;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EODatabaseSource is a general-purpose implementation
-* of EODataSource that is EOClassDescription-aware and
-* that can vend appropriate EODetailDataSources.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public abstract class EODatabaseDataSource
-{
- EOQualifier auxiliaryQualifier;
- EOEditingContext editingContext;
- String entityName;
- String fetchSpecificationName;
- EOFetchSpecification fetchSpecification;
- NSDictionary qualifierBindings;
- EOClassDescription classDescription;
- boolean fetchEnabled;
-
- /**
- * Constructs a data source that fetches all objects of
- * the specified entity type.
- */
- public EODatabaseDataSource(
- EOEditingContext aContext, String anEntityName)
- {
- this( aContext, anEntityName, null );
- }
-
- /**
- * Constructs a data source that fetches objects of the
- * specified entity type according to the fetch specification
- * with the specified name.
- */
- public EODatabaseDataSource(
- EOEditingContext aContext, String anEntityName, String aFetchSpecName)
- {
- fetchEnabled = true;
- editingContext = aContext;
- entityName = anEntityName;
- setFetchSpecificationByName( fetchSpecificationName );
- }
-
- /**
- * Returns the qualifier that is applied to the results fetched by the fetch
- * specification before objects are returned by fetch objects, or null if no
- * such qualifier has been specified.
- */
- public EOQualifier auxiliaryQualifier()
- {
- return auxiliaryQualifier;
- }
-
- /**
- * Returns the description of the class of the
- * objects that is vended by this data source,
- * or null if no entity name is specified.
- */
- public EOClassDescription classDescriptionForObjects ()
- {
- if ( entityName == null ) return null;
- return EOClassDescription.classDescriptionForEntityName( entityName );
- }
-
- /**
- * Returns the object store at the root of the
- * editing context's editing hierarchy.
- */
- public EOObjectStore databaseContext()
- {
- EOObjectStore store = editingContext();
- while ( store instanceof EOEditingContext )
- {
- store = ((EOEditingContext)store).parentObjectStore();
- }
- return store;
- }
-
- /**
- * Returns a detail data source that is capable of
- * manipulating objects of the type returned by
- * applying the specified key to objects
- * vended by this data source.
- * @see #qualifyWithRelationshipKey
- */
- public EODataSource dataSourceQualifiedByKey ( String aKey )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- /**
- * Deletes the specified object from this data source.
- * This implementation deletes the specified object from
- * the editing context.
- */
- public void deleteObject ( Object anObject )
- {
- editingContext.deleteObject( anObject );
- }
-
- /**
- * Returns the editing context for this data source,
- * or null if no editing context was specified.
- */
- public EOEditingContext editingContext ()
- {
- return editingContext;
- }
+ * EODatabaseSource is a general-purpose implementation of EODataSource that is
+ * EOClassDescription-aware and that can vend appropriate EODetailDataSources.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public abstract class EODatabaseDataSource {
+ EOQualifier auxiliaryQualifier;
+ EOEditingContext editingContext;
+ String entityName;
+ String fetchSpecificationName;
+ EOFetchSpecification fetchSpecification;
+ NSDictionary qualifierBindings;
+ EOClassDescription classDescription;
+ boolean fetchEnabled;
-/*
- public EOEntity entity() {}
-*/
+ /**
+ * Constructs a data source that fetches all objects of the specified entity
+ * type.
+ */
+ public EODatabaseDataSource(EOEditingContext aContext, String anEntityName) {
+ this(aContext, anEntityName, null);
+ }
+
+ /**
+ * Constructs a data source that fetches objects of the specified entity type
+ * according to the fetch specification with the specified name.
+ */
+ public EODatabaseDataSource(EOEditingContext aContext, String anEntityName, String aFetchSpecName) {
+ fetchEnabled = true;
+ editingContext = aContext;
+ entityName = anEntityName;
+ setFetchSpecificationByName(fetchSpecificationName);
+ }
+
+ /**
+ * Returns the qualifier that is applied to the results fetched by the fetch
+ * specification before objects are returned by fetch objects, or null if no
+ * such qualifier has been specified.
+ */
+ public EOQualifier auxiliaryQualifier() {
+ return auxiliaryQualifier;
+ }
+
+ /**
+ * Returns the description of the class of the objects that is vended by this
+ * data source, or null if no entity name is specified.
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ if (entityName == null)
+ return null;
+ return EOClassDescription.classDescriptionForEntityName(entityName);
+ }
+
+ /**
+ * Returns the object store at the root of the editing context's editing
+ * hierarchy.
+ */
+ public EOObjectStore databaseContext() {
+ EOObjectStore store = editingContext();
+ while (store instanceof EOEditingContext) {
+ store = ((EOEditingContext) store).parentObjectStore();
+ }
+ return store;
+ }
+
+ /**
+ * Returns a detail data source that is capable of manipulating objects of the
+ * type returned by applying the specified key to objects vended by this data
+ * source.
+ *
+ * @see #qualifyWithRelationshipKey
+ */
+ public EODataSource dataSourceQualifiedByKey(String aKey) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Deletes the specified object from this data source. This implementation
+ * deletes the specified object from the editing context.
+ */
+ public void deleteObject(Object anObject) {
+ editingContext.deleteObject(anObject);
+ }
+
+ /**
+ * Returns the editing context for this data source, or null if no editing
+ * context was specified.
+ */
+ public EOEditingContext editingContext() {
+ return editingContext;
+ }
+
+ /*
+ * public EOEntity entity() {}
+ */
+
+ /**
+ * Returns a List containing the objects of the current entity type that conform
+ * to the specified fetch specification. If an auxiliary qualifier has been
+ * specified, that qualifier is applied to the objects before returning the
+ * result. If fetch is not enabled, this method returns null.
+ */
+ public NSArray fetchObjects() {
+ if (!isFetchEnabled())
+ return null;
+ NSArray result = editingContext.objectsWithFetchSpecification(fetchSpecification());
+ if (auxiliaryQualifier() != null) {
+ result = EOQualifier.filteredArrayWithQualifier(result, auxiliaryQualifier());
+ }
+ return result;
+ }
- /**
- * Returns a List containing the objects of the current
- * entity type that conform to the specified fetch specification.
- * If an auxiliary qualifier has been specified, that qualifier
- * is applied to the objects before returning the result.
- * If fetch is not enabled, this method returns null.
- */
- public NSArray fetchObjects ()
- {
- if ( ! isFetchEnabled() ) return null;
- NSArray result =
- editingContext.objectsWithFetchSpecification( fetchSpecification() );
- if ( auxiliaryQualifier() != null )
- {
- result = EOQualifier.filteredArrayWithQualifier( result, auxiliaryQualifier() );
- }
- return result;
- }
-
- /**
- * Returns the fetch specification currently used by this data
- * source to fetch objects, or null if none is specified.
- * If null, this fetchObjects() will return all objects of the
- * specified entity type.
- */
- public EOFetchSpecification fetchSpecification()
- {
- return fetchSpecification;
- }
-
- /**
- * Returns a copy of the fetch specification that will be used to
- * determine fetch for this data source. If this data source has
- * an auxiliary qualifier, that qualifier will be inserted into
- * the returned fetch specification's qualifier.
- */
- public EOFetchSpecification fetchSpecificationForFetch()
- {
- EOFetchSpecification result = (EOFetchSpecification) fetchSpecification.clone();
- if ( auxiliaryQualifier() != null )
- {
- NSMutableArray join = new NSMutableArray();
- join.addObject( fetchSpecification.qualifier() );
- join.addObject( auxiliaryQualifier() );
- result.setQualifier( new EOAndQualifier( join ) );
- }
- return result;
- }
-
- /**
- * Returns the name of the current fetch specification, or null
- * if no name has been specified.
- */
- public String fetchSpecificationName()
- {
- return fetchSpecificationName;
- }
-
- /**
- * Inserts the specified object into this data source.
- * This implementation registers the object as an inserted
- * object with the editing context.
- */
- public void insertObject ( Object anObject )
- {
- editingContext.insertObject( anObject );
- }
-
- /**
- * Returns whether fetching is currently allowed.
- * If false, fetchObjects() will return null.
- * Default is true.
- */
- public boolean isFetchEnabled()
- {
- return fetchEnabled;
- }
-
- /**
- * Returns a List of the union of the binding keys for the fetch spec's
- * qualifier and the auxiliary qualifier.
- */
- public NSArray qualifierBindingKeys()
- {
- NSSet union = new NSSet();
- if ( ( fetchSpecification != null )
- && ( fetchSpecification.qualifier() != null ) )
- {
- union.addAll( fetchSpecification.qualifier().bindingKeys() );
- }
- if ( auxiliaryQualifier() != null )
- {
- union.addAll( auxiliaryQualifier().bindingKeys() );
- }
- return new NSArray( (Collection) union );
- }
-
- /**
- * Returns a Map of the bindings that will be applied against
- * the fetch spec's qualifier and the auxiliary qualifier,
- * or null if no bindings exist.
- */
- public NSDictionary qualifierBindings()
- {
- if ( qualifierBindings == null ) return null;
- return new NSDictionary( (Map) qualifierBindings );
- }
-
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- */
- public void qualifyWithRelationshipKey (
- String aKey, Object anObject )
- {
- throw new WotonomyException( "Not implemented yet" );
- }
-
- /**
- * Sets the auxiliary qualifier that will be applied to
- * objects returned from the fetch described by the fetch specification.
- */
- public void setAuxiliaryQualifier(EOQualifier aQualifier)
- {
- auxiliaryQualifier = aQualifier;
- }
-
- /**
- * Sets whether fetches are currently allowed.
- * If false, fetchObjects() will return null.
- */
- public void setFetchEnabled(boolean isFetchEnabled)
- {
- fetchEnabled = isFetchEnabled;
- }
-
- /**
- * Sets the fetch specification used by this data source.
- * If null, all objects of the specified entity type will
- * be returned by fetchObjects().
- */
- public void setFetchSpecification( EOFetchSpecification aFetchSpec)
- {
- fetchSpecificationName = null;
- fetchSpecification = aFetchSpec;
- }
-
- /**
- * Sets the fetch specification used by this data source,
- * requesting it from the class description for this data source's
- * entity class description, if any. If the name cannot be resolved,
- * the fetch specification will be set to null.
- */
- public void setFetchSpecificationByName(String aName)
- {
- fetchSpecificationName = aName;
- fetchSpecification = EOFetchSpecification.fetchSpecificationNamed( aName, entityName );
- }
-
- /*
- public void setParentDataSourceRelationshipKey( EODataSource aDataSource, String aKey)
- */
-
- /**
- * Sets the bindings to be applied to the fetch specification and the auxiliary qualifier.
- */
- public void setQualifierBindings(Map aBindingMap)
- {
- if ( aBindingMap == null )
- {
- qualifierBindings = null;
- }
- else
- {
- qualifierBindings = new NSDictionary( (Map) aBindingMap );
- }
- }
+ /**
+ * Returns the fetch specification currently used by this data source to fetch
+ * objects, or null if none is specified. If null, this fetchObjects() will
+ * return all objects of the specified entity type.
+ */
+ public EOFetchSpecification fetchSpecification() {
+ return fetchSpecification;
+ }
+
+ /**
+ * Returns a copy of the fetch specification that will be used to determine
+ * fetch for this data source. If this data source has an auxiliary qualifier,
+ * that qualifier will be inserted into the returned fetch specification's
+ * qualifier.
+ */
+ public EOFetchSpecification fetchSpecificationForFetch() {
+ EOFetchSpecification result = (EOFetchSpecification) fetchSpecification.clone();
+ if (auxiliaryQualifier() != null) {
+ NSMutableArray join = new NSMutableArray();
+ join.addObject(fetchSpecification.qualifier());
+ join.addObject(auxiliaryQualifier());
+ result.setQualifier(new EOAndQualifier(join));
+ }
+ return result;
+ }
+
+ /**
+ * Returns the name of the current fetch specification, or null if no name has
+ * been specified.
+ */
+ public String fetchSpecificationName() {
+ return fetchSpecificationName;
+ }
+
+ /**
+ * Inserts the specified object into this data source. This implementation
+ * registers the object as an inserted object with the editing context.
+ */
+ public void insertObject(Object anObject) {
+ editingContext.insertObject(anObject);
+ }
+
+ /**
+ * Returns whether fetching is currently allowed. If false, fetchObjects() will
+ * return null. Default is true.
+ */
+ public boolean isFetchEnabled() {
+ return fetchEnabled;
+ }
+
+ /**
+ * Returns a List of the union of the binding keys for the fetch spec's
+ * qualifier and the auxiliary qualifier.
+ */
+ public NSArray qualifierBindingKeys() {
+ NSSet union = new NSSet();
+ if ((fetchSpecification != null) && (fetchSpecification.qualifier() != null)) {
+ union.addAll(fetchSpecification.qualifier().bindingKeys());
+ }
+ if (auxiliaryQualifier() != null) {
+ union.addAll(auxiliaryQualifier().bindingKeys());
+ }
+ return new NSArray((Collection) union);
+ }
+
+ /**
+ * Returns a Map of the bindings that will be applied against the fetch spec's
+ * qualifier and the auxiliary qualifier, or null if no bindings exist.
+ */
+ public NSDictionary qualifierBindings() {
+ if (qualifierBindings == null)
+ return null;
+ return new NSDictionary((Map) qualifierBindings);
+ }
+
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object.
+ */
+ public void qualifyWithRelationshipKey(String aKey, Object anObject) {
+ throw new WotonomyException("Not implemented yet");
+ }
+
+ /**
+ * Sets the auxiliary qualifier that will be applied to objects returned from
+ * the fetch described by the fetch specification.
+ */
+ public void setAuxiliaryQualifier(EOQualifier aQualifier) {
+ auxiliaryQualifier = aQualifier;
+ }
+
+ /**
+ * Sets whether fetches are currently allowed. If false, fetchObjects() will
+ * return null.
+ */
+ public void setFetchEnabled(boolean isFetchEnabled) {
+ fetchEnabled = isFetchEnabled;
+ }
+
+ /**
+ * Sets the fetch specification used by this data source. If null, all objects
+ * of the specified entity type will be returned by fetchObjects().
+ */
+ public void setFetchSpecification(EOFetchSpecification aFetchSpec) {
+ fetchSpecificationName = null;
+ fetchSpecification = aFetchSpec;
+ }
+
+ /**
+ * Sets the fetch specification used by this data source, requesting it from the
+ * class description for this data source's entity class description, if any. If
+ * the name cannot be resolved, the fetch specification will be set to null.
+ */
+ public void setFetchSpecificationByName(String aName) {
+ fetchSpecificationName = aName;
+ fetchSpecification = EOFetchSpecification.fetchSpecificationNamed(aName, entityName);
+ }
+
+ /*
+ * public void setParentDataSourceRelationshipKey( EODataSource aDataSource,
+ * String aKey)
+ */
+
+ /**
+ * Sets the bindings to be applied to the fetch specification and the auxiliary
+ * qualifier.
+ */
+ public void setQualifierBindings(Map aBindingMap) {
+ if (aBindingMap == null) {
+ qualifierBindings = null;
+ } else {
+ qualifierBindings = new NSDictionary((Map) aBindingMap);
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/24 17:38:00 mpowers
- * Contributing EODatabaseDataSource.
+ * Revision 1.1 2001/11/24 17:38:00 mpowers Contributing EODatabaseDataSource.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODeferredFaulting.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODeferredFaulting.java
index c87a097..6ce9808 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODeferredFaulting.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODeferredFaulting.java
@@ -19,30 +19,26 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EODeferredFaulting defines a method
-* to handle relationships that are deferred faults.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EODeferredFaulting extends EOFaulting
-{
- /**
- * Returns a fault for the specified deferred fault.
- */
- Object willReadRelationship( Object anObject );
+ * EODeferredFaulting defines a method to handle relationships that are deferred
+ * faults.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EODeferredFaulting extends EOFaulting {
+ /**
+ * Returns a fault for the specified deferred fault.
+ */
+ Object willReadRelationship(Object anObject);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserver.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserver.java
index 758fb40..b947a82 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserver.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserver.java
@@ -22,131 +22,108 @@ import java.util.Observable;
import java.util.Observer;
/**
-* This is an abstract class for receiving coalesced
-* notifications of changes from objects.
-* This class also implements Observer for greater
-* compatibility.
-* The point of EODelayedObservers is that when
-* they receive a willChange message, they
-* queue themselves with a EODelayedObserverQueue
-* so they can receive a single subjectChanged()
-* after all changes from an observed object take
-* place.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public abstract class EODelayedObserver
- implements EOObserving, Observer
-{
- /**
- * Notified immediately.
- */
- public static final int ObserverPriorityImmediate = 0;
- public static final int ObserverPriorityFirst = 1;
- public static final int ObserverPrioritySecond = 2;
- public static final int ObserverPriorityThird = 3;
- public static final int ObserverPriorityFourth = 4;
- public static final int ObserverPriorityFifth = 5;
- public static final int ObserverPrioritySixth = 6;
- public static final int ObserverPriorityLater = 7;
- public static final int ObserverNumberOfPriorities = 8;
-
- /**
- * Default constructor.
- */
- public EODelayedObserver ()
- {
- }
-
- /**
- * Removes this observer from the observer queue
- * for a currently pending notification.
- */
- public void discardPendingNotification ()
- {
- observerQueue().dequeueObserver( this );
- }
-
- /**
- * Returns the observer queue to which this observer
- * belongs. This implementation returns the default
- * EODelayedObserverQueue.
- * Override to use a different one.
- */
- public EODelayedObserverQueue observerQueue ()
- {
- return EODelayedObserverQueue.defaultObserverQueue();
- }
-
- /**
- * Returns the priority of this observer in the queue.
- * This implementation returns ObserverPriorityThird.
- * Override to be notified before other observers.
- */
- public int priority ()
- {
- return ObserverPriorityThird;
- }
-
- /**
- * Notifies observer that one or more objects that
- * it is observing have changed. The observer should
- * check all objects it is observing for changes.
- */
- public abstract void subjectChanged ();
-
- // interface EOObserving
-
- /**
- * Called when the specified object is about to change.
- * This implementation puts this observer on a
- * notification queue.
- */
- public void objectWillChange ( Object anObject )
- {
- observerQueue().enqueueObserver( this );
- }
-
- // interface Observer
-
- /**
- * Called when the specified object has changed,
- * with the specified argument.
- * This method is included for interacting with
- * the java.lang.Observer pattern.
- * This implementation simply objectWillChange(anObject)
- * so that the observer still gets a single subjectChanged
- * call in response to multiple changes.
- */
- public void update ( Observable anObject, Object aValue )
- {
- objectWillChange( anObject );
- }
+ * This is an abstract class for receiving coalesced notifications of changes
+ * from objects. This class also implements Observer for greater compatibility.
+ * The point of EODelayedObservers is that when they receive a willChange
+ * message, they queue themselves with a EODelayedObserverQueue so they can
+ * receive a single subjectChanged() after all changes from an observed object
+ * take place.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public abstract class EODelayedObserver implements EOObserving, Observer {
+ /**
+ * Notified immediately.
+ */
+ public static final int ObserverPriorityImmediate = 0;
+ public static final int ObserverPriorityFirst = 1;
+ public static final int ObserverPrioritySecond = 2;
+ public static final int ObserverPriorityThird = 3;
+ public static final int ObserverPriorityFourth = 4;
+ public static final int ObserverPriorityFifth = 5;
+ public static final int ObserverPrioritySixth = 6;
+ public static final int ObserverPriorityLater = 7;
+ public static final int ObserverNumberOfPriorities = 8;
+
+ /**
+ * Default constructor.
+ */
+ public EODelayedObserver() {
+ }
+
+ /**
+ * Removes this observer from the observer queue for a currently pending
+ * notification.
+ */
+ public void discardPendingNotification() {
+ observerQueue().dequeueObserver(this);
+ }
+
+ /**
+ * Returns the observer queue to which this observer belongs. This
+ * implementation returns the default EODelayedObserverQueue. Override to use a
+ * different one.
+ */
+ public EODelayedObserverQueue observerQueue() {
+ return EODelayedObserverQueue.defaultObserverQueue();
+ }
+
+ /**
+ * Returns the priority of this observer in the queue. This implementation
+ * returns ObserverPriorityThird. Override to be notified before other
+ * observers.
+ */
+ public int priority() {
+ return ObserverPriorityThird;
+ }
+
+ /**
+ * Notifies observer that one or more objects that it is observing have changed.
+ * The observer should check all objects it is observing for changes.
+ */
+ public abstract void subjectChanged();
+
+ // interface EOObserving
+
+ /**
+ * Called when the specified object is about to change. This implementation puts
+ * this observer on a notification queue.
+ */
+ public void objectWillChange(Object anObject) {
+ observerQueue().enqueueObserver(this);
+ }
+
+ // interface Observer
+
+ /**
+ * Called when the specified object has changed, with the specified argument.
+ * This method is included for interacting with the java.lang.Observer pattern.
+ * This implementation simply objectWillChange(anObject) so that the observer
+ * still gets a single subjectChanged call in response to multiple changes.
+ */
+ public void update(Observable anObject, Object aValue) {
+ objectWillChange(anObject);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/10/26 18:38:10 mpowers
- * Reordered priorities.
+ * Revision 1.2 2001/10/26 18:38:10 mpowers Reordered priorities.
*
- * Revision 1.1.1.1 2000/12/21 15:46:38 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:38 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
index 6b9b9c3..cea0d9e 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
@@ -26,298 +26,246 @@ import net.wotonomy.foundation.NSRunLoop;
import net.wotonomy.foundation.NSSelector;
/**
-* EODelayedObserverQueue allows EODelayedObservers
-* to receive only one subjectChanged() message
-* after numerous willChange() messages have
-* been sent. Observers are then notified in order
-* of their priority property,
-* so that certain observers can be notified before
-* others for whatever application-specific purpose.
-* This class is not thread-safe and should be used
-* only for single-threaded GUI clients (AWT and Swing).
-* <br><br>
-*
-* Important note: because AWT's event queue does
-* not allow for priority-based scheduling, this
-* class installs a custom event queue, replacing
-* the existing queue on the AWT dispatch thread.
-* We know of no way around this problem.
-* <br><br>
-*
-* Implementation note: this queue relies on the
-* result of equals() for maintaining a set of
-* objects on the queue. If two EODelayedObservers
-* evaluate to the same value using equals(), only
-* one of them will exist on the queue. If this,
-* starts to suck, we can change it.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * EODelayedObserverQueue allows EODelayedObservers to receive only one
+ * subjectChanged() message after numerous willChange() messages have been sent.
+ * Observers are then notified in order of their priority property, so that
+ * certain observers can be notified before others for whatever
+ * application-specific purpose. This class is not thread-safe and should be
+ * used only for single-threaded GUI clients (AWT and Swing). <br>
+ * <br>
+ *
+ * Important note: because AWT's event queue does not allow for priority-based
+ * scheduling, this class installs a custom event queue, replacing the existing
+ * queue on the AWT dispatch thread. We know of no way around this problem. <br>
+ * <br>
+ *
+ * Implementation note: this queue relies on the result of equals() for
+ * maintaining a set of objects on the queue. If two EODelayedObservers evaluate
+ * to the same value using equals(), only one of them will exist on the queue.
+ * If this, starts to suck, we can change it.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
-public class EODelayedObserverQueue
-{
- /**
- * The default run loop ordering flushes the delayed observers
- * up to ObserverPrioritySixth before dispatching the AWT event
- * queue. ObserverPriorityLater is run last.
- */
- public static int FlushDelayedObserversRunLoopOrdering = 400000;
-
- private static EODelayedObserverQueue
- defaultObserverQueue = null;
-
- private static NSSelector runLaterSelector =
- new NSSelector( "flushObserverQueue",
- new Class[] { Object.class } );
+public class EODelayedObserverQueue {
+ /**
+ * The default run loop ordering flushes the delayed observers up to
+ * ObserverPrioritySixth before dispatching the AWT event queue.
+ * ObserverPriorityLater is run last.
+ */
+ public static int FlushDelayedObserversRunLoopOrdering = 400000;
+
+ private static EODelayedObserverQueue defaultObserverQueue = null;
+
+ private static NSSelector runLaterSelector = new NSSelector("flushObserverQueue", new Class[] { Object.class });
private boolean willRunLater;
- private LinkedList priorityQueue;
-
- /**
- * Default constructor.
- */
- public EODelayedObserverQueue ()
- {
+ private LinkedList priorityQueue;
+
+ /**
+ * Default constructor.
+ */
+ public EODelayedObserverQueue() {
willRunLater = false;
- priorityQueue = new LinkedList();
- }
+ priorityQueue = new LinkedList();
+ }
- /**
- * Returns the system default observer queue.
- */
- public static EODelayedObserverQueue defaultObserverQueue ()
- {
- if ( defaultObserverQueue == null )
- {
- defaultObserverQueue = new EODelayedObserverQueue();
+ /**
+ * Returns the system default observer queue.
+ */
+ public static EODelayedObserverQueue defaultObserverQueue() {
+ if (defaultObserverQueue == null) {
+ defaultObserverQueue = new EODelayedObserverQueue();
}
return defaultObserverQueue;
- }
+ }
- /**
- * Removes the specified observer from the queue.
- */
- public void dequeueObserver (
- EODelayedObserver anObserver )
- {
+ /**
+ * Removes the specified observer from the queue.
+ */
+ public void dequeueObserver(EODelayedObserver anObserver) {
//System.out.println( "dequeueObserver: " + anObserver );
- //synchronized ( priorityQueue )
- //{
- priorityQueue.remove( anObserver );
- //}
- }
+ // synchronized ( priorityQueue )
+ // {
+ priorityQueue.remove(anObserver);
+ // }
+ }
- /**
- * Adds the specified observer to the queue.
- * An already enqueued observer will not be
- * added again.
- * If the observer's priority is
- * ObserverPriorityImmediate, it will be
- * notified immediately and not added to the
- * queue.
- * Otherwise, the queue sets itself up to
- * call notifyObserversUpToPriority during the
- * run loop as specified by
- * FlushDelayedObserversRunLoopOrdering.
- */
- public void enqueueObserver (
- EODelayedObserver anObserver )
- {
- // syntactic glue for Runnables
- final EODelayedObserver observer = anObserver;
-
- if ( observer.priority() ==
- EODelayedObserver.ObserverPriorityImmediate )
- {
- // invoke immediately
+ /**
+ * Adds the specified observer to the queue. An already enqueued observer will
+ * not be added again. If the observer's priority is ObserverPriorityImmediate,
+ * it will be notified immediately and not added to the queue. Otherwise, the
+ * queue sets itself up to call notifyObserversUpToPriority during the run loop
+ * as specified by FlushDelayedObserversRunLoopOrdering.
+ */
+ public void enqueueObserver(EODelayedObserver anObserver) {
+ // syntactic glue for Runnables
+ final EODelayedObserver observer = anObserver;
+
+ if (observer.priority() == EODelayedObserver.ObserverPriorityImmediate) {
+ // invoke immediately
observer.subjectChanged();
- }
- else
- {
- // place in the delayed observer queue
-
- //synchronized ( priorityQueue )
- //{
- int i = 0;
- int priority = observer.priority();
- Object o;
+ } else {
+ // place in the delayed observer queue
+
+ // synchronized ( priorityQueue )
+ // {
+ int i = 0;
+ int priority = observer.priority();
+ Object o;
- Iterator iterator = priorityQueue.iterator();
+ Iterator iterator = priorityQueue.iterator();
- // scan entire list to ensure we're not already queued
- while ( iterator.hasNext() )
- {
- o = iterator.next();
- if ( o == observer )
- {
- // already queued
- return;
- }
- if ( ((EODelayedObserver)o).priority() > priority )
- {
- // insert at this index: break now
- break;
- }
- i++;
- }
-
- // if we broke early, we found a threshhold:
- // continue scanning to ensure we're not already queued
- while ( iterator.hasNext() )
- {
- if ( iterator.next() == observer )
- {
- // already queued
- return;
- }
- }
-
- // insert before items of lower priority,
- // otherwise insert at end of list.
- priorityQueue.add( i, observer );
-
- //}
+ // scan entire list to ensure we're not already queued
+ while (iterator.hasNext()) {
+ o = iterator.next();
+ if (o == observer) {
+ // already queued
+ return;
+ }
+ if (((EODelayedObserver) o).priority() > priority) {
+ // insert at this index: break now
+ break;
+ }
+ i++;
+ }
+
+ // if we broke early, we found a threshhold:
+ // continue scanning to ensure we're not already queued
+ while (iterator.hasNext()) {
+ if (iterator.next() == observer) {
+ // already queued
+ return;
+ }
+ }
+
+ // insert before items of lower priority,
+ // otherwise insert at end of list.
+ priorityQueue.add(i, observer);
+
+ // }
runLater();
}
//System.out.println( "enqueueObserver: " + anObserver + " : " + priorityQueue );
- }
+ }
- /**
- * Notifies all observers with priority equal to
- * or greater than the specified priority.
- */
- public void notifyObserversUpToPriority ( int priority )
- {
+ /**
+ * Notifies all observers with priority equal to or greater than the specified
+ * priority.
+ */
+ public void notifyObserversUpToPriority(int priority) {
//System.out.println( "notifyObserversUpToPriority: priorityQueue size = " + priorityQueue.size() );
EODelayedObserver o;
- while ( ! priorityQueue.isEmpty() )
- {
+ while (!priorityQueue.isEmpty()) {
o = (EODelayedObserver) priorityQueue.getFirst();
- if ( o.priority() > priority ) break;
- priorityQueue.removeFirst();
-
- try
- {
- o.subjectChanged();
- }
- catch ( Exception exc )
- {
- System.out.println( "Error notifying observer: " + o );
- exc.printStackTrace();
- }
+ if (o.priority() > priority)
+ break;
+ priorityQueue.removeFirst();
+
+ try {
+ o.subjectChanged();
+ } catch (Exception exc) {
+ System.out.println("Error notifying observer: " + o);
+ exc.printStackTrace();
+ }
}
}
-
+
/**
- * Called to ensure that notifyObserversUpToPriority
- * will be called on the next event loop.
- */
- private void runLater()
- {
- if ( ! willRunLater )
- {
+ * Called to ensure that notifyObserversUpToPriority will be called on the next
+ * event loop.
+ */
+ private void runLater() {
+ if (!willRunLater) {
willRunLater = true;
- NSRunLoop.currentRunLoop().performSelectorWithOrder(
- runLaterSelector, this, null, FlushDelayedObserversRunLoopOrdering, null );
+ NSRunLoop.currentRunLoop().performSelectorWithOrder(runLaterSelector, this, null,
+ FlushDelayedObserversRunLoopOrdering, null);
}
}
-
+
/**
- * This method is called by the event queue run loop
- * and calls notifyObserversUpToPriority with
- * ObserverPriorityLater.
- * NOTE: This method is not part of the specification.
- */
- public void flushObserverQueue( Object anObject )
- {
+ * This method is called by the event queue run loop and calls
+ * notifyObserversUpToPriority with ObserverPriorityLater. NOTE: This method is
+ * not part of the specification.
+ */
+ public void flushObserverQueue(Object anObject) {
//System.out.println( "EODelayedObserverQueue: running" );
- notifyObserversUpToPriority( EODelayedObserver.ObserverPrioritySixth );
- if ( ! priorityQueue.isEmpty() )
- {
- // assumes all remaining on queue are ObserverPriorityLater
- NSRunLoop.invokeLater(
- new PriorityLaterRunnable( new LinkedList( priorityQueue ) ) );
- priorityQueue.clear();
- }
+ notifyObserversUpToPriority(EODelayedObserver.ObserverPrioritySixth);
+ if (!priorityQueue.isEmpty()) {
+ // assumes all remaining on queue are ObserverPriorityLater
+ NSRunLoop.invokeLater(new PriorityLaterRunnable(new LinkedList(priorityQueue)));
+ priorityQueue.clear();
+ }
willRunLater = false;
}
-
- /**
- * A runnable for dispatching remaining observers running at ObserverPriorityLater.
- */
- class PriorityLaterRunnable implements Runnable
- {
- List observers;
-
- public PriorityLaterRunnable( List anObserverList )
- {
- observers = anObserverList;
- }
-
- public void run()
- {
- EODelayedObserver o = null;
- Iterator i = observers.iterator();
- while ( i.hasNext() )
- {
- try
- {
- o = (EODelayedObserver) i.next();
- o.subjectChanged();
- }
- catch ( Exception exc )
- {
- System.out.println( "Error notifying observer: " + o );
- exc.printStackTrace();
- }
- }
- }
- }
-
-}
+
+ /**
+ * A runnable for dispatching remaining observers running at
+ * ObserverPriorityLater.
+ */
+ class PriorityLaterRunnable implements Runnable {
+ List observers;
+
+ public PriorityLaterRunnable(List anObserverList) {
+ observers = anObserverList;
+ }
+
+ public void run() {
+ EODelayedObserver o = null;
+ Iterator i = observers.iterator();
+ while (i.hasNext()) {
+ try {
+ o = (EODelayedObserver) i.next();
+ o.subjectChanged();
+ } catch (Exception exc) {
+ System.out.println("Error notifying observer: " + o);
+ exc.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ * Revision 1.8 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
*
- * Revision 1.7 2002/05/20 15:08:35 mpowers
- * Optimization for enqueueObserver: we were scanning the entire list anyway;
- * now we compare priorities and ensure we're not double-queued on same pass.
+ * Revision 1.7 2002/05/20 15:08:35 mpowers Optimization for enqueueObserver: we
+ * were scanning the entire list anyway; now we compare priorities and ensure
+ * we're not double-queued on same pass.
*
- * Revision 1.6 2002/05/15 13:45:57 mpowers
- * RunLater now appropriately runs later: at the end of the current awt queue.
+ * Revision 1.6 2002/05/15 13:45:57 mpowers RunLater now appropriately runs
+ * later: at the end of the current awt queue.
*
- * Revision 1.5 2002/03/11 03:18:39 mpowers
- * Now properly handling ObserverChangesLater.
+ * Revision 1.5 2002/03/11 03:18:39 mpowers Now properly handling
+ * ObserverChangesLater.
*
- * Revision 1.4 2001/10/26 18:37:15 mpowers
- * Now using NSRunLoop instead of AWT EventQueue.
+ * Revision 1.4 2001/10/26 18:37:15 mpowers Now using NSRunLoop instead of AWT
+ * EventQueue.
*
- * Revision 1.3 2001/10/22 21:54:16 mpowers
- * Removed swing dependency in favor of jdk1.3 event queue.
- * Optimized priority queue population.
+ * Revision 1.3 2001/10/22 21:54:16 mpowers Removed swing dependency in favor of
+ * jdk1.3 event queue. Optimized priority queue population.
*
- * Revision 1.2 2001/10/12 18:01:59 mpowers
- * Now catching exceptions before they disrupt the awt event queue.
+ * Revision 1.2 2001/10/12 18:01:59 mpowers Now catching exceptions before they
+ * disrupt the awt event queue.
*
- * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEditingContext.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEditingContext.java
index b01727d..3a39035 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEditingContext.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEditingContext.java
@@ -42,3206 +42,2593 @@ import net.wotonomy.foundation.internal.WotonomyException;
//import javax.swing.undo.UndoManager;
/**
-* EOEditingContext provides transactional support for
-* fetching, editing, and committing changes made on a
-* collection of objects to a parent object store. <br><br>
-*
-* EOEditingContext is itself a subclass of EOObjectStore,
-* and this means that EOEditingContexts can use other
-* EOEditingContexts as their parent. However, there
-* still must exist an EOObjectStore as the root of the
-* editing hierarchy that can maintain persistent state.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOEditingContext
- extends EOObjectStore
- implements EOObserving
-{
- /**
- * Key for the NSNotification posted after this editing context
- * saves changes. Object of the notification will be this editing
- * context, and user info will contain InsertedKey, UpdatedKey,
- * and DeletedKey (keys are defined in EOObjectStore).
- */
- public static final String
- EditingContextDidSaveChangesNotification =
- "EOEditingContextDidSaveChangesNotification";
-
- /**
- * Key for the NSNotification posted after this editing context
- * observes changes. Object of the notification will be this editing
- * context, and user info will contain InsertedKey, UpdatedKey, InvalidatedKey,
- * and DeletedKey (keys are defined in EOObjectStore), however
- * the objects in the corresponding Lists will be the actual
- * objects, not their ids.
- */
- public static final String
- ObjectsChangedInEditingContextNotification =
- "EOObjectsChangedInEditingContextNotification";
-
- /**
- * The default run loop ordering processes recent changes
- * before delayed observers are notified and before dispatching
- * the AWT event queue.
- */
- public static int
- EditingContextFlushChangesRunLoopOrdering = 300000;
-
- private static NSSelector runLaterSelector =
- new NSSelector( "flushRecentChanges",
- new Class[] { Object.class } );
-
- private static EOObjectStore defaultParentObjectStore = null;
- private static double defaultFetchTimestampLag = 0;
- private static boolean retainsRegisteredObjects = true;
-
- private EOObjectStore parentStore;
- private WeakReference delegate;
- private WeakReference messageHandler;
- private List editorSet;
- private double fetchTimestamp;
- private boolean lockBeforeModify;
- private boolean propagateDeletesAfterEvent;
- private boolean stopValidationAfterError;
- private NSMutableArray insertedObjects;
- private NSMutableArray insertedObjectsBuffer;
- private NSArray insertedObjectsProxy;
- private NSMutableArray updatedObjects;
- private NSMutableArray updatedObjectsBuffer;
- private NSArray updatedObjectsProxy;
- private NSMutableArray deletedObjects;
- private NSMutableArray deletedObjectsBuffer;
- private NSArray deletedObjectsProxy;
- private NSMutableArray deletedIDsBuffer;
- private NSMutableArray invalidatedObjectsBuffer;
- private NSMutableArray invalidatedIDsBuffer;
- private Registrar registrar;
+ * EOEditingContext provides transactional support for fetching, editing, and
+ * committing changes made on a collection of objects to a parent object store.
+ * <br>
+ * <br>
+ *
+ * EOEditingContext is itself a subclass of EOObjectStore, and this means that
+ * EOEditingContexts can use other EOEditingContexts as their parent. However,
+ * there still must exist an EOObjectStore as the root of the editing hierarchy
+ * that can maintain persistent state.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOEditingContext extends EOObjectStore implements EOObserving {
+ /**
+ * Key for the NSNotification posted after this editing context saves changes.
+ * Object of the notification will be this editing context, and user info will
+ * contain InsertedKey, UpdatedKey, and DeletedKey (keys are defined in
+ * EOObjectStore).
+ */
+ public static final String EditingContextDidSaveChangesNotification = "EOEditingContextDidSaveChangesNotification";
+
+ /**
+ * Key for the NSNotification posted after this editing context observes
+ * changes. Object of the notification will be this editing context, and user
+ * info will contain InsertedKey, UpdatedKey, InvalidatedKey, and DeletedKey
+ * (keys are defined in EOObjectStore), however the objects in the corresponding
+ * Lists will be the actual objects, not their ids.
+ */
+ public static final String ObjectsChangedInEditingContextNotification = "EOObjectsChangedInEditingContextNotification";
+
+ /**
+ * The default run loop ordering processes recent changes before delayed
+ * observers are notified and before dispatching the AWT event queue.
+ */
+ public static int EditingContextFlushChangesRunLoopOrdering = 300000;
+
+ private static NSSelector runLaterSelector = new NSSelector("flushRecentChanges", new Class[] { Object.class });
+
+ private static EOObjectStore defaultParentObjectStore = null;
+ private static double defaultFetchTimestampLag = 0;
+ private static boolean retainsRegisteredObjects = true;
+
+ private EOObjectStore parentStore;
+ private WeakReference delegate;
+ private WeakReference messageHandler;
+ private List editorSet;
+ private double fetchTimestamp;
+ private boolean lockBeforeModify;
+ private boolean propagateDeletesAfterEvent;
+ private boolean stopValidationAfterError;
+ private NSMutableArray insertedObjects;
+ private NSMutableArray insertedObjectsBuffer;
+ private NSArray insertedObjectsProxy;
+ private NSMutableArray updatedObjects;
+ private NSMutableArray updatedObjectsBuffer;
+ private NSArray updatedObjectsProxy;
+ private NSMutableArray deletedObjects;
+ private NSMutableArray deletedObjectsBuffer;
+ private NSArray deletedObjectsProxy;
+ private NSMutableArray deletedIDsBuffer;
+ private NSMutableArray invalidatedObjectsBuffer;
+ private NSMutableArray invalidatedIDsBuffer;
+ private Registrar registrar;
// private UndoManager undoManager;
- // so we don't have to trouble EOObserverCenter
- private boolean ignoreChanges;
-
- // for delayed handling of processRecentChanges
- private boolean willRunLater;
-
- // for handling of notifications posted
- // while we're in the saveChanges method
- private boolean isInvalidating;
-
- // for i18n or other customization
- static protected String MessageChangeConflict =
- "Another user changed an object you are editing: ";
-
- /**
- * Default constructor creates a new editing context
- * that uses the default object store. If the default
- * object store has not been set, an exception is thrown.
- */
- public EOEditingContext()
- {
- this( defaultParentObjectStore() );
- }
-
- /**
- * Creates a new editing context that uses the specified
- * object store as its parent object store.
- */
- public EOEditingContext( EOObjectStore anObjectStore )
- {
- if ( anObjectStore == null )
- {
- throw new IllegalArgumentException(
- "A parent object store must be specified." );
- }
-
- parentStore = anObjectStore;
- delegate = null;
- messageHandler = null;
- editorSet = new LinkedList();
- fetchTimestamp = 0;
- lockBeforeModify = false;
- propagateDeletesAfterEvent = true;
- stopValidationAfterError = true;
- insertedObjects = new NSMutableArray();
- insertedObjectsBuffer = new NSMutableArray();
- insertedObjectsProxy = NSArray.arrayBackedByList( insertedObjects );
- updatedObjects = new NSMutableArray();
- updatedObjectsBuffer = new NSMutableArray();
- updatedObjectsProxy = NSArray.arrayBackedByList( updatedObjects );
- deletedObjects = new NSMutableArray();
- deletedObjectsBuffer = new NSMutableArray();
- deletedObjectsProxy = NSArray.arrayBackedByList( deletedObjects );
- deletedIDsBuffer = new NSMutableArray();
- invalidatedObjectsBuffer = new NSMutableArray();
- invalidatedIDsBuffer = new NSMutableArray();
-
- if ( instancesRetainRegisteredObjects() )
- {
- registrar = new Registrar( this );
- }
- else
- {
- registrar = new WeakRegistrar( this );
- }
-
- ignoreChanges = false;
- willRunLater = false;
- isInvalidating = false;
-
- // create undo manager
- //TODO: this should be NSUndoManager
+ // so we don't have to trouble EOObserverCenter
+ private boolean ignoreChanges;
+
+ // for delayed handling of processRecentChanges
+ private boolean willRunLater;
+
+ // for handling of notifications posted
+ // while we're in the saveChanges method
+ private boolean isInvalidating;
+
+ // for i18n or other customization
+ static protected String MessageChangeConflict = "Another user changed an object you are editing: ";
+
+ /**
+ * Default constructor creates a new editing context that uses the default
+ * object store. If the default object store has not been set, an exception is
+ * thrown.
+ */
+ public EOEditingContext() {
+ this(defaultParentObjectStore());
+ }
+
+ /**
+ * Creates a new editing context that uses the specified object store as its
+ * parent object store.
+ */
+ public EOEditingContext(EOObjectStore anObjectStore) {
+ if (anObjectStore == null) {
+ throw new IllegalArgumentException("A parent object store must be specified.");
+ }
+
+ parentStore = anObjectStore;
+ delegate = null;
+ messageHandler = null;
+ editorSet = new LinkedList();
+ fetchTimestamp = 0;
+ lockBeforeModify = false;
+ propagateDeletesAfterEvent = true;
+ stopValidationAfterError = true;
+ insertedObjects = new NSMutableArray();
+ insertedObjectsBuffer = new NSMutableArray();
+ insertedObjectsProxy = NSArray.arrayBackedByList(insertedObjects);
+ updatedObjects = new NSMutableArray();
+ updatedObjectsBuffer = new NSMutableArray();
+ updatedObjectsProxy = NSArray.arrayBackedByList(updatedObjects);
+ deletedObjects = new NSMutableArray();
+ deletedObjectsBuffer = new NSMutableArray();
+ deletedObjectsProxy = NSArray.arrayBackedByList(deletedObjects);
+ deletedIDsBuffer = new NSMutableArray();
+ invalidatedObjectsBuffer = new NSMutableArray();
+ invalidatedIDsBuffer = new NSMutableArray();
+
+ if (instancesRetainRegisteredObjects()) {
+ registrar = new Registrar(this);
+ } else {
+ registrar = new WeakRegistrar(this);
+ }
+
+ ignoreChanges = false;
+ willRunLater = false;
+ isInvalidating = false;
+
+ // create undo manager
+ // TODO: this should be NSUndoManager
// undoManager = new UndoManager();
- // register for notifications
- NSSelector handleNotification =
- new NSSelector( "handleNotification",
- new Class[] { NSNotification.class } );
- // any from parent store
- NSNotificationCenter.defaultCenter().addObserver(
- this, handleNotification, null, parentStore );
- // global id change from any
- NSNotificationCenter.defaultCenter().addObserver(
- this, handleNotification, EOGlobalID.GlobalIDChangedNotification, null );
+ // register for notifications
+ NSSelector handleNotification = new NSSelector("handleNotification", new Class[] { NSNotification.class });
+ // any from parent store
+ NSNotificationCenter.defaultCenter().addObserver(this, handleNotification, null, parentStore);
+ // global id change from any
+ NSNotificationCenter.defaultCenter().addObserver(this, handleNotification,
+ EOGlobalID.GlobalIDChangedNotification, null);
//new net.wotonomy.ui.swing.NotificationInspector( null, parentStore );
- }
-
- /**
- * Registers the specified object as an editor for this
- * context. The object is expected to implement
- * EOEditingContext.Editor.
- */
- public void addEditor ( Object anEditor )
- {
- if ( anEditor == null ) return;
- editorSet.add( new WeakReference( anEditor ) );
- }
-
- /**
- * Returns a read-only List of objects associated with the object
- * with the specified id for the specified property
- * relationship, or may return a placeholder array that
- * will defer the fetch until needed (aka an array fault).
- * All objects must be registered in the specified editing context.
- * This implementation calls to its parent object store's
- * implementation if the requested source object is not
- * registered in this editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public NSArray arrayFaultWithSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationshipKey,
- EOEditingContext aContext )
- {
- NSArray result = null;
- Object source = registrar.objectForGlobalID( aGlobalID );
-
- // if not registered in our context
- if ( source == null )
- {
- // get the object registered into our context
- result = parentStore.arrayFaultWithSourceGlobalID(
- aGlobalID, aRelationshipKey, this );
- }
- else // source is registered in our context
- {
- // get existing value
- Object value;
- if ( source instanceof EOKeyValueCoding )
- {
- value = ((EOKeyValueCoding)source).storedValueForKey(
- aRelationshipKey );
- }
- else // handle directly
- {
- value = EOKeyValueCodingSupport.storedValueForKey(
- source, aRelationshipKey );
- }
-
- if ( value == null )
- {
- // do the same as if the source was null
- result = parentStore.arrayFaultWithSourceGlobalID(
- aGlobalID, aRelationshipKey, this );
- }
- else
- if ( value instanceof NSArray )
- {
- result = (NSArray) value;
- }
- else // not NSArray
- if ( value instanceof Collection )
- {
- // convert to NSArray
- result = new NSArray( (Collection) value );
- }
- else
- {
- throw new WotonomyException(
- "Relationship key did not return a collection: "
- + aGlobalID + " : " + aRelationshipKey );
- }
- }
-
- // if our context is not the specified context
- if ( aContext != this )
- {
- result = (NSArray) clone( this, result, aContext );
- }
-
- return result;
- }
-
- /**
- * Returns a snapshot of the specified object as it
- * existed when it was last read or committed to the
- * parent object store.
- */
- public NSDictionary committedSnapshotForObject (
- Object anObject )
- {
- byte[] snapshot = (byte[])
- registrar.getCommitSnapshot( anObject );
- if ( snapshot == null )
- {
- // this object not modified: take a current snapshot
- snapshot = takeSnapshot( anObject );
- }
- return convertSnapshotToDictionary( snapshot );
- }
-
- /**
- * Returns a snapshot of the specified object as it
- * existed before the edits triggered by the current
- * event loop were processed.
- */
- public NSDictionary currentEventSnapshotForObject (
- Object anObject )
- {
- byte[] result = (byte[])
- registrar.getCurrentSnapshot( anObject );
- if ( result == null )
- {
- return committedSnapshotForObject( anObject );
- }
- return convertSnapshotToDictionary( result );
- }
-
- /**
- * Returns the delegate for this editing context,
- * or null if no delegate has been set.
- */
- public Object delegate ()
- {
- if ( delegate == null ) return null;
- return delegate.get();
- }
-
- /**
- * Deletes the specified object from this editing context.
- * The editing context marks the object as deleted and
- * will notify the parent store when changes are committed.
- */
- public void deleteObject (
- Object anObject )
- {
- willChange();
+ }
+
+ /**
+ * Registers the specified object as an editor for this context. The object is
+ * expected to implement EOEditingContext.Editor.
+ */
+ public void addEditor(Object anEditor) {
+ if (anEditor == null)
+ return;
+ editorSet.add(new WeakReference(anEditor));
+ }
+
+ /**
+ * Returns a read-only List of objects associated with the object with the
+ * specified id for the specified property relationship, or may return a
+ * placeholder array that will defer the fetch until needed (aka an array
+ * fault). All objects must be registered in the specified editing context. This
+ * implementation calls to its parent object store's implementation if the
+ * requested source object is not registered in this editing context. The
+ * specified relationship key must produce a result of type Collection for the
+ * source object or an exception is thrown.
+ */
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationshipKey,
+ EOEditingContext aContext) {
+ NSArray result = null;
+ Object source = registrar.objectForGlobalID(aGlobalID);
+
+ // if not registered in our context
+ if (source == null) {
+ // get the object registered into our context
+ result = parentStore.arrayFaultWithSourceGlobalID(aGlobalID, aRelationshipKey, this);
+ } else // source is registered in our context
+ {
+ // get existing value
+ Object value;
+ if (source instanceof EOKeyValueCoding) {
+ value = ((EOKeyValueCoding) source).storedValueForKey(aRelationshipKey);
+ } else // handle directly
+ {
+ value = EOKeyValueCodingSupport.storedValueForKey(source, aRelationshipKey);
+ }
+
+ if (value == null) {
+ // do the same as if the source was null
+ result = parentStore.arrayFaultWithSourceGlobalID(aGlobalID, aRelationshipKey, this);
+ } else if (value instanceof NSArray) {
+ result = (NSArray) value;
+ } else // not NSArray
+ if (value instanceof Collection) {
+ // convert to NSArray
+ result = new NSArray((Collection) value);
+ } else {
+ throw new WotonomyException(
+ "Relationship key did not return a collection: " + aGlobalID + " : " + aRelationshipKey);
+ }
+ }
+
+ // if our context is not the specified context
+ if (aContext != this) {
+ result = (NSArray) clone(this, result, aContext);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a snapshot of the specified object as it existed when it was last
+ * read or committed to the parent object store.
+ */
+ public NSDictionary committedSnapshotForObject(Object anObject) {
+ byte[] snapshot = (byte[]) registrar.getCommitSnapshot(anObject);
+ if (snapshot == null) {
+ // this object not modified: take a current snapshot
+ snapshot = takeSnapshot(anObject);
+ }
+ return convertSnapshotToDictionary(snapshot);
+ }
+
+ /**
+ * Returns a snapshot of the specified object as it existed before the edits
+ * triggered by the current event loop were processed.
+ */
+ public NSDictionary currentEventSnapshotForObject(Object anObject) {
+ byte[] result = (byte[]) registrar.getCurrentSnapshot(anObject);
+ if (result == null) {
+ return committedSnapshotForObject(anObject);
+ }
+ return convertSnapshotToDictionary(result);
+ }
+
+ /**
+ * Returns the delegate for this editing context, or null if no delegate has
+ * been set.
+ */
+ public Object delegate() {
+ if (delegate == null)
+ return null;
+ return delegate.get();
+ }
+
+ /**
+ * Deletes the specified object from this editing context. The editing context
+ * marks the object as deleted and will notify the parent store when changes are
+ * committed.
+ */
+ public void deleteObject(Object anObject) {
+ willChange();
int i;
// remove from added objects if necessary
- i = insertedObjects.indexOfIdenticalObject( anObject );
- if ( i != NSArray.NotFound )
+ i = insertedObjects.indexOfIdenticalObject(anObject);
+ if (i != NSArray.NotFound) {
+ insertedObjects.removeObjectAtIndex(i);
+
+ // if in the inserted objects buffer
+ int index = insertedObjectsBuffer.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ // remove from inserted objects buffer
+ insertedObjectsBuffer.removeObjectAtIndex(index);
+ }
+
+ // now forget the object ever existed.
+ forgetObject(anObject);
+
+ // we're done
+ return;
+ } else // otherwise add to deleted objects list
{
- insertedObjects.removeObjectAtIndex( i );
-
- // if in the inserted objects buffer
- int index = insertedObjectsBuffer.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- // remove from inserted objects buffer
- insertedObjectsBuffer.removeObjectAtIndex( index );
- }
-
- // now forget the object ever existed.
- forgetObject( anObject );
-
- // we're done
- return;
- }
- else // otherwise add to deleted objects list
- {
- deletedObjects.addObject( anObject );
+ deletedObjects.addObject(anObject);
}
-
+
// remove from updated objects if necessary
- i = updatedObjects.indexOfIdenticalObject( anObject );
- if ( i != NSArray.NotFound )
- {
- updatedObjects.removeObjectAtIndex( i );
- }
-
- // add to buffer
- deletedObjectsBuffer.addObject( anObject );
- deletedIDsBuffer.addObject( globalIDForObject( anObject ) );
- }
-
- /**
- * Returns a read-only List of all objects marked as deleted
- * in this editing context.
- */
- public NSArray deletedObjects ()
- {
- return deletedObjectsProxy;
- }
-
- /**
- * Called by child editing contexts when they no longer
- * need to track the specified id.
- * This implementation forwards the call to the parent store.
- */
- public void editingContextDidForgetObjectWithGlobalID (
- EOEditingContext aContext,
- EOGlobalID aGlobalID )
- {
- parentStore.editingContextDidForgetObjectWithGlobalID(
- aContext, aGlobalID );
- }
-
- /**
- * Returns a read-only List of registered editors of this
- * editing context.
- */
- public NSArray editors ()
- {
- NSMutableArray result = new NSMutableArray();
- Object o;
- Iterator i = editorSet.iterator();
- while ( i.hasNext() )
- {
- o = ((WeakReference)i.next()).get();
- if ( o != null )
- {
- result.addObject( o );
- }
- else
- {
- i.remove();
- }
- }
- return result;
- }
-
-/*
- public static void encodeObjectWithCoder (
- Object anObject,
- NSCoder aCoder )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
+ i = updatedObjects.indexOfIdenticalObject(anObject);
+ if (i != NSArray.NotFound) {
+ updatedObjects.removeObjectAtIndex(i);
+ }
- /**
- * Returns the object for the specified id.
- * If the object is registered in in this context
- * but not in the specified context,
- * this implementation will create a copy of the object
- * and register it in the specified context.
- * Otherwise it will forward the call to the parent
- * object store.
- */
- public /*EOEnterpriseObject*/ Object faultForGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- Object result = registrar.objectForGlobalID( aGlobalID );
-
- // if not registered in our context
- if ( result == null )
- {
- // get the object registered into our context
- result = parentStore.faultForGlobalID( aGlobalID, this );
- }
-
- // if our context is not the specified context
- if ( aContext != this )
- {
- result = registerClone( aGlobalID, this, result, aContext );
- }
-
- return result;
- }
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary.
- * This implementation calls faultForRawRow
- * on the parent store.
- */
- public Object faultForRawRow (
- Map aDictionary,
- String anEntityName )
- {
- return parentStore.faultForRawRow(
- aDictionary, anEntityName, this );
- }
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary. The fault should
- * belong to the specified editing context.
- * This implementation forwards the call to
- * the parent store.
- */
- public /*EOEnterpriseObject*/ Object faultForRawRow (
- Map aDictionary,
- String anEntityName,
- EOEditingContext aContext )
- {
- return parentStore.faultForRawRow(
- aDictionary, anEntityName, aContext );
- }
-
- /**
- * Returns the fetch timestamp for this editing context.
- */
- public double fetchTimestamp ()
- {
- return fetchTimestamp;
- }
-
- /**
- * Unregisters the specified object from this editing context,
- * removing all references to it. Use this method to remove
- * an object from the context without marking it for deletion.
- */
- public void forgetObject (
- Object anObject )
- {
- EOGlobalID id = registrar.globalIDForObject( anObject );
- if ( id == null )
- {
- System.err.println(
- "EOEditingContext.forgetObject: not registered: " + anObject );
- return;
- }
-
- // unregister object
- registrar.forgetObject( anObject );
-
- // remove from all, inserted, updated, and deleted lists
- int index;
- index = updatedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- updatedObjects.removeObjectAtIndex( index );
- }
- index = insertedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- insertedObjects.removeObjectAtIndex( index );
- return;
- }
- index = deletedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- deletedObjects.removeObjectAtIndex( index );
- return;
- }
-
- // notify parent context
- parentStore.editingContextDidForgetObjectWithGlobalID( this, id );
- }
-
- /**
- * Returns the id for the specified object, or null
- * if the object is not registered in this context.
- */
- public EOGlobalID globalIDForObject (
- Object anObject )
- {
- return registrar.globalIDForObject( anObject );
- }
-
- /**
- * Returns an array of ids for an array of objects.
- */
- private NSArray globalIDsForObjects(
- List anObjectList )
- {
- NSMutableArray result = new NSMutableArray();
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- result.add( globalIDForObject( it.next() ) );
- }
- return result;
- }
-
- /**
- * Returns whether this editing context has changes that
- * have not yet been committed to the parent object store.
- */
- public boolean hasChanges ()
- {
- if ( updatedObjects.count() > 0 ) return true;
- if ( insertedObjects.count() > 0 ) return true;
- if ( deletedObjects.count() > 0 ) return true;
- return false;
- }
-
- /**
- * Given a newly instantiated object, this method
- * initializes its properties to values appropriate
- * for the specified id. The object should already
- * belong to the specified editing context.
- * This method is called to populate faults.
- * This implementation will try to apply the values
- * from an object with a matching id in this editing
- * context if possible, calling to the parent object
- * store only if such an object is not found.
- */
- public void initializeObject (
- /*EOEnterpriseObject*/ Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- Object existingObject = registrar.objectForGlobalID( aGlobalID );
-
- // if not registered in our context
- if ( existingObject == null )
- {
- // get the object registered into our context
- existingObject = parentStore.faultForGlobalID( aGlobalID, this );
- }
-
- if ( aContext == this )
- {
- // initialize the object
- parentStore.initializeObject(
- /*(EOEnterpriseObject)*/existingObject, aGlobalID, this );
- }
- else // ( aContext != this )
- {
- // translates child relationships
- copy( this, existingObject, aContext, anObject );
- }
-
- aContext.registrar.setCommitSnapshot( anObject, null );
- aContext.registrar.setCurrentSnapshot( anObject, null );
- }
-
- /**
- * Inserts the specified object into this editing context.
- * This implementation calls insertObjectWithGlobalID
- * with an EOTemporaryGlobalID.
- */
- public void insertObject ( Object anObject )
- {
- insertObjectWithGlobalID(
- anObject, new EOTemporaryGlobalID() );
- }
-
- /**
- * Inserts the specified object into this editing context
- * with the specified id, which is expected to be a
- * temporary id.
- */
- public void insertObjectWithGlobalID (
- Object anObject,
- EOGlobalID aGlobalID )
- {
- willChange();
-
- // if this object was marked for deletion
- int index = deletedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- // don't need to re-register: just update the lists
-
- // remove from deleted list
- deletedObjects.removeObjectAtIndex( index );
-
- // if in the deleted ids buffer
- index = deletedIDsBuffer.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- // remove from deleted ids buffer
- deletedIDsBuffer.removeObjectAtIndex( index );
- }
-
- // if in the deleted objects buffer
- index = deletedObjectsBuffer.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound )
- {
- // remove from deleted objects buffer
- deletedObjectsBuffer.removeObjectAtIndex( index );
- }
- else // not in the deleted objects buffer
- {
- // add to the inserted objects buffer
- insertedObjectsBuffer.addObject( anObject );
- }
-
- // we're done
- return;
- }
-
- // make sure object is not already in editing context
- if ( objectForGlobalID( aGlobalID ) != null )
- {
- throw new WotonomyException(
- "Tried to insert but object was already registered:"
- + aGlobalID );
- }
-
- // register object
- recordObject( anObject, aGlobalID );
-
- // add to inserted list
- insertedObjects.addObject( anObject );
- // add to buffer
- insertedObjectsBuffer.addObject( anObject );
- }
-
- /**
- * Returns a read-only List of the objects that have been
- * inserted into this editing context.
- */
- public NSArray insertedObjects ()
- {
- return insertedObjectsProxy;
- }
-
- /**
- * Turn all objects in this editing context into faults,
- * so that they will be fetched the next time they are
- * accessed, and calls invalidateObjectsWithGlobalIDs
- * on the parent object store.
- */
- public void invalidateAllObjects ()
- {
- // register change so processRecentChanges is called
- willChange();
-
- invalidateAllObjectsQuietly();
-
- // post notification
- NSNotificationCenter.defaultCenter().postNotification(
- new NSNotification(
- InvalidatedAllObjectsInStoreNotification, this ) );
- }
-
- /**
- * Only refaults all objects, does not notify will change
- * nor post notification, but does call parent store.
- * Called by invalidateAllObjects() and handleNotification().
- */
- private void invalidateAllObjectsQuietly()
- {
- // remember the ids
- NSMutableArray ids = new NSMutableArray( registrar.registeredGlobalIDs() );
-
- // track of discarded IDs (from inserted objects)
- NSMutableArray discardedIDs = new NSMutableArray();
-
- // refault all objects
- EOGlobalID id;
- Object o;
- Enumeration e = ids.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- id = (EOGlobalID) e.nextElement();
- o = objectForGlobalID( id );
-
- // some objects may have been manually discarded
- if ( o != null )
- {
- // don't refault newly inserted objects
- if ( insertedObjects.indexOfIdenticalObject( o ) == NSArray.NotFound )
- {
- refaultObject( o, id, this );
- }
- else
- {
- // discard inserted objects
- forgetObject( o );
- discardedIDs.add( id );
- }
- invalidatedObjectsBuffer.add( o );
- }
- invalidatedIDsBuffer.add( id );
- }
- ids.removeAll( discardedIDs );
-
- // call to parent store (should call this after posting instead?)
- isInvalidating = true;
- parentStore.invalidateObjectsWithGlobalIDs( ids );
- isInvalidating = false;
- }
-
- /**
- * Turns the objects with the specified ids into faults,
- * so that they will be fetched the next time they are
- * accessed, and forwards the call to the parent object store.
- */
- public void invalidateObjectsWithGlobalIDs (
- List anArray )
- {
- // register change so processRecentChanges is called
- willChange();
-
- // call to parent to invalidate objects
- parentStore.invalidateObjectsWithGlobalIDs( anArray );
-
- Object o;
- EOGlobalID id;
- Iterator it = anArray.iterator();
- while ( it.hasNext() )
- {
- id = (EOGlobalID) it.next();
- if ( id != null )
- {
- o = objectForGlobalID( id );
- if ( o != null )
- {
- Object result = notifyDelegate(
- "editingContextShouldInvalidateObject",
- new Class[] { EOEditingContext.class, Object.class, EOGlobalID.class },
- new Object[] { this, o, id } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- // refault the object
- refaultObject( o, id, this );
- invalidatedObjectsBuffer.add( o );
- invalidatedIDsBuffer.add( id );
- }
- }
- }
- else
- {
- throw new WotonomyException(
- "Attempted to invalidate a null global id: " + anArray );
- }
- }
-
- }
-/*
- public boolean invalidatesObjectsWhenFinalized ( )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-
- public boolean invalidatesObjectsWhenFreed ( )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Returns whether the object referenced by the
- * specified id is locked.
- * This implementation simply forwards the call to
- * the parent object store.
- */
- public boolean isObjectLockedWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext)
- {
- return parentStore.isObjectLockedWithGlobalID(
- aGlobalID, aContext );
- }
-
-/*
- public void lock ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Locks the specified object in this editing context
- * by calling lockObjectWithGlobalID on the parent store.
- */
- public void lockObject (
- Object anObject )
- {
- parentStore.lockObjectWithGlobalID(
- globalIDForObject( anObject ), this );
- }
-
- /**
- * Locks the object referenced by the specified id
- * in the specified editing context.
- * This implementation simply forwards the call to
- * the parent object store.
- */
- public void lockObjectWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext)
- {
- parentStore.lockObjectWithGlobalID(
- aGlobalID, aContext );
- }
-
- /**
- * Returns whether this editing context attempts to
- * lock objects when they are first modified.
- */
- public boolean locksObjectsBeforeFirstModification ()
- {
- return lockBeforeModify;
- }
-
- /**
- * Returns the message handler for this editing context,
- * or null if no message handler has been set.
- */
- public Object messageHandler ()
- {
- if ( messageHandler == null ) return null;
- return messageHandler.get();
- }
-
- /**
- * Returns the object registered in this editing context
- * for the specified id, or null if that id is not
- * registered.
- */
- public Object objectForGlobalID (
- EOGlobalID aGlobalID )
- {
- return registrar.objectForGlobalID( aGlobalID );
- }
-
- /**
- * Returns a read-only List of objects associated with the object
- * with the specified id for the specified property
- * relationship. This method may not return an array fault
- * because array faults call this method to fetch on demand.
- * All objects must be registered the specified editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public NSArray objectsForSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationshipKey,
- EOEditingContext aContext )
- {
+ // add to buffer
+ deletedObjectsBuffer.addObject(anObject);
+ deletedIDsBuffer.addObject(globalIDForObject(anObject));
+ }
+
+ /**
+ * Returns a read-only List of all objects marked as deleted in this editing
+ * context.
+ */
+ public NSArray deletedObjects() {
+ return deletedObjectsProxy;
+ }
+
+ /**
+ * Called by child editing contexts when they no longer need to track the
+ * specified id. This implementation forwards the call to the parent store.
+ */
+ public void editingContextDidForgetObjectWithGlobalID(EOEditingContext aContext, EOGlobalID aGlobalID) {
+ parentStore.editingContextDidForgetObjectWithGlobalID(aContext, aGlobalID);
+ }
+
+ /**
+ * Returns a read-only List of registered editors of this editing context.
+ */
+ public NSArray editors() {
+ NSMutableArray result = new NSMutableArray();
+ Object o;
+ Iterator i = editorSet.iterator();
+ while (i.hasNext()) {
+ o = ((WeakReference) i.next()).get();
+ if (o != null) {
+ result.addObject(o);
+ } else {
+ i.remove();
+ }
+ }
+ return result;
+ }
+
+ /*
+ * public static void encodeObjectWithCoder ( Object anObject, NSCoder aCoder )
+ * { throw new net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+
+ /**
+ * Returns the object for the specified id. If the object is registered in in
+ * this context but not in the specified context, this implementation will
+ * create a copy of the object and register it in the specified context.
+ * Otherwise it will forward the call to the parent object store.
+ */
+ public /* EOEnterpriseObject */ Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ Object result = registrar.objectForGlobalID(aGlobalID);
+
+ // if not registered in our context
+ if (result == null) {
+ // get the object registered into our context
+ result = parentStore.faultForGlobalID(aGlobalID, this);
+ }
+
+ // if our context is not the specified context
+ if (aContext != this) {
+ result = registerClone(aGlobalID, this, result, aContext);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. This implementation calls
+ * faultForRawRow on the parent store.
+ */
+ public Object faultForRawRow(Map aDictionary, String anEntityName) {
+ return parentStore.faultForRawRow(aDictionary, anEntityName, this);
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. The fault should belong to the
+ * specified editing context. This implementation forwards the call to the
+ * parent store.
+ */
+ public /* EOEnterpriseObject */ Object faultForRawRow(Map aDictionary, String anEntityName,
+ EOEditingContext aContext) {
+ return parentStore.faultForRawRow(aDictionary, anEntityName, aContext);
+ }
+
+ /**
+ * Returns the fetch timestamp for this editing context.
+ */
+ public double fetchTimestamp() {
+ return fetchTimestamp;
+ }
+
+ /**
+ * Unregisters the specified object from this editing context, removing all
+ * references to it. Use this method to remove an object from the context
+ * without marking it for deletion.
+ */
+ public void forgetObject(Object anObject) {
+ EOGlobalID id = registrar.globalIDForObject(anObject);
+ if (id == null) {
+ System.err.println("EOEditingContext.forgetObject: not registered: " + anObject);
+ return;
+ }
+
+ // unregister object
+ registrar.forgetObject(anObject);
+
+ // remove from all, inserted, updated, and deleted lists
+ int index;
+ index = updatedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ updatedObjects.removeObjectAtIndex(index);
+ }
+ index = insertedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ insertedObjects.removeObjectAtIndex(index);
+ return;
+ }
+ index = deletedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ deletedObjects.removeObjectAtIndex(index);
+ return;
+ }
+
+ // notify parent context
+ parentStore.editingContextDidForgetObjectWithGlobalID(this, id);
+ }
+
+ /**
+ * Returns the id for the specified object, or null if the object is not
+ * registered in this context.
+ */
+ public EOGlobalID globalIDForObject(Object anObject) {
+ return registrar.globalIDForObject(anObject);
+ }
+
+ /**
+ * Returns an array of ids for an array of objects.
+ */
+ private NSArray globalIDsForObjects(List anObjectList) {
+ NSMutableArray result = new NSMutableArray();
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ result.add(globalIDForObject(it.next()));
+ }
+ return result;
+ }
+
+ /**
+ * Returns whether this editing context has changes that have not yet been
+ * committed to the parent object store.
+ */
+ public boolean hasChanges() {
+ if (updatedObjects.count() > 0)
+ return true;
+ if (insertedObjects.count() > 0)
+ return true;
+ if (deletedObjects.count() > 0)
+ return true;
+ return false;
+ }
+
+ /**
+ * Given a newly instantiated object, this method initializes its properties to
+ * values appropriate for the specified id. The object should already belong to
+ * the specified editing context. This method is called to populate faults. This
+ * implementation will try to apply the values from an object with a matching id
+ * in this editing context if possible, calling to the parent object store only
+ * if such an object is not found.
+ */
+ public void initializeObject(/* EOEnterpriseObject */ Object anObject, EOGlobalID aGlobalID,
+ EOEditingContext aContext) {
+ Object existingObject = registrar.objectForGlobalID(aGlobalID);
+
+ // if not registered in our context
+ if (existingObject == null) {
+ // get the object registered into our context
+ existingObject = parentStore.faultForGlobalID(aGlobalID, this);
+ }
+
+ if (aContext == this) {
+ // initialize the object
+ parentStore.initializeObject(/* (EOEnterpriseObject) */existingObject, aGlobalID, this);
+ } else // ( aContext != this )
+ {
+ // translates child relationships
+ copy(this, existingObject, aContext, anObject);
+ }
+
+ aContext.registrar.setCommitSnapshot(anObject, null);
+ aContext.registrar.setCurrentSnapshot(anObject, null);
+ }
+
+ /**
+ * Inserts the specified object into this editing context. This implementation
+ * calls insertObjectWithGlobalID with an EOTemporaryGlobalID.
+ */
+ public void insertObject(Object anObject) {
+ insertObjectWithGlobalID(anObject, new EOTemporaryGlobalID());
+ }
+
+ /**
+ * Inserts the specified object into this editing context with the specified id,
+ * which is expected to be a temporary id.
+ */
+ public void insertObjectWithGlobalID(Object anObject, EOGlobalID aGlobalID) {
+ willChange();
+
+ // if this object was marked for deletion
+ int index = deletedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ // don't need to re-register: just update the lists
+
+ // remove from deleted list
+ deletedObjects.removeObjectAtIndex(index);
+
+ // if in the deleted ids buffer
+ index = deletedIDsBuffer.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ // remove from deleted ids buffer
+ deletedIDsBuffer.removeObjectAtIndex(index);
+ }
+
+ // if in the deleted objects buffer
+ index = deletedObjectsBuffer.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound) {
+ // remove from deleted objects buffer
+ deletedObjectsBuffer.removeObjectAtIndex(index);
+ } else // not in the deleted objects buffer
+ {
+ // add to the inserted objects buffer
+ insertedObjectsBuffer.addObject(anObject);
+ }
+
+ // we're done
+ return;
+ }
+
+ // make sure object is not already in editing context
+ if (objectForGlobalID(aGlobalID) != null) {
+ throw new WotonomyException("Tried to insert but object was already registered:" + aGlobalID);
+ }
+
+ // register object
+ recordObject(anObject, aGlobalID);
+
+ // add to inserted list
+ insertedObjects.addObject(anObject);
+ // add to buffer
+ insertedObjectsBuffer.addObject(anObject);
+ }
+
+ /**
+ * Returns a read-only List of the objects that have been inserted into this
+ * editing context.
+ */
+ public NSArray insertedObjects() {
+ return insertedObjectsProxy;
+ }
+
+ /**
+ * Turn all objects in this editing context into faults, so that they will be
+ * fetched the next time they are accessed, and calls
+ * invalidateObjectsWithGlobalIDs on the parent object store.
+ */
+ public void invalidateAllObjects() {
+ // register change so processRecentChanges is called
+ willChange();
+
+ invalidateAllObjectsQuietly();
+
+ // post notification
+ NSNotificationCenter.defaultCenter()
+ .postNotification(new NSNotification(InvalidatedAllObjectsInStoreNotification, this));
+ }
+
+ /**
+ * Only refaults all objects, does not notify will change nor post notification,
+ * but does call parent store. Called by invalidateAllObjects() and
+ * handleNotification().
+ */
+ private void invalidateAllObjectsQuietly() {
+ // remember the ids
+ NSMutableArray ids = new NSMutableArray(registrar.registeredGlobalIDs());
+
+ // track of discarded IDs (from inserted objects)
+ NSMutableArray discardedIDs = new NSMutableArray();
+
+ // refault all objects
+ EOGlobalID id;
+ Object o;
+ Enumeration e = ids.objectEnumerator();
+ while (e.hasMoreElements()) {
+ id = (EOGlobalID) e.nextElement();
+ o = objectForGlobalID(id);
+
+ // some objects may have been manually discarded
+ if (o != null) {
+ // don't refault newly inserted objects
+ if (insertedObjects.indexOfIdenticalObject(o) == NSArray.NotFound) {
+ refaultObject(o, id, this);
+ } else {
+ // discard inserted objects
+ forgetObject(o);
+ discardedIDs.add(id);
+ }
+ invalidatedObjectsBuffer.add(o);
+ }
+ invalidatedIDsBuffer.add(id);
+ }
+ ids.removeAll(discardedIDs);
+
+ // call to parent store (should call this after posting instead?)
+ isInvalidating = true;
+ parentStore.invalidateObjectsWithGlobalIDs(ids);
+ isInvalidating = false;
+ }
+
+ /**
+ * Turns the objects with the specified ids into faults, so that they will be
+ * fetched the next time they are accessed, and forwards the call to the parent
+ * object store.
+ */
+ public void invalidateObjectsWithGlobalIDs(List anArray) {
+ // register change so processRecentChanges is called
+ willChange();
+
+ // call to parent to invalidate objects
+ parentStore.invalidateObjectsWithGlobalIDs(anArray);
+
+ Object o;
+ EOGlobalID id;
+ Iterator it = anArray.iterator();
+ while (it.hasNext()) {
+ id = (EOGlobalID) it.next();
+ if (id != null) {
+ o = objectForGlobalID(id);
+ if (o != null) {
+ Object result = notifyDelegate("editingContextShouldInvalidateObject",
+ new Class[] { EOEditingContext.class, Object.class, EOGlobalID.class },
+ new Object[] { this, o, id });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ // refault the object
+ refaultObject(o, id, this);
+ invalidatedObjectsBuffer.add(o);
+ invalidatedIDsBuffer.add(id);
+ }
+ }
+ } else {
+ throw new WotonomyException("Attempted to invalidate a null global id: " + anArray);
+ }
+ }
+
+ }
+
+ /*
+ * public boolean invalidatesObjectsWhenFinalized ( ) { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ *
+ * public boolean invalidatesObjectsWhenFreed ( ) { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * Returns whether the object referenced by the specified id is locked. This
+ * implementation simply forwards the call to the parent object store.
+ */
+ public boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ return parentStore.isObjectLockedWithGlobalID(aGlobalID, aContext);
+ }
+
+ /*
+ * public void lock () { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * Locks the specified object in this editing context by calling
+ * lockObjectWithGlobalID on the parent store.
+ */
+ public void lockObject(Object anObject) {
+ parentStore.lockObjectWithGlobalID(globalIDForObject(anObject), this);
+ }
+
+ /**
+ * Locks the object referenced by the specified id in the specified editing
+ * context. This implementation simply forwards the call to the parent object
+ * store.
+ */
+ public void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ parentStore.lockObjectWithGlobalID(aGlobalID, aContext);
+ }
+
+ /**
+ * Returns whether this editing context attempts to lock objects when they are
+ * first modified.
+ */
+ public boolean locksObjectsBeforeFirstModification() {
+ return lockBeforeModify;
+ }
+
+ /**
+ * Returns the message handler for this editing context, or null if no message
+ * handler has been set.
+ */
+ public Object messageHandler() {
+ if (messageHandler == null)
+ return null;
+ return messageHandler.get();
+ }
+
+ /**
+ * Returns the object registered in this editing context for the specified id,
+ * or null if that id is not registered.
+ */
+ public Object objectForGlobalID(EOGlobalID aGlobalID) {
+ return registrar.objectForGlobalID(aGlobalID);
+ }
+
+ /**
+ * Returns a read-only List of objects associated with the object with the
+ * specified id for the specified property relationship. This method may not
+ * return an array fault because array faults call this method to fetch on
+ * demand. All objects must be registered the specified editing context. The
+ * specified relationship key must produce a result of type Collection for the
+ * source object or an exception is thrown.
+ */
+ public NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationshipKey, EOEditingContext aContext) {
//System.out.println( "EOEditingContext.objectsForSourceGlobalID: "
//+ aGlobalID + " : " + aRelationshipKey );
-
- NSArray result = null;
-
-if ( aContext == this )
-{
- throw new WotonomyException( "Assert failed: calling objectsForSourceGlobalID on ourself." );
-}
- Object source = registrar.objectForGlobalID( aGlobalID );
-
- // if not registered in our context
- if ( source == null )
- {
- // get the object registered into our context
- result = parentStore.objectsForSourceGlobalID(
- aGlobalID, aRelationshipKey, this );
- }
- else // source is registered in our context
- {
- // get existing value
- Object value;
- if ( source instanceof EOKeyValueCoding )
- {
- value = ((EOKeyValueCoding)source).storedValueForKey(
- aRelationshipKey );
- }
- else // handle directly
- {
- value = EOKeyValueCodingSupport.storedValueForKey(
- source, aRelationshipKey );
- }
-
- // if we don't have a valid value on our object
- if ( ( value == null )
- || ( ( value instanceof ArrayFault )
- && ( !((ArrayFault)value).isFetched() ) ) )
- {
- // do the same as if the source was null
- result = parentStore.objectsForSourceGlobalID(
- aGlobalID, aRelationshipKey, this );
-
- // set our value since we have it
- if ( source instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)source).takeStoredValueForKey(
- result, aRelationshipKey );
- }
- else // handle directly
- {
- EOKeyValueCodingSupport.takeStoredValueForKey(
- source, result, aRelationshipKey );
- }
- }
- else
- if ( ( value instanceof ArrayFault )
- && ( !((ArrayFault)value).isFetched() ) )
- {
- // do the same as if the source was null
- result = parentStore.objectsForSourceGlobalID(
- aGlobalID, aRelationshipKey, this );
- }
- else
- if ( value instanceof NSArray )
- {
- result = (NSArray) value;
- }
- else // not NSArray
- if ( value instanceof Collection )
- {
- // convert to NSArray
- result = new NSArray( (Collection) value );
- }
- else
- {
- throw new WotonomyException(
- "Relationship key did not return a collection: "
- + aGlobalID + " : " + aRelationshipKey );
- }
- }
-
- // if our context is not the specified context
- if ( aContext != this )
- {
- result = (NSArray) clone( this, result, aContext );
- }
-
- return result;
- }
-
- /**
- * Returns a read-only List of objects the meet the criteria of
- * the supplied specification. This method simply calls
- * objectsWithFetchSpecification on this editing context
- * with this editing context as the parameter.
- */
- public NSArray objectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec )
- {
- return objectsWithFetchSpecification( aFetchSpec, this );
- }
-
- /**
- * Returns a read-only List of objects the meet the criteria of
- * the supplied specification. Faults are not allowed in the array.
- * If any objects are already fetched, they should not be
- * refetched. All objects should belong to the specified editing context.
- * This implementation forwards the call to the parent object
- * store, which will register each object in the specified editing
- * context only if it does not already exist.
- */
- public NSArray objectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec,
- EOEditingContext aContext)
- {
- if ( aContext == this )
- {
- Object result = notifyDelegate(
- "editingContextShouldFetchObjects",
- new Class[] { EOEditingContext.class, EOFetchSpecification.class },
- new Object[] { aContext, aFetchSpec } );
- if ( result instanceof NSArray ) return (NSArray) result;
- }
- return parentStore.objectsWithFetchSpecification( aFetchSpec, aContext );
- }
-
- /**
- * Returns the parent object store for this editing context.
- * The result will not be null.
- */
- public EOObjectStore parentObjectStore ()
- {
- return parentStore;
- }
-
- /**
- * Updates the inserted, updated, and deleted objects lists,
- * and posts notifications about which objects have been changed.
- * This method is called at the end of an event loop in which
- * objects were modified. This method is additionally called
- * by saveChanges() so that any changes in the same event loop
- * will be processed correctly before calling to the parent
- * object store.
- * This implementation updates those lists immediately, but
- * only posts notifications when this method is called.
- */
- public void processRecentChanges ()
- { // System.out.println( "EOEditingContext.processRecentChanges: " + invalidatedObjectsBuffer );
-
- /*
- * This implementation actually updates those lists immediately,
- * but keeps a separate buffer of changes in the current event
- * loop for the purposes of posting a notification.
- * NOTE: to reenable buffering, uncomment lines from this method
- * body and reenable the RecentChangesObserver in the constructor.
- */
-
- // broadcast ObjectsChangedInStoreNotification
- // for the benefit of child editing contexts
-
- boolean postStoreInfo =
- ( insertedObjectsBuffer.size() +
- updatedObjectsBuffer.size() +
- deletedIDsBuffer.size() +
- invalidatedIDsBuffer.size() > 0 );
-
- NSMutableDictionary storeInfo = new NSMutableDictionary();
- if ( postStoreInfo )
- {
- storeInfo.setObjectForKey(
- globalIDsForObjects( insertedObjectsBuffer ),
- // globalIDsForObjects( insertedObjects ),
- EOObjectStore.InsertedKey );
- storeInfo.setObjectForKey(
- globalIDsForObjects( updatedObjectsBuffer ),
- // globalIDsForObjects( updatedObjects ),
- EOObjectStore.UpdatedKey );
- storeInfo.setObjectForKey(
- new NSArray( (Collection) deletedIDsBuffer ),
- // globalIDsForObjects( deletedObjects ),
- EOObjectStore.DeletedKey );
- storeInfo.setObjectForKey(
- new NSArray( (Collection) invalidatedIDsBuffer ),
- EOObjectStore.InvalidatedKey );
- }
-
- // broadcast ObjectsChangedInEditingContextNotification
- // for the benefit of attached display groups
-
- boolean postContextInfo =
- ( insertedObjectsBuffer.size() +
- updatedObjectsBuffer.size() +
- deletedObjectsBuffer.size() +
- invalidatedObjectsBuffer.size() > 0 );
-
- NSMutableDictionary contextInfo = new NSMutableDictionary();
-
- if ( postContextInfo )
- {
-
- contextInfo.setObjectForKey(
- new NSArray( (Collection) insertedObjectsBuffer ),
- // new NSArray( (Collection) insertedObjects ),
- EOObjectStore.InsertedKey );
- contextInfo.setObjectForKey(
- new NSArray( (Collection) updatedObjectsBuffer ),
- // new NSArray( (Collection) updatedObjects ),
- EOObjectStore.UpdatedKey );
- contextInfo.setObjectForKey(
- new NSArray( (Collection) deletedObjectsBuffer ),
- // new NSArray( (Collection) deletedObjects ),
- EOObjectStore.DeletedKey );
- contextInfo.setObjectForKey(
- new NSArray( (Collection) invalidatedObjectsBuffer ),
- EOObjectStore.InvalidatedKey );
- }
-
- // update the current snapshots
-
- Object o;
- Iterator it;
- it = insertedObjectsBuffer.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- registrar.setCurrentSnapshot( o, takeSnapshot( o ) );
- }
- it = updatedObjectsBuffer.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- registrar.setCurrentSnapshot( o, takeSnapshot( o ) );
- }
-
- // clear buffers
-
- insertedObjectsBuffer.removeAllObjects();
- updatedObjectsBuffer.removeAllObjects();
- deletedObjectsBuffer.removeAllObjects();
- deletedIDsBuffer.removeAllObjects();
- invalidatedObjectsBuffer.removeAllObjects();
- invalidatedIDsBuffer.removeAllObjects();
-
- // post notifications (does order matter?)
-
- if ( postStoreInfo )
- {
- NSNotificationCenter.defaultCenter().postNotification(
- new NSNotification(
- ObjectsChangedInStoreNotification, this, storeInfo ) );
- }
-
- if ( postContextInfo )
- {
- NSNotificationCenter.defaultCenter().postNotification(
- new NSNotification(
- ObjectsChangedInEditingContextNotification, this, contextInfo ) );
- }
-
- }
-
- /**
- * Returns whether this editing context propagates deletes
- * immediately after the event that triggered the delete.
- * Otherwise, propagation occurs only before commit.
- */
- public boolean propagatesDeletesAtEndOfEvent ()
- {
- return propagateDeletesAfterEvent;
- }
-
- /**
- * Registers the specified object in this editing context
- * for the specified id. This method is called by an object
- * store when fetching objects for a display group, or when
- * objects are inserted into a display group.
- * This implementation will re-register the object under the
- * new id if it is already registered under a different id.
- */
- public void recordObject (
- Object anObject,
- EOGlobalID aGlobalID )
- {
- // find state for re-registration
- boolean inserted = false;
- boolean updated = false;
- boolean deleted = false;
-
- // is the object already registered?
- EOGlobalID existingID = globalIDForObject( anObject );
- if ( existingID != null )
- {
- // remember object state
- int index;
- index = insertedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound ) inserted = true;
- index = updatedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound ) updated = true;
- index = deletedObjects.indexOfIdenticalObject( anObject );
- if ( index != NSArray.NotFound ) deleted = true;
- // forget the object
- forgetObject( anObject );
- }
-
- // is the global id already in use?
- Object existingObject = objectForGlobalID( aGlobalID );
- if ( existingObject != null )
- {
- // forget it (don't worry about state?)
- forgetObject( existingObject );
- }
-
- registrar.registerObject( anObject, aGlobalID );
-
- // restore state if necessary
- if ( inserted ) insertedObjects.addObject( anObject );
- if ( updated ) updatedObjects.addObject( anObject );
- if ( deleted ) deletedObjects.addObject( anObject );
- }
-
- /**
- * Undoes the last undo operation.
- */
- public void redo ()
- {
- //TODO: not supported yet
- throw new UnsupportedOperationException("Not implemented yet.");
- }
-
- /**
- * Refaults this editing context, turning all unmodified
- * objects into faults. This implementation calls
- * editingContextWillSaveChanges() on all editors, and
- * then calls refaultObjects().
- */
- public void refault ()
- {
- fireWillSaveChanges();
- refaultObjects();
- }
-
- /**
- * Refaults the specified object, turning it into a fault
- * for the specified global id in the specified context.
- */
- public void refaultObject (
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext)
- {
- aContext.registrar.setCurrentSnapshot( anObject, null );
-
- ignoreChanges = true;
- parentStore.refaultObject( anObject, aGlobalID, aContext );
- ignoreChanges = false;
-
+
+ NSArray result = null;
+
+ if (aContext == this) {
+ throw new WotonomyException("Assert failed: calling objectsForSourceGlobalID on ourself.");
+ }
+ Object source = registrar.objectForGlobalID(aGlobalID);
+
+ // if not registered in our context
+ if (source == null) {
+ // get the object registered into our context
+ result = parentStore.objectsForSourceGlobalID(aGlobalID, aRelationshipKey, this);
+ } else // source is registered in our context
+ {
+ // get existing value
+ Object value;
+ if (source instanceof EOKeyValueCoding) {
+ value = ((EOKeyValueCoding) source).storedValueForKey(aRelationshipKey);
+ } else // handle directly
+ {
+ value = EOKeyValueCodingSupport.storedValueForKey(source, aRelationshipKey);
+ }
+
+ // if we don't have a valid value on our object
+ if ((value == null) || ((value instanceof ArrayFault) && (!((ArrayFault) value).isFetched()))) {
+ // do the same as if the source was null
+ result = parentStore.objectsForSourceGlobalID(aGlobalID, aRelationshipKey, this);
+
+ // set our value since we have it
+ if (source instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) source).takeStoredValueForKey(result, aRelationshipKey);
+ } else // handle directly
+ {
+ EOKeyValueCodingSupport.takeStoredValueForKey(source, result, aRelationshipKey);
+ }
+ } else if ((value instanceof ArrayFault) && (!((ArrayFault) value).isFetched())) {
+ // do the same as if the source was null
+ result = parentStore.objectsForSourceGlobalID(aGlobalID, aRelationshipKey, this);
+ } else if (value instanceof NSArray) {
+ result = (NSArray) value;
+ } else // not NSArray
+ if (value instanceof Collection) {
+ // convert to NSArray
+ result = new NSArray((Collection) value);
+ } else {
+ throw new WotonomyException(
+ "Relationship key did not return a collection: " + aGlobalID + " : " + aRelationshipKey);
+ }
+ }
+
+ // if our context is not the specified context
+ if (aContext != this) {
+ result = (NSArray) clone(this, result, aContext);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a read-only List of objects the meet the criteria of the supplied
+ * specification. This method simply calls objectsWithFetchSpecification on this
+ * editing context with this editing context as the parameter.
+ */
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec) {
+ return objectsWithFetchSpecification(aFetchSpec, this);
+ }
+
+ /**
+ * Returns a read-only List of objects the meet the criteria of the supplied
+ * specification. Faults are not allowed in the array. If any objects are
+ * already fetched, they should not be refetched. All objects should belong to
+ * the specified editing context. This implementation forwards the call to the
+ * parent object store, which will register each object in the specified editing
+ * context only if it does not already exist.
+ */
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext) {
+ if (aContext == this) {
+ Object result = notifyDelegate("editingContextShouldFetchObjects",
+ new Class[] { EOEditingContext.class, EOFetchSpecification.class },
+ new Object[] { aContext, aFetchSpec });
+ if (result instanceof NSArray)
+ return (NSArray) result;
+ }
+ return parentStore.objectsWithFetchSpecification(aFetchSpec, aContext);
+ }
+
+ /**
+ * Returns the parent object store for this editing context. The result will not
+ * be null.
+ */
+ public EOObjectStore parentObjectStore() {
+ return parentStore;
+ }
+
+ /**
+ * Updates the inserted, updated, and deleted objects lists, and posts
+ * notifications about which objects have been changed. This method is called at
+ * the end of an event loop in which objects were modified. This method is
+ * additionally called by saveChanges() so that any changes in the same event
+ * loop will be processed correctly before calling to the parent object store.
+ * This implementation updates those lists immediately, but only posts
+ * notifications when this method is called.
+ */
+ public void processRecentChanges() { // System.out.println( "EOEditingContext.processRecentChanges: " +
+ // invalidatedObjectsBuffer );
+
+ /*
+ * This implementation actually updates those lists immediately, but keeps a
+ * separate buffer of changes in the current event loop for the purposes of
+ * posting a notification. NOTE: to reenable buffering, uncomment lines from
+ * this method body and reenable the RecentChangesObserver in the constructor.
+ */
+
+ // broadcast ObjectsChangedInStoreNotification
+ // for the benefit of child editing contexts
+
+ boolean postStoreInfo = (insertedObjectsBuffer.size() + updatedObjectsBuffer.size() + deletedIDsBuffer.size()
+ + invalidatedIDsBuffer.size() > 0);
+
+ NSMutableDictionary storeInfo = new NSMutableDictionary();
+ if (postStoreInfo) {
+ storeInfo.setObjectForKey(globalIDsForObjects(insertedObjectsBuffer),
+ // globalIDsForObjects( insertedObjects ),
+ EOObjectStore.InsertedKey);
+ storeInfo.setObjectForKey(globalIDsForObjects(updatedObjectsBuffer),
+ // globalIDsForObjects( updatedObjects ),
+ EOObjectStore.UpdatedKey);
+ storeInfo.setObjectForKey(new NSArray((Collection) deletedIDsBuffer),
+ // globalIDsForObjects( deletedObjects ),
+ EOObjectStore.DeletedKey);
+ storeInfo.setObjectForKey(new NSArray((Collection) invalidatedIDsBuffer), EOObjectStore.InvalidatedKey);
+ }
+
+ // broadcast ObjectsChangedInEditingContextNotification
+ // for the benefit of attached display groups
+
+ boolean postContextInfo = (insertedObjectsBuffer.size() + updatedObjectsBuffer.size()
+ + deletedObjectsBuffer.size() + invalidatedObjectsBuffer.size() > 0);
+
+ NSMutableDictionary contextInfo = new NSMutableDictionary();
+
+ if (postContextInfo) {
+
+ contextInfo.setObjectForKey(new NSArray((Collection) insertedObjectsBuffer),
+ // new NSArray( (Collection) insertedObjects ),
+ EOObjectStore.InsertedKey);
+ contextInfo.setObjectForKey(new NSArray((Collection) updatedObjectsBuffer),
+ // new NSArray( (Collection) updatedObjects ),
+ EOObjectStore.UpdatedKey);
+ contextInfo.setObjectForKey(new NSArray((Collection) deletedObjectsBuffer),
+ // new NSArray( (Collection) deletedObjects ),
+ EOObjectStore.DeletedKey);
+ contextInfo.setObjectForKey(new NSArray((Collection) invalidatedObjectsBuffer),
+ EOObjectStore.InvalidatedKey);
+ }
+
+ // update the current snapshots
+
+ Object o;
+ Iterator it;
+ it = insertedObjectsBuffer.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ registrar.setCurrentSnapshot(o, takeSnapshot(o));
+ }
+ it = updatedObjectsBuffer.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ registrar.setCurrentSnapshot(o, takeSnapshot(o));
+ }
+
+ // clear buffers
+
+ insertedObjectsBuffer.removeAllObjects();
+ updatedObjectsBuffer.removeAllObjects();
+ deletedObjectsBuffer.removeAllObjects();
+ deletedIDsBuffer.removeAllObjects();
+ invalidatedObjectsBuffer.removeAllObjects();
+ invalidatedIDsBuffer.removeAllObjects();
+
+ // post notifications (does order matter?)
+
+ if (postStoreInfo) {
+ NSNotificationCenter.defaultCenter()
+ .postNotification(new NSNotification(ObjectsChangedInStoreNotification, this, storeInfo));
+ }
+
+ if (postContextInfo) {
+ NSNotificationCenter.defaultCenter().postNotification(
+ new NSNotification(ObjectsChangedInEditingContextNotification, this, contextInfo));
+ }
+
+ }
+
+ /**
+ * Returns whether this editing context propagates deletes immediately after the
+ * event that triggered the delete. Otherwise, propagation occurs only before
+ * commit.
+ */
+ public boolean propagatesDeletesAtEndOfEvent() {
+ return propagateDeletesAfterEvent;
+ }
+
+ /**
+ * Registers the specified object in this editing context for the specified id.
+ * This method is called by an object store when fetching objects for a display
+ * group, or when objects are inserted into a display group. This implementation
+ * will re-register the object under the new id if it is already registered
+ * under a different id.
+ */
+ public void recordObject(Object anObject, EOGlobalID aGlobalID) {
+ // find state for re-registration
+ boolean inserted = false;
+ boolean updated = false;
+ boolean deleted = false;
+
+ // is the object already registered?
+ EOGlobalID existingID = globalIDForObject(anObject);
+ if (existingID != null) {
+ // remember object state
+ int index;
+ index = insertedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound)
+ inserted = true;
+ index = updatedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound)
+ updated = true;
+ index = deletedObjects.indexOfIdenticalObject(anObject);
+ if (index != NSArray.NotFound)
+ deleted = true;
+ // forget the object
+ forgetObject(anObject);
+ }
+
+ // is the global id already in use?
+ Object existingObject = objectForGlobalID(aGlobalID);
+ if (existingObject != null) {
+ // forget it (don't worry about state?)
+ forgetObject(existingObject);
+ }
+
+ registrar.registerObject(anObject, aGlobalID);
+
+ // restore state if necessary
+ if (inserted)
+ insertedObjects.addObject(anObject);
+ if (updated)
+ updatedObjects.addObject(anObject);
+ if (deleted)
+ deletedObjects.addObject(anObject);
+ }
+
+ /**
+ * Undoes the last undo operation.
+ */
+ public void redo() {
+ // TODO: not supported yet
+ throw new UnsupportedOperationException("Not implemented yet.");
+ }
+
+ /**
+ * Refaults this editing context, turning all unmodified objects into faults.
+ * This implementation calls editingContextWillSaveChanges() on all editors, and
+ * then calls refaultObjects().
+ */
+ public void refault() {
+ fireWillSaveChanges();
+ refaultObjects();
+ }
+
+ /**
+ * Refaults the specified object, turning it into a fault for the specified
+ * global id in the specified context.
+ */
+ public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ aContext.registrar.setCurrentSnapshot(anObject, null);
+
+ ignoreChanges = true;
+ parentStore.refaultObject(anObject, aGlobalID, aContext);
+ ignoreChanges = false;
+
// remove from updated objects if necessary
- int i = updatedObjects.indexOfIdenticalObject( anObject );
- if ( i != NSArray.NotFound )
- {
- updatedObjects.removeObjectAtIndex( i );
- }
-
- // add to invalidated notification queue
- invalidatedObjectsBuffer.addObject( anObject );
- invalidatedIDsBuffer.addObject( aGlobalID );
- }
-
- /**
- * Turns all unmodified objects into faults, calling
- * processRecentChanges() and then refaultObject() for
- * each unmodified object.
- */
- public void refaultObjects ()
- {
- // is this call really needed?
- // processRecentChanges();
-
- Object o;
- EOGlobalID id;
- Iterator it = registeredObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( updatedObjects.indexOfIdenticalObject( o ) == NSArray.NotFound )
- && ( insertedObjects.indexOfIdenticalObject( o ) == NSArray.NotFound )
- && ( deletedObjects.indexOfIdenticalObject( o ) == NSArray.NotFound ) )
- {
- id = globalIDForObject( o );
- refaultObject( o, id, this );
- }
- }
- }
-
- /**
- * Calls editingContextWillSaveChanges() on all editors,
- * and then calls invalidateAllObjects().
- */
- public void refetch ()
- {
- fireWillSaveChanges();
- invalidateAllObjects();
- }
-
- /**
- * Returns a read-only List of all objects registered in this
- * editing context.
- */
- public NSArray registeredObjects ()
- {
- return registrar.registeredObjects();
- }
-
- /**
- * Unregisters the specified editor with this editing context.
- */
- public void removeEditor ( Object anObject )
- {
- if ( anObject == null ) return;
-
- Object o;
- Iterator i = editorSet.iterator();
- while ( i.hasNext() )
- {
- o = ((WeakReference)i.next()).get();
- if ( ( o == null ) || ( o == anObject ) )
- {
- i.remove();
- }
- }
- }
-
- /**
- * Unregisters all objects from this editing context,
- * and resets the fetch timestamp.
- */
- public void reset ()
- {
- Iterator it = registeredObjects().iterator();
- while ( it.hasNext() )
- {
- forgetObject( it.next() );
- }
- fetchTimestamp = 0; //FIXME: reset timestamp properly
- }
-
- /**
- * Reverts the objects in this editing context to
- * their original state.
- * Calls editingContextWillSaveChanges on all editors,
- * discards all inserted objects, restores deleted
- * objects, and applies the fetch snapshot to all
- * registered objects.
- */
- public void revert ()
- {
- willChange();
- fireWillSaveChanges();
-
- Iterator it;
-
- // forget inserted objects
- it = new NSArray( insertedObjects ).iterator();
- while ( it.hasNext() )
- {
- forgetObject( it.next() );
- }
-
- EOGlobalID id;
- Object o;
- byte[] snapshot;
-
- // re-initialize updated objects
- it = new NSArray( updatedObjects ).iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- snapshot = (byte[]) registrar.getCommitSnapshot( o );
- if ( snapshot != null )
- {
- applySnapshot( snapshot, o );
- }
- registrar.setCommitSnapshot( o, null );
- updatedObjectsBuffer.addObject( o );
- }
-
- // re-initialize deleted objects
- it = new NSArray( deletedObjects ).iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- snapshot = (byte[]) registrar.getCommitSnapshot( o );
- if ( snapshot != null )
- {
- applySnapshot( snapshot, o );
- }
- registrar.setCommitSnapshot( o, null );
- updatedObjectsBuffer.addObject( o );
- }
-
- // reset lists
- insertedObjects.removeAllObjects(); // unneccessary?
- deletedObjects.removeAllObjects();
- updatedObjects.removeAllObjects();
-
- // post notification
- processRecentChanges();
- }
-
- /**
- * Returns the root object store, which is the parent
- * of all parent object stores of this editing context.
- */
- public EOObjectStore rootObjectStore ()
- {
- EOObjectStore parent = parentObjectStore();
- while ( parent instanceof EOEditingContext )
- {
- parent = ((EOEditingContext)parent).parentObjectStore();
- }
- return parent;
- }
-
- /**
- * Calls editingContextWillSaveChanges on all editors,
- * and commits all changes in this editing context to
- * the parent editing context by calling
- * saveChangesInEditingContext to the parent.
- * Then posts EditingContextDidSaveChangeNotification.
- */
- public void saveChanges ()
- {
+ int i = updatedObjects.indexOfIdenticalObject(anObject);
+ if (i != NSArray.NotFound) {
+ updatedObjects.removeObjectAtIndex(i);
+ }
+
+ // add to invalidated notification queue
+ invalidatedObjectsBuffer.addObject(anObject);
+ invalidatedIDsBuffer.addObject(aGlobalID);
+ }
+
+ /**
+ * Turns all unmodified objects into faults, calling processRecentChanges() and
+ * then refaultObject() for each unmodified object.
+ */
+ public void refaultObjects() {
+ // is this call really needed?
+ // processRecentChanges();
+
+ Object o;
+ EOGlobalID id;
+ Iterator it = registeredObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((updatedObjects.indexOfIdenticalObject(o) == NSArray.NotFound)
+ && (insertedObjects.indexOfIdenticalObject(o) == NSArray.NotFound)
+ && (deletedObjects.indexOfIdenticalObject(o) == NSArray.NotFound)) {
+ id = globalIDForObject(o);
+ refaultObject(o, id, this);
+ }
+ }
+ }
+
+ /**
+ * Calls editingContextWillSaveChanges() on all editors, and then calls
+ * invalidateAllObjects().
+ */
+ public void refetch() {
+ fireWillSaveChanges();
+ invalidateAllObjects();
+ }
+
+ /**
+ * Returns a read-only List of all objects registered in this editing context.
+ */
+ public NSArray registeredObjects() {
+ return registrar.registeredObjects();
+ }
+
+ /**
+ * Unregisters the specified editor with this editing context.
+ */
+ public void removeEditor(Object anObject) {
+ if (anObject == null)
+ return;
+
+ Object o;
+ Iterator i = editorSet.iterator();
+ while (i.hasNext()) {
+ o = ((WeakReference) i.next()).get();
+ if ((o == null) || (o == anObject)) {
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Unregisters all objects from this editing context, and resets the fetch
+ * timestamp.
+ */
+ public void reset() {
+ Iterator it = registeredObjects().iterator();
+ while (it.hasNext()) {
+ forgetObject(it.next());
+ }
+ fetchTimestamp = 0; // FIXME: reset timestamp properly
+ }
+
+ /**
+ * Reverts the objects in this editing context to their original state. Calls
+ * editingContextWillSaveChanges on all editors, discards all inserted objects,
+ * restores deleted objects, and applies the fetch snapshot to all registered
+ * objects.
+ */
+ public void revert() {
+ willChange();
+ fireWillSaveChanges();
+
+ Iterator it;
+
+ // forget inserted objects
+ it = new NSArray(insertedObjects).iterator();
+ while (it.hasNext()) {
+ forgetObject(it.next());
+ }
+
+ EOGlobalID id;
+ Object o;
+ byte[] snapshot;
+
+ // re-initialize updated objects
+ it = new NSArray(updatedObjects).iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ snapshot = (byte[]) registrar.getCommitSnapshot(o);
+ if (snapshot != null) {
+ applySnapshot(snapshot, o);
+ }
+ registrar.setCommitSnapshot(o, null);
+ updatedObjectsBuffer.addObject(o);
+ }
+
+ // re-initialize deleted objects
+ it = new NSArray(deletedObjects).iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ snapshot = (byte[]) registrar.getCommitSnapshot(o);
+ if (snapshot != null) {
+ applySnapshot(snapshot, o);
+ }
+ registrar.setCommitSnapshot(o, null);
+ updatedObjectsBuffer.addObject(o);
+ }
+
+ // reset lists
+ insertedObjects.removeAllObjects(); // unneccessary?
+ deletedObjects.removeAllObjects();
+ updatedObjects.removeAllObjects();
+
+ // post notification
+ processRecentChanges();
+ }
+
+ /**
+ * Returns the root object store, which is the parent of all parent object
+ * stores of this editing context.
+ */
+ public EOObjectStore rootObjectStore() {
+ EOObjectStore parent = parentObjectStore();
+ while (parent instanceof EOEditingContext) {
+ parent = ((EOEditingContext) parent).parentObjectStore();
+ }
+ return parent;
+ }
+
+ /**
+ * Calls editingContextWillSaveChanges on all editors, and commits all changes
+ * in this editing context to the parent editing context by calling
+ * saveChangesInEditingContext to the parent. Then posts
+ * EditingContextDidSaveChangeNotification.
+ */
+ public void saveChanges() {
//System.out.println( "EOEditingContext.saveChanges: " + this );
- willChange();
-
- // process any changes
- processRecentChanges();
-
- // set up user info for notification to be posted.
- NSMutableDictionary userInfo = new NSMutableDictionary();
- userInfo.setObjectForKey(
- new NSArray( (Collection) insertedObjects ),
- EOObjectStore.InsertedKey );
- userInfo.setObjectForKey(
- new NSArray( (Collection) updatedObjects ),
- EOObjectStore.UpdatedKey );
- userInfo.setObjectForKey(
- new NSArray( (Collection) deletedObjects ),
- EOObjectStore.DeletedKey );
-
- // notify the editors
- fireWillSaveChanges();
-
- // notify the delegate
- notifyDelegate(
- "editingContextWillSaveChanges",
- new Class[] { EOEditingContext.class },
- new Object[] { this } );
-
- // needed for notification handling
- isInvalidating = true;
- try
- {
- // ask parent to save us
- parentStore.saveChangesInEditingContext( this );
- }
- catch ( RuntimeException e )
- {
- // unset save flag and rethrow
- isInvalidating = false;
- throw e;
- }
- isInvalidating = false;
-
- // no exceptions: proceed!
-
- Object o, key;
- Iterator it;
-
- // update the committed snapshots
- it = insertedObjects.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- registrar.setCommitSnapshot( o, null );
- registrar.setCurrentSnapshot( o, null );
- }
- it = updatedObjects.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- registrar.setCommitSnapshot( o, null );
- registrar.setCurrentSnapshot( o, null );
- }
-
- // clear the lists
- updatedObjects.removeAllObjects();
- insertedObjects.removeAllObjects();
- it = new NSArray( deletedObjects() ).iterator();
- while ( it.hasNext() )
- { // parent is doing this as well?
- forgetObject( it.next() );
- }
-
- // post notification
- NSNotificationCenter.defaultCenter().postNotification(
- new NSNotification(
- EditingContextDidSaveChangesNotification, this, userInfo ) );
- }
-
- /**
- * Commits all changes in the specified editing context
- * to this one. Called by child editing contexts in
- * their saveChanges() method.
- */
- public void saveChangesInEditingContext (
- EOEditingContext aContext)
- {
- Object o;
- Iterator it;
-
- // process deletes
- List deletes = new NSArray( aContext.deletedObjects() );
- it = deletes.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- EOGlobalID id = aContext.globalIDForObject( o );
- Object localVersion = objectForGlobalID( id );
- if ( localVersion == null )
- {
- // make a local copy and register it
- localVersion = registerClone( id, aContext, o, this );
- if ( localVersion == null )
- {
- throw new WotonomyException(
- "Deleted object could not be serialized: "
- + id + " : " + o );
- }
- }
- else // we have a local version, copy changes
- {
- copy( aContext, o, this, localVersion );
- // copy marks the object as updated: will be on both lists
- }
- // delete our copy -- marks context as changed
- deleteObject( localVersion );
- }
-
- // process inserts - all inserts are new objects
- List inserts = new NSArray( aContext.insertedObjects() );
- it = inserts.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- // make a local copy and register it
- EOGlobalID id = aContext.globalIDForObject( o );
- willChange(); // need to mark editing context as changed
- Object localVersion = registerClone( id, aContext, o, this );
- if ( localVersion == null )
- {
- throw new WotonomyException(
- "Inserted object could not be serialized: "
- + o );
- }
- // insert our copy manually so a new id is not generated
- insertedObjects.addObject( localVersion );
- insertedObjectsBuffer.addObject( localVersion );
- }
-
- // process updates
- List updates = new NSArray( aContext.updatedObjects() );
- it = updates.iterator();
- while ( it.hasNext() )
- {
- willChange(); // need to mark editing context as changed
- o = it.next();
- EOGlobalID id = aContext.globalIDForObject( o );
- Object localVersion = objectForGlobalID( id );
- if ( localVersion == null )
- {
- // make a local copy and register it
- localVersion = registerClone( id, aContext, o, this );
- if ( localVersion == null )
- {
- throw new WotonomyException(
- "Updated object could not be serialized: "
- + id + " : " + o );
- }
- if ( id.isTemporary() )
- {
- // mark this object as inserted
- insertedObjects.addObject( localVersion );
- insertedObjectsBuffer.addObject( localVersion );
- }
- else
- {
- // mark this object as updated
- updatedObjects.addObject( localVersion );
-
- // notify of update only if not on deleted list
- if ( deletedObjectsBuffer.indexOfIdenticalObject(
- localVersion ) == NSArray.NotFound )
- {
- updatedObjectsBuffer.addObject( localVersion );
- }
- }
- }
- else // we have a local version, copy changes
- {
- copy( aContext, o, this, localVersion );
- // copy marks the object as updated
- }
- }
-
- }
-
- /**
- * Sets the delegate for this editing context.
- * Note: this implementation retains only a
- * weak reference to the specified object.
- */
- public void setDelegate (
- Object anObject )
- {
- if ( anObject == null ) delegate = null;
- delegate = new WeakReference( anObject );
- }
-
- /**
- * Sets the fetch timestamp for this editing context.
- */
- public void setFetchTimestamp (
- double aDouble )
- {
- fetchTimestamp = aDouble;
- }
-/*
- public void setInvalidatesObjectsWhenFinalized (
- boolean invalidatesObjects )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-
- public void setInvalidatesObjectsWhenFreed (
- boolean invalidatesObjects )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Sets whether this editing context attempts to
- * lock objects when they are first modified.
- * Default is false.
- */
- public void setLocksObjectsBeforeFirstModification (
- boolean locksObjects )
- {
- lockBeforeModify = locksObjects;
- }
-
- /**
- * Sets the message handler for this editing context.
- * Note: this implementation retains only a
- * weak reference to the specified object.
- */
- public void setMessageHandler (
- Object anObject )
- {
- if ( anObject == null ) messageHandler = null;
- messageHandler = new WeakReference( anObject );
- }
-
- /**
- * Sets whether this editing context propagates deletes
- * immediately after the event that triggered the delete.
- * Otherwise, propagation occurs only before commit.
- * Default is true.
- */
- public void setPropagatesDeletesAtEndOfEvent (
- boolean propagatesDeletes )
- {
- propagateDeletesAfterEvent = propagatesDeletes;
- }
-/*
- public void setSharedEditingContext (
- EOSharedEditingContext aSharedEditingContext )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Sets whether validation is stopped after the
- * first error occurs. Otherwise, validation will
- * continue for all other objects.
- * Default is true.
- */
- public void setStopsValidationAfterFirstError (
- boolean stopsValidation )
- {
- stopValidationAfterError = stopsValidation;
- }
-
- /**
- * Sets the undo manager to be used for this context.
- * Note: This is currently javax.swing.undo.UndoManager,
- * until we have a implementation of NSUndoManager.
- */
-/*
- public void setUndoManager (
- UndoManager anUndoManager )
- {
- undoManager = anUndoManager;
- }
-*/
-/*
- public EOSharedEditingContext sharedEditingContext ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Returns whether validation is stopped after the
- * first error occurs. Otherwise, validation will
- * continue for all other objects.
- */
- public boolean stopsValidationAfterFirstError ()
- {
- return stopValidationAfterError;
- }
-
- /**
- * Reverts the last change on the undo stack.
- */
- public void undo ()
- {
- //TODO: not supported yet
- throw new UnsupportedOperationException("Not implemented yet.");
- }
-/*
- public NSUndoManager undoManager ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
-/**
- public void unlock ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
- /**
- * Returns a read-only list of all objects marked as modified,
- * but not inserted or deleted, in this editing context.
- */
- public NSArray updatedObjects ()
- {
- return updatedObjectsProxy;
- }
-
- /**
- * Notify editors of changes.
- */
- private void fireWillSaveChanges()
- {
- Object o = null;
- Iterator i = editors().iterator();
- while ( i.hasNext() )
- {
- try
- {
- o = i.next();
- NSSelector.invoke( "editingContextWillSaveChanges",
- new Class[] { EOEditingContext.class }, o, this );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println( "Error while notifying editor of pending save: " + o );
- exc.printStackTrace();
- }
- }
- }
-
- /**
- * Handles notifications from parent store, looking for
- * InvalidatedAllObjectsInStoreNotification and
- * ObjectsChangedInStoreNotification.
- * The former causes all objects in this store to be
- * invalidated.
- * The latter refaults the invalidated ids, merges changes
- * from the updated ids, and forgets the deleted ids, then
- * posts a ObjectsChangedInStoreNotification.
- * Note: This method is not in the public specification.
- */
- public void handleNotification( NSNotification aNotification )
- { // System.out.println( "EOEditingContext: " + this + " : " + aNotification );
-
- willChange();
- if ( InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
- refaultObjects();
-
- // relay notification
- NSNotificationCenter.defaultCenter().postNotification(
- new NSNotification(
- InvalidatedAllObjectsInStoreNotification, this ) );
- }
- else
- if ( EOGlobalID.GlobalIDChangedNotification
- .equals( aNotification.name() ) )
- {
- NSDictionary userInfo = aNotification.userInfo();
-
- // if any keys in userInfo are registered ids,
- // re-register with new permanent values.
-
- Object o;
- EOGlobalID id;
- Enumeration e = userInfo.keyEnumerator();
- while ( e.hasMoreElements() )
- {
- id = (EOGlobalID) e.nextElement();
- o = objectForGlobalID( id );
- if ( o != null )
- {
- // record object is assumed to handle key updates
- recordObject( o, (EOGlobalID) userInfo.objectForKey( id ) );
- }
- }
- }
- else
- if ( EOObjectStore.ObjectsChangedInStoreNotification
- .equals( aNotification.name() ) )
- {
- //System.out.println( "EOEditingContext.handleNotification: " + aNotification + " : " + this );
- // post so child contexts are notified
- willChange();
-
- Object o;
- EOGlobalID id;
- Enumeration e;
- NSDictionary userInfo = aNotification.userInfo();
-
- // inserted objects are ignored
-
- // existing deleted objects are removed
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- e = deletes.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- id = (EOGlobalID) e.nextElement();
- o = objectForGlobalID( id );
- if ( o != null )
- {
- //System.out.println( "EOEditingContext: deleted: " + id );
- forgetObject( o );
- deletedObjectsBuffer.addObject( o );
- deletedIDsBuffer.addObject( id );
- }
- }
-
- // existing updated objects are merged
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- e = updates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- id = (EOGlobalID) e.nextElement();
- o = objectForGlobalID( id );
- if ( o != null )
- {
- //System.out.println( "EOEditingContext: updated: " + id );
- if ( updatedObjects // only update if unchanged
- .indexOfIdenticalObject( o ) == NSArray.NotFound )
- {
- refaultObject( o, id, this );
- updatedObjectsBuffer.addObject( o );
- }
- else
- {
- // notify user and/or merge
- handleUpdateConflict( id, o );
- }
- }
- }
-
- // existing invalidated objects are refaulted
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- e = invalidates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- id = (EOGlobalID) e.nextElement();
- o = objectForGlobalID( id );
- if ( o != null )
- {
- if ( updatedObjects // only invalidate if unchanged
- .indexOfIdenticalObject( o ) == NSArray.NotFound )
- {
- refaultObject( o, id, this );
- }
- else
- {
- // notify user and/or merge
- handleUpdateConflict( id, o );
- }
- if ( invalidatedObjectsBuffer
- .indexOfIdenticalObject( o ) == NSArray.NotFound )
- {
- invalidatedObjectsBuffer.addObject( o );
- }
- if ( invalidatedIDsBuffer
- .indexOfIdenticalObject( id ) == NSArray.NotFound )
- {
- invalidatedIDsBuffer.addObject( id );
- }
- }
- }
-
- }
- }
-
- /**
- * Called by handleNotification to resolve the case where we have
- * received notification that another user or context has updated
- * an object that is currently marked as edited in this context.
- * This implementation first asks the delegate if it should merge.
- * If true or no delegate, the changes are merged. True or false,
- * the delegate is then sent editingContextDidMergeChanges.
- */
- private void handleUpdateConflict( EOGlobalID anID, Object anObject )
- {
- // if we're causing the invalidation, ignore
- // (this is probably better handled by the caller...)
- if ( isInvalidating )
- {
- ignoreChanges = true;
- parentStore.refaultObject( anObject, anID, this );
- ignoreChanges = false;
- return;
- }
-
- Boolean result = (Boolean) notifyDelegate(
- "editingContextShouldMergeChangesForObject",
- new Class[] { EOEditingContext.class, Object.class },
- new Object[] { this, anObject } );
-
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- // do merge
- mergeExternalChanges( anID, anObject );
- }
- else // Boolean.FALSE
- {
- // do nothing: don't lose the user's changes
- }
-
- // notify merge did happen
- notifyDelegate(
- "editingContextDidMergeChanges",
- new Class[] { EOEditingContext.class },
- new Object[] { this } );
- }
-
- /**
- * For the currently modified object with the specified global id,
- * this method merges changes with the updated version in the parent
- * object store. This implementation looks at the fetch snapshot
- * to determine which changes where made by the user, fetches the
- * updated version of the object, and then determine what external
- * changes were made. If the changes do not overlap, the original
- * changes are applied to the updated version. If there is a conflict,
- * notifies the user of the conflict.
- */
- private boolean mergeExternalChanges( EOGlobalID anID, Object anObject )
- {
- try
- {
- Iterator i;
- Object key;
-
- // get fetch snapshot
- Map fetchSnapshot = committedSnapshotForObject( anObject );
-
- // get current snapshot
- Map currentSnapshot = currentEventSnapshotForObject( anObject );
-
- // diff against fetch snapshot
- Map currentDiff = new HashMap();
- i = currentSnapshot.keySet().iterator();
- while ( i.hasNext() )
- {
- key = i.next();
- if ( ! currentSnapshot.get( key ).equals( fetchSnapshot.get( key ) ) )
- {
- currentDiff.put( key, currentSnapshot.get( key ) );
- }
- }
-
- // refault
- ignoreChanges = true;
- parentStore.refaultObject( anObject, anID, this );
- ignoreChanges = false;
-
- // get updated snapshot
- Map updatedSnapshot = convertSnapshotToDictionary( takeSnapshot( anObject ) );
-
- // diff against fetch snapshot
- Map updatedDiff = new HashMap();
- i = updatedSnapshot.keySet().iterator();
- while ( i.hasNext() )
- {
- key = i.next();
- if ( ! updatedSnapshot.get( key ).equals( fetchSnapshot.get( key ) ) )
- {
- updatedDiff.put( key, updatedSnapshot.get( key ) );
- }
- }
-
- // determine if there's a conflict
- boolean proceed = true;
- Set updatedKeys = updatedDiff.keySet();
- i = currentDiff.keySet().iterator();
- while ( i.hasNext() )
- {
- if ( updatedKeys.contains( i.next() ) )
- {
- proceed = false;
- break;
- }
- }
-
- // if no conflicts, apply original diff to current object and exit
- if ( proceed )
- {
- KeyValueCodingUtilities.takeStoredValuesFromDictionary( anObject, currentDiff );
- return true; // exit!
- }
- }
- catch ( Exception exc )
- {
- // log error to standard out
- exc.printStackTrace();
- }
-
- // notify user we're unable to merge
- notifyMessageHandler( MessageChangeConflict + anObject );
- return false;
- }
-
- /**
- * Sends the specified message to the message handler.
- */
- private void notifyMessageHandler( String aMessage )
- {
- Object handler = null;
- try
- {
- handler = messageHandler();
- if ( handler == null ) return;
- NSSelector.invoke( "editingContextPresentErrorMessage",
- new Class[] { EOEditingContext.class, String.class },
- handler, this, aMessage );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while notifying message handler: " +
- handler + " : " + aMessage );
- exc.printStackTrace();
- }
- }
-
- /**
- * Sends the specified message to the delegate.
- * Returns the return value of the method,
- * or null if no return value or no delegate
- * or no implementation.
- */
- private Object notifyDelegate(
- String aMethodName, Class[] types, Object[] params )
- {
- try
- {
- Object delegate = delegate();
- if ( delegate == null ) return null;
- return NSSelector.invoke(
- aMethodName, types, delegate, params );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while messaging delegate: " +
- delegate + " : " + aMethodName );
- exc.printStackTrace();
- }
-
- return null;
- }
-
- // interface EOObserving
-
- /**
- * Implementation of the EOObserving interface.
- * Called before objects are modified.
- */
- public void objectWillChange (
- Object anObject )
- {
- if ( ignoreChanges ) return;
+ willChange();
+
+ // process any changes
+ processRecentChanges();
+
+ // set up user info for notification to be posted.
+ NSMutableDictionary userInfo = new NSMutableDictionary();
+ userInfo.setObjectForKey(new NSArray((Collection) insertedObjects), EOObjectStore.InsertedKey);
+ userInfo.setObjectForKey(new NSArray((Collection) updatedObjects), EOObjectStore.UpdatedKey);
+ userInfo.setObjectForKey(new NSArray((Collection) deletedObjects), EOObjectStore.DeletedKey);
+
+ // notify the editors
+ fireWillSaveChanges();
+
+ // notify the delegate
+ notifyDelegate("editingContextWillSaveChanges", new Class[] { EOEditingContext.class }, new Object[] { this });
+
+ // needed for notification handling
+ isInvalidating = true;
+ try {
+ // ask parent to save us
+ parentStore.saveChangesInEditingContext(this);
+ } catch (RuntimeException e) {
+ // unset save flag and rethrow
+ isInvalidating = false;
+ throw e;
+ }
+ isInvalidating = false;
+
+ // no exceptions: proceed!
+
+ Object o, key;
+ Iterator it;
+
+ // update the committed snapshots
+ it = insertedObjects.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ registrar.setCommitSnapshot(o, null);
+ registrar.setCurrentSnapshot(o, null);
+ }
+ it = updatedObjects.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ registrar.setCommitSnapshot(o, null);
+ registrar.setCurrentSnapshot(o, null);
+ }
+
+ // clear the lists
+ updatedObjects.removeAllObjects();
+ insertedObjects.removeAllObjects();
+ it = new NSArray(deletedObjects()).iterator();
+ while (it.hasNext()) { // parent is doing this as well?
+ forgetObject(it.next());
+ }
+
+ // post notification
+ NSNotificationCenter.defaultCenter()
+ .postNotification(new NSNotification(EditingContextDidSaveChangesNotification, this, userInfo));
+ }
+
+ /**
+ * Commits all changes in the specified editing context to this one. Called by
+ * child editing contexts in their saveChanges() method.
+ */
+ public void saveChangesInEditingContext(EOEditingContext aContext) {
+ Object o;
+ Iterator it;
+
+ // process deletes
+ List deletes = new NSArray(aContext.deletedObjects());
+ it = deletes.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ EOGlobalID id = aContext.globalIDForObject(o);
+ Object localVersion = objectForGlobalID(id);
+ if (localVersion == null) {
+ // make a local copy and register it
+ localVersion = registerClone(id, aContext, o, this);
+ if (localVersion == null) {
+ throw new WotonomyException("Deleted object could not be serialized: " + id + " : " + o);
+ }
+ } else // we have a local version, copy changes
+ {
+ copy(aContext, o, this, localVersion);
+ // copy marks the object as updated: will be on both lists
+ }
+ // delete our copy -- marks context as changed
+ deleteObject(localVersion);
+ }
+
+ // process inserts - all inserts are new objects
+ List inserts = new NSArray(aContext.insertedObjects());
+ it = inserts.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ // make a local copy and register it
+ EOGlobalID id = aContext.globalIDForObject(o);
+ willChange(); // need to mark editing context as changed
+ Object localVersion = registerClone(id, aContext, o, this);
+ if (localVersion == null) {
+ throw new WotonomyException("Inserted object could not be serialized: " + o);
+ }
+ // insert our copy manually so a new id is not generated
+ insertedObjects.addObject(localVersion);
+ insertedObjectsBuffer.addObject(localVersion);
+ }
+
+ // process updates
+ List updates = new NSArray(aContext.updatedObjects());
+ it = updates.iterator();
+ while (it.hasNext()) {
+ willChange(); // need to mark editing context as changed
+ o = it.next();
+ EOGlobalID id = aContext.globalIDForObject(o);
+ Object localVersion = objectForGlobalID(id);
+ if (localVersion == null) {
+ // make a local copy and register it
+ localVersion = registerClone(id, aContext, o, this);
+ if (localVersion == null) {
+ throw new WotonomyException("Updated object could not be serialized: " + id + " : " + o);
+ }
+ if (id.isTemporary()) {
+ // mark this object as inserted
+ insertedObjects.addObject(localVersion);
+ insertedObjectsBuffer.addObject(localVersion);
+ } else {
+ // mark this object as updated
+ updatedObjects.addObject(localVersion);
+
+ // notify of update only if not on deleted list
+ if (deletedObjectsBuffer.indexOfIdenticalObject(localVersion) == NSArray.NotFound) {
+ updatedObjectsBuffer.addObject(localVersion);
+ }
+ }
+ } else // we have a local version, copy changes
+ {
+ copy(aContext, o, this, localVersion);
+ // copy marks the object as updated
+ }
+ }
+
+ }
+
+ /**
+ * Sets the delegate for this editing context. Note: this implementation retains
+ * only a weak reference to the specified object.
+ */
+ public void setDelegate(Object anObject) {
+ if (anObject == null)
+ delegate = null;
+ delegate = new WeakReference(anObject);
+ }
+
+ /**
+ * Sets the fetch timestamp for this editing context.
+ */
+ public void setFetchTimestamp(double aDouble) {
+ fetchTimestamp = aDouble;
+ }
+
+ /*
+ * public void setInvalidatesObjectsWhenFinalized ( boolean invalidatesObjects )
+ * { throw new net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ *
+ * public void setInvalidatesObjectsWhenFreed ( boolean invalidatesObjects ) {
+ * throw new net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * Sets whether this editing context attempts to lock objects when they are
+ * first modified. Default is false.
+ */
+ public void setLocksObjectsBeforeFirstModification(boolean locksObjects) {
+ lockBeforeModify = locksObjects;
+ }
+
+ /**
+ * Sets the message handler for this editing context. Note: this implementation
+ * retains only a weak reference to the specified object.
+ */
+ public void setMessageHandler(Object anObject) {
+ if (anObject == null)
+ messageHandler = null;
+ messageHandler = new WeakReference(anObject);
+ }
+
+ /**
+ * Sets whether this editing context propagates deletes immediately after the
+ * event that triggered the delete. Otherwise, propagation occurs only before
+ * commit. Default is true.
+ */
+ public void setPropagatesDeletesAtEndOfEvent(boolean propagatesDeletes) {
+ propagateDeletesAfterEvent = propagatesDeletes;
+ }
+
+ /*
+ * public void setSharedEditingContext ( EOSharedEditingContext
+ * aSharedEditingContext ) { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * Sets whether validation is stopped after the first error occurs. Otherwise,
+ * validation will continue for all other objects. Default is true.
+ */
+ public void setStopsValidationAfterFirstError(boolean stopsValidation) {
+ stopValidationAfterError = stopsValidation;
+ }
+
+ /**
+ * Sets the undo manager to be used for this context. Note: This is currently
+ * javax.swing.undo.UndoManager, until we have a implementation of
+ * NSUndoManager.
+ */
+ /*
+ * public void setUndoManager ( UndoManager anUndoManager ) { undoManager =
+ * anUndoManager; }
+ */
+ /*
+ * public EOSharedEditingContext sharedEditingContext () { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * Returns whether validation is stopped after the first error occurs.
+ * Otherwise, validation will continue for all other objects.
+ */
+ public boolean stopsValidationAfterFirstError() {
+ return stopValidationAfterError;
+ }
+
+ /**
+ * Reverts the last change on the undo stack.
+ */
+ public void undo() {
+ // TODO: not supported yet
+ throw new UnsupportedOperationException("Not implemented yet.");
+ }
+
+ /*
+ * public NSUndoManager undoManager () { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+ /**
+ * public void unlock () { throw new net.wotonomy.util.WotonomyException("Not
+ * implemented yet."); }
+ */
+ /**
+ * Returns a read-only list of all objects marked as modified, but not inserted
+ * or deleted, in this editing context.
+ */
+ public NSArray updatedObjects() {
+ return updatedObjectsProxy;
+ }
+
+ /**
+ * Notify editors of changes.
+ */
+ private void fireWillSaveChanges() {
+ Object o = null;
+ Iterator i = editors().iterator();
+ while (i.hasNext()) {
+ try {
+ o = i.next();
+ NSSelector.invoke("editingContextWillSaveChanges", new Class[] { EOEditingContext.class }, o, this);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while notifying editor of pending save: " + o);
+ exc.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Handles notifications from parent store, looking for
+ * InvalidatedAllObjectsInStoreNotification and
+ * ObjectsChangedInStoreNotification. The former causes all objects in this
+ * store to be invalidated. The latter refaults the invalidated ids, merges
+ * changes from the updated ids, and forgets the deleted ids, then posts a
+ * ObjectsChangedInStoreNotification. Note: This method is not in the public
+ * specification.
+ */
+ public void handleNotification(NSNotification aNotification) { // System.out.println( "EOEditingContext: " + this +
+ // " : " + aNotification );
+
+ willChange();
+ if (InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
+ refaultObjects();
+
+ // relay notification
+ NSNotificationCenter.defaultCenter()
+ .postNotification(new NSNotification(InvalidatedAllObjectsInStoreNotification, this));
+ } else if (EOGlobalID.GlobalIDChangedNotification.equals(aNotification.name())) {
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // if any keys in userInfo are registered ids,
+ // re-register with new permanent values.
+
+ Object o;
+ EOGlobalID id;
+ Enumeration e = userInfo.keyEnumerator();
+ while (e.hasMoreElements()) {
+ id = (EOGlobalID) e.nextElement();
+ o = objectForGlobalID(id);
+ if (o != null) {
+ // record object is assumed to handle key updates
+ recordObject(o, (EOGlobalID) userInfo.objectForKey(id));
+ }
+ }
+ } else if (EOObjectStore.ObjectsChangedInStoreNotification.equals(aNotification.name())) {
+ // System.out.println( "EOEditingContext.handleNotification: " + aNotification +
+ // " : " + this );
+ // post so child contexts are notified
+ willChange();
+
+ Object o;
+ EOGlobalID id;
+ Enumeration e;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // inserted objects are ignored
+
+ // existing deleted objects are removed
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ e = deletes.objectEnumerator();
+ while (e.hasMoreElements()) {
+ id = (EOGlobalID) e.nextElement();
+ o = objectForGlobalID(id);
+ if (o != null) {
+ // System.out.println( "EOEditingContext: deleted: " + id );
+ forgetObject(o);
+ deletedObjectsBuffer.addObject(o);
+ deletedIDsBuffer.addObject(id);
+ }
+ }
+
+ // existing updated objects are merged
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ e = updates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ id = (EOGlobalID) e.nextElement();
+ o = objectForGlobalID(id);
+ if (o != null) {
+ // System.out.println( "EOEditingContext: updated: " + id );
+ if (updatedObjects // only update if unchanged
+ .indexOfIdenticalObject(o) == NSArray.NotFound) {
+ refaultObject(o, id, this);
+ updatedObjectsBuffer.addObject(o);
+ } else {
+ // notify user and/or merge
+ handleUpdateConflict(id, o);
+ }
+ }
+ }
+
+ // existing invalidated objects are refaulted
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ e = invalidates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ id = (EOGlobalID) e.nextElement();
+ o = objectForGlobalID(id);
+ if (o != null) {
+ if (updatedObjects // only invalidate if unchanged
+ .indexOfIdenticalObject(o) == NSArray.NotFound) {
+ refaultObject(o, id, this);
+ } else {
+ // notify user and/or merge
+ handleUpdateConflict(id, o);
+ }
+ if (invalidatedObjectsBuffer.indexOfIdenticalObject(o) == NSArray.NotFound) {
+ invalidatedObjectsBuffer.addObject(o);
+ }
+ if (invalidatedIDsBuffer.indexOfIdenticalObject(id) == NSArray.NotFound) {
+ invalidatedIDsBuffer.addObject(id);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Called by handleNotification to resolve the case where we have received
+ * notification that another user or context has updated an object that is
+ * currently marked as edited in this context. This implementation first asks
+ * the delegate if it should merge. If true or no delegate, the changes are
+ * merged. True or false, the delegate is then sent
+ * editingContextDidMergeChanges.
+ */
+ private void handleUpdateConflict(EOGlobalID anID, Object anObject) {
+ // if we're causing the invalidation, ignore
+ // (this is probably better handled by the caller...)
+ if (isInvalidating) {
+ ignoreChanges = true;
+ parentStore.refaultObject(anObject, anID, this);
+ ignoreChanges = false;
+ return;
+ }
+
+ Boolean result = (Boolean) notifyDelegate("editingContextShouldMergeChangesForObject",
+ new Class[] { EOEditingContext.class, Object.class }, new Object[] { this, anObject });
+
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ // do merge
+ mergeExternalChanges(anID, anObject);
+ } else // Boolean.FALSE
+ {
+ // do nothing: don't lose the user's changes
+ }
+
+ // notify merge did happen
+ notifyDelegate("editingContextDidMergeChanges", new Class[] { EOEditingContext.class }, new Object[] { this });
+ }
+
+ /**
+ * For the currently modified object with the specified global id, this method
+ * merges changes with the updated version in the parent object store. This
+ * implementation looks at the fetch snapshot to determine which changes where
+ * made by the user, fetches the updated version of the object, and then
+ * determine what external changes were made. If the changes do not overlap, the
+ * original changes are applied to the updated version. If there is a conflict,
+ * notifies the user of the conflict.
+ */
+ private boolean mergeExternalChanges(EOGlobalID anID, Object anObject) {
+ try {
+ Iterator i;
+ Object key;
+
+ // get fetch snapshot
+ Map fetchSnapshot = committedSnapshotForObject(anObject);
+
+ // get current snapshot
+ Map currentSnapshot = currentEventSnapshotForObject(anObject);
+
+ // diff against fetch snapshot
+ Map currentDiff = new HashMap();
+ i = currentSnapshot.keySet().iterator();
+ while (i.hasNext()) {
+ key = i.next();
+ if (!currentSnapshot.get(key).equals(fetchSnapshot.get(key))) {
+ currentDiff.put(key, currentSnapshot.get(key));
+ }
+ }
+
+ // refault
+ ignoreChanges = true;
+ parentStore.refaultObject(anObject, anID, this);
+ ignoreChanges = false;
+
+ // get updated snapshot
+ Map updatedSnapshot = convertSnapshotToDictionary(takeSnapshot(anObject));
+
+ // diff against fetch snapshot
+ Map updatedDiff = new HashMap();
+ i = updatedSnapshot.keySet().iterator();
+ while (i.hasNext()) {
+ key = i.next();
+ if (!updatedSnapshot.get(key).equals(fetchSnapshot.get(key))) {
+ updatedDiff.put(key, updatedSnapshot.get(key));
+ }
+ }
+
+ // determine if there's a conflict
+ boolean proceed = true;
+ Set updatedKeys = updatedDiff.keySet();
+ i = currentDiff.keySet().iterator();
+ while (i.hasNext()) {
+ if (updatedKeys.contains(i.next())) {
+ proceed = false;
+ break;
+ }
+ }
+
+ // if no conflicts, apply original diff to current object and exit
+ if (proceed) {
+ KeyValueCodingUtilities.takeStoredValuesFromDictionary(anObject, currentDiff);
+ return true; // exit!
+ }
+ } catch (Exception exc) {
+ // log error to standard out
+ exc.printStackTrace();
+ }
+
+ // notify user we're unable to merge
+ notifyMessageHandler(MessageChangeConflict + anObject);
+ return false;
+ }
+
+ /**
+ * Sends the specified message to the message handler.
+ */
+ private void notifyMessageHandler(String aMessage) {
+ Object handler = null;
+ try {
+ handler = messageHandler();
+ if (handler == null)
+ return;
+ NSSelector.invoke("editingContextPresentErrorMessage", new Class[] { EOEditingContext.class, String.class },
+ handler, this, aMessage);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while notifying message handler: " + handler + " : " + aMessage);
+ exc.printStackTrace();
+ }
+ }
+
+ /**
+ * Sends the specified message to the delegate. Returns the return value of the
+ * method, or null if no return value or no delegate or no implementation.
+ */
+ private Object notifyDelegate(String aMethodName, Class[] types, Object[] params) {
+ try {
+ Object delegate = delegate();
+ if (delegate == null)
+ return null;
+ return NSSelector.invoke(aMethodName, types, delegate, params);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while messaging delegate: " + delegate + " : " + aMethodName);
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ // interface EOObserving
+
+ /**
+ * Implementation of the EOObserving interface. Called before objects are
+ * modified.
+ */
+ public void objectWillChange(Object anObject) {
+ if (ignoreChanges)
+ return;
//NSNotificationCenter.defaultCenter().postNotification( "objectWillChange", this, new NSDictionary( "object", anObject ) );
//new RuntimeException().printStackTrace();
- willChange();
-
- // mark as updated if not marked already
- int i = updatedObjects.indexOfIdenticalObject( anObject );
- if ( i == NSArray.NotFound )
- {
- // don't mark inserted objects as updated
- i = insertedObjects.indexOfIdenticalObject( anObject );
- if ( i == NSArray.NotFound )
- {
- i = deletedObjects.indexOfIdenticalObject( anObject );
- if ( i == NSArray.NotFound )
- {
- // add object
- updatedObjects.addObject( anObject );
-
- // record revert snapshot
- registrar.setCommitSnapshot( anObject, takeSnapshot( anObject ) );
- }
- }
- }
-
- // add to buffer
- if ( updatedObjectsBuffer.indexOfIdenticalObject( anObject )
- == NSArray.NotFound )
- {
- updatedObjectsBuffer.addObject( anObject );
- }
- }
-
- // static methods
-
- public static double defaultFetchTimestampLag ()
- {
- return defaultFetchTimestampLag;
- }
-
- /**
- * Returns the default parent object store for all
- * object stores created with the parameterless
- * constructor.
- */
- public static EOObjectStore defaultParentObjectStore ()
- {
- return defaultParentObjectStore;
- }
+ willChange();
+
+ // mark as updated if not marked already
+ int i = updatedObjects.indexOfIdenticalObject(anObject);
+ if (i == NSArray.NotFound) {
+ // don't mark inserted objects as updated
+ i = insertedObjects.indexOfIdenticalObject(anObject);
+ if (i == NSArray.NotFound) {
+ i = deletedObjects.indexOfIdenticalObject(anObject);
+ if (i == NSArray.NotFound) {
+ // add object
+ updatedObjects.addObject(anObject);
+
+ // record revert snapshot
+ registrar.setCommitSnapshot(anObject, takeSnapshot(anObject));
+ }
+ }
+ }
-/*
- public static Object initObjectWithCoder (
- Object anObject,
- NSCoder aCoder )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
+ // add to buffer
+ if (updatedObjectsBuffer.indexOfIdenticalObject(anObject) == NSArray.NotFound) {
+ updatedObjectsBuffer.addObject(anObject);
+ }
+ }
- /**
- * Returns whether editing contexts are configured to retain strong
- * references to their registered objects. If false, editing contexts
- * will only retain weak references to their registered objects.
- */
- public static boolean instancesRetainRegisteredObjects()
- {
- return retainsRegisteredObjects;
- }
-
- /**
- * Sets the global default fetch timestamp lag.
- */
- public static void setDefaultFetchTimestampLag (
- double aDouble )
- {
- defaultFetchTimestampLag = aDouble;
- }
-
- /**
- * Sets the global default parent object store,
- * used for the parameterless constructor.
- */
- public static void setDefaultParentObjectStore (
- EOObjectStore anObjectStore )
- {
- defaultParentObjectStore = anObjectStore;
- }
-
- public static void setInstancesRetainRegisteredObjects (
- boolean retainsObjects )
- {
- retainsRegisteredObjects = retainsObjects;
- }
+ // static methods
-/*
- public static void setSubstitutionEditingContext (
- EOEditingContext aContext)
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-
- public static void setUsesContextRelativeEncoding (
- boolean usesRelativeEncoding )
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-
- public static EOEditingContext substitutionEditingContext ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-
- public static boolean usesContextRelativeEncoding ()
- {
- throw new net.wotonomy.util.WotonomyException("Not implemented yet.");
- }
-*/
+ public static double defaultFetchTimestampLag() {
+ return defaultFetchTimestampLag;
+ }
+
+ /**
+ * Returns the default parent object store for all object stores created with
+ * the parameterless constructor.
+ */
+ public static EOObjectStore defaultParentObjectStore() {
+ return defaultParentObjectStore;
+ }
+
+ /*
+ * public static Object initObjectWithCoder ( Object anObject, NSCoder aCoder )
+ * { throw new net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+
+ /**
+ * Returns whether editing contexts are configured to retain strong references
+ * to their registered objects. If false, editing contexts will only retain weak
+ * references to their registered objects.
+ */
+ public static boolean instancesRetainRegisteredObjects() {
+ return retainsRegisteredObjects;
+ }
+
+ /**
+ * Sets the global default fetch timestamp lag.
+ */
+ public static void setDefaultFetchTimestampLag(double aDouble) {
+ defaultFetchTimestampLag = aDouble;
+ }
+
+ /**
+ * Sets the global default parent object store, used for the parameterless
+ * constructor.
+ */
+ public static void setDefaultParentObjectStore(EOObjectStore anObjectStore) {
+ defaultParentObjectStore = anObjectStore;
+ }
+
+ public static void setInstancesRetainRegisteredObjects(boolean retainsObjects) {
+ retainsRegisteredObjects = retainsObjects;
+ }
+
+ /*
+ * public static void setSubstitutionEditingContext ( EOEditingContext aContext)
+ * { throw new net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ *
+ * public static void setUsesContextRelativeEncoding ( boolean
+ * usesRelativeEncoding ) { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ *
+ * public static EOEditingContext substitutionEditingContext () { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ *
+ * public static boolean usesContextRelativeEncoding () { throw new
+ * net.wotonomy.util.WotonomyException("Not implemented yet."); }
+ */
+
+ public String toString() {
+ return "[EOEditingContext@" + Integer.toHexString(System.identityHashCode(this)) + ":" + " inserted="
+ + idsForObjects(insertedObjects) + " updated=" + idsForObjects(updatedObjects) + " deleted="
+ + idsForObjects(deletedObjects) + " registered=" + registrar.registeredGlobalIDs() + " ]";
+ }
+
+ private List idsForObjects(List objects) {
+ List result = new LinkedList();
+ Iterator i = objects.iterator();
+ while (i.hasNext())
+ result.add(globalIDForObject(i.next()));
+ return result;
+ }
- public String toString()
- {
- return "[EOEditingContext@"+Integer.toHexString(System.identityHashCode(this))+":"+
- " inserted="+idsForObjects(insertedObjects)+
- " updated="+idsForObjects(updatedObjects)+
- " deleted="+idsForObjects(deletedObjects)+
- " registered="+registrar.registeredGlobalIDs()+" ]";
- }
- private List idsForObjects( List objects )
- {
- List result = new LinkedList();
- Iterator i = objects.iterator();
- while ( i.hasNext() ) result.add( globalIDForObject( i.next() ) );
- return result;
- }
-
- // snapshots
-
- /**
- * Returns a NSDictionary containing only the mutable properties
- * for the specified object and deep clones of their values.
- * Nulls are represented by NSNull.nullValue().
- */
- private byte[] takeSnapshot( Object anObject )
- { // System.out.println( "takeSnapshot: " + anObject );
- return KeyValueCodingUtilities.freeze( anObject, this, anObject, true );
- }
-
- /**
- * Applies the map of properties and values to the
- * specified object. Null values for properties must
- * be represented by the NSNull.nullValue().
- * Posts a willChange event before applying changes.
- */
- private void applySnapshot( byte[] aSnapshot, Object anObject )
- {
- // must clone snapshot to avoid changing existing snapshot
- NSDictionary values = convertSnapshotToDictionary( aSnapshot );
+ // snapshots
+
+ /**
+ * Returns a NSDictionary containing only the mutable properties for the
+ * specified object and deep clones of their values. Nulls are represented by
+ * NSNull.nullValue().
+ */
+ private byte[] takeSnapshot(Object anObject) { // System.out.println( "takeSnapshot: " + anObject );
+ return KeyValueCodingUtilities.freeze(anObject, this, anObject, true);
+ }
+
+ /**
+ * Applies the map of properties and values to the specified object. Null values
+ * for properties must be represented by the NSNull.nullValue(). Posts a
+ * willChange event before applying changes.
+ */
+ private void applySnapshot(byte[] aSnapshot, Object anObject) {
+ // must clone snapshot to avoid changing existing snapshot
+ NSDictionary values = convertSnapshotToDictionary(aSnapshot);
//System.out.println( "applySnapshot: " + aSnapshot + " : " + values );
//ignoreChanges = true;
- willChange();
- KeyValueCodingUtilities.takeStoredValuesFromDictionary( anObject, values );
+ willChange();
+ KeyValueCodingUtilities.takeStoredValuesFromDictionary(anObject, values);
//ignoreChanges = false;
- }
-
- /**
- * Snapshots are stored internally in binary format,
- * but exposed to the user as NSDictionaries.
- */
- private NSDictionary convertSnapshotToDictionary( byte[] aSnapshot )
- {
- // get the object
- Object clone = KeyValueCodingUtilities.thaw( aSnapshot, this, true );
- // get all keys for this object
- EOClassDescription classDesc =
- EOClassDescription.classDescriptionForClass( clone.getClass() );
- List keys = new LinkedList();
- keys.addAll( classDesc.attributeKeys() );
- keys.addAll( classDesc.toOneRelationshipKeys() );
- keys.addAll( classDesc.toManyRelationshipKeys() );
-
- return KeyValueCodingUtilities.valuesForKeys( clone, keys );
- }
- /**
- * Creates a deep clone of the specified object.
- * (Object.clone() only creates a shallow clone.)
- * Returns null if operation fails.
- */
- static private Object clone(
- EOEditingContext aSourceContext,
- Object aSource,
- EOEditingContext aDestinationContext )
- { // System.out.println( "clone: " + aSource );
- return KeyValueCodingUtilities.clone(
- aSourceContext, aSource, aDestinationContext );
- }
-
- /**
- * Creates a deep clone of the specified object.
- * but does not transpose references. This allows
- * us to register an object before transposing
- * references so that child objects will be able
- * to resolve references to their parent.
- * After recording the object, we copy the source
- * object into the clone, which does transpose
- * and resolve properly.
- * Returns null if operation fails.
- */
- static private Object registerClone(
- EOGlobalID aGlobalID,
- EOEditingContext aSourceContext,
- Object aSource,
- EOEditingContext aDestinationContext )
- {
- // while we'd like to just transpose/clone at the same time
- // we must record a clone without transposing: this
- // avoids a endless loop if the object graph has a cycle
- Object clone = KeyValueCodingUtilities.thaw(
- KeyValueCodingUtilities.freeze(
- aSource, aSourceContext, aSource, false ),
- aDestinationContext, false );
-
- aDestinationContext.recordObject( clone, aGlobalID );
-
- // need to copy to transpose references into this context
- // while preserving the same instance of the object
- aDestinationContext.ignoreChanges = true;
- copy( aSourceContext, aSource, aDestinationContext, clone );
- aDestinationContext.ignoreChanges = false;
-
- // return our clone
- return clone;
- }
-
- /**
- * Copies values from one object to another.
- * Returns the destination object, or throws exception
- * if operation fails.
- */
- static private Object copy(
- EOEditingContext aSourceContext,
- Object aSource,
- EOEditingContext aDestinationContext,
- Object aDestination )
- { // System.out.println( "copy: " );
- EOObserverCenter.notifyObserversObjectWillChange( aDestination );
- KeyValueCodingUtilities.copy( aSourceContext, aSource, aDestinationContext, aDestination );
- return aDestination;
- }
-
- // process recent changes
-
- /**
- * Called to notify observers of changes.
- * Also calls runLater().
- */
- private void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- runLater();
- }
-
- /**
- * Called to ensure that processRecentChanges
- * will be called on the next event loop.
- */
- private void runLater()
- {
- if ( ! willRunLater )
- {
+ }
+
+ /**
+ * Snapshots are stored internally in binary format, but exposed to the user as
+ * NSDictionaries.
+ */
+ private NSDictionary convertSnapshotToDictionary(byte[] aSnapshot) {
+ // get the object
+ Object clone = KeyValueCodingUtilities.thaw(aSnapshot, this, true);
+ // get all keys for this object
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForClass(clone.getClass());
+ List keys = new LinkedList();
+ keys.addAll(classDesc.attributeKeys());
+ keys.addAll(classDesc.toOneRelationshipKeys());
+ keys.addAll(classDesc.toManyRelationshipKeys());
+
+ return KeyValueCodingUtilities.valuesForKeys(clone, keys);
+ }
+
+ /**
+ * Creates a deep clone of the specified object. (Object.clone() only creates a
+ * shallow clone.) Returns null if operation fails.
+ */
+ static private Object clone(EOEditingContext aSourceContext, Object aSource, EOEditingContext aDestinationContext) { // System.out.println(
+ // "clone:
+ // "
+ // +
+ // aSource
+ // );
+ return KeyValueCodingUtilities.clone(aSourceContext, aSource, aDestinationContext);
+ }
+
+ /**
+ * Creates a deep clone of the specified object. but does not transpose
+ * references. This allows us to register an object before transposing
+ * references so that child objects will be able to resolve references to their
+ * parent. After recording the object, we copy the source object into the clone,
+ * which does transpose and resolve properly. Returns null if operation fails.
+ */
+ static private Object registerClone(EOGlobalID aGlobalID, EOEditingContext aSourceContext, Object aSource,
+ EOEditingContext aDestinationContext) {
+ // while we'd like to just transpose/clone at the same time
+ // we must record a clone without transposing: this
+ // avoids a endless loop if the object graph has a cycle
+ Object clone = KeyValueCodingUtilities.thaw(
+ KeyValueCodingUtilities.freeze(aSource, aSourceContext, aSource, false), aDestinationContext, false);
+
+ aDestinationContext.recordObject(clone, aGlobalID);
+
+ // need to copy to transpose references into this context
+ // while preserving the same instance of the object
+ aDestinationContext.ignoreChanges = true;
+ copy(aSourceContext, aSource, aDestinationContext, clone);
+ aDestinationContext.ignoreChanges = false;
+
+ // return our clone
+ return clone;
+ }
+
+ /**
+ * Copies values from one object to another. Returns the destination object, or
+ * throws exception if operation fails.
+ */
+ static private Object copy(EOEditingContext aSourceContext, Object aSource, EOEditingContext aDestinationContext,
+ Object aDestination) { // System.out.println( "copy: " );
+ EOObserverCenter.notifyObserversObjectWillChange(aDestination);
+ KeyValueCodingUtilities.copy(aSourceContext, aSource, aDestinationContext, aDestination);
+ return aDestination;
+ }
+
+ // process recent changes
+
+ /**
+ * Called to notify observers of changes. Also calls runLater().
+ */
+ private void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ runLater();
+ }
+
+ /**
+ * Called to ensure that processRecentChanges will be called on the next event
+ * loop.
+ */
+ private void runLater() {
+ if (!willRunLater) {
willRunLater = true;
- NSRunLoop.currentRunLoop().performSelectorWithOrder(
- runLaterSelector, this, null, EditingContextFlushChangesRunLoopOrdering, null );
+ NSRunLoop.currentRunLoop().performSelectorWithOrder(runLaterSelector, this, null,
+ EditingContextFlushChangesRunLoopOrdering, null);
}
}
-
+
/**
- * This method is called by the event queue run loop
- * and calls processRecentChanges.
- * NOTE: This method is not part of the specification.
- */
- public void flushRecentChanges( Object anObject )
- {
+ * This method is called by the event queue run loop and calls
+ * processRecentChanges. NOTE: This method is not part of the specification.
+ */
+ public void flushRecentChanges(Object anObject) {
//System.out.println( "EODelayedObserverQueue: running" );
- processRecentChanges();
+ processRecentChanges();
willRunLater = false;
}
-
- // inner classes
-
- /**
- * Gatekeeper for all access to registered objects.
- */
- static private class Registrar
- {
- EOEditingContext context;
- NSMutableDictionary IDsToObjects;
- NSMutableDictionary objectsToIDs;
- NSMutableDictionary objectsToCommitSnapshots;
- NSMutableDictionary objectsToCurrentSnapshots;
-
- ReferenceKey comparisonKey; //FIXME not thread safe!
-
- public Registrar( EOEditingContext aContext )
- {
- context = aContext;
- IDsToObjects = new NSMutableDictionary();
- objectsToIDs = new NSMutableDictionary();
- objectsToCommitSnapshots = new NSMutableDictionary();
- objectsToCurrentSnapshots = new NSMutableDictionary();
- comparisonKey = new ReferenceKey();
- }
-
- public NSArray registeredObjects()
- {
- return IDsToObjects.allValues();
- }
-
- public NSArray registeredGlobalIDs()
- {
- return IDsToObjects.allKeys();
- }
-
- public Object objectForGlobalID( EOGlobalID aGlobalID )
- {
- return IDsToObjects.objectForKey( aGlobalID );
- }
-
- public EOGlobalID globalIDForObject( Object anObject )
- {
- comparisonKey.set( anObject );
- return (EOGlobalID) objectsToIDs.objectForKey( comparisonKey );
- }
-
- public byte[] getCommitSnapshot( Object anObject )
- {
- comparisonKey.set( anObject );
- return (byte[]) objectsToCommitSnapshots.objectForKey( comparisonKey );
- }
-
- public void setCommitSnapshot( Object anObject, byte[] aSnapshot )
- {
- if ( aSnapshot == null )
- {
- comparisonKey.set( anObject );
- objectsToCommitSnapshots.removeObjectForKey( comparisonKey );
- }
- else
- {
- objectsToCommitSnapshots.setObjectForKey(
- aSnapshot, new ReferenceKey( anObject ) );
- }
- }
-
- public byte[] getCurrentSnapshot( Object anObject )
- {
- comparisonKey.set( anObject );
- return (byte[]) objectsToCurrentSnapshots.objectForKey( comparisonKey );
- }
-
- public void setCurrentSnapshot( Object anObject, byte[] aSnapshot )
- {
- if ( aSnapshot == null )
- {
- comparisonKey.set( anObject );
- objectsToCurrentSnapshots.removeObjectForKey( comparisonKey );
- }
- else
- {
- objectsToCurrentSnapshots.setObjectForKey(
- aSnapshot, new ReferenceKey( anObject ) );
- }
- }
-
- public void registerObject( Object anObject, EOGlobalID aGlobalID )
- {
- IDsToObjects.setObjectForKey( anObject, aGlobalID );
- objectsToIDs.setObjectForKey( aGlobalID, new ReferenceKey( anObject ) );
- EOObserverCenter.addObserver( context, anObject );
- }
-
- public void forgetObject( Object anObject )
- {
- comparisonKey.set( anObject );
- Object id = objectsToIDs.objectForKey( comparisonKey );
- IDsToObjects.removeObjectForKey( id );
- objectsToIDs.removeObjectForKey( comparisonKey );
- EOObserverCenter.removeObserver( context, anObject );
- }
-
- public void disposeSnapshots( Object anObject )
- {
- setCommitSnapshot( anObject, null );
- setCurrentSnapshot( anObject, null );
- }
-
- }
-
- /**
- * Registrar that uses only WeakReferences.
- * Used if retainsRegisteredObjects is false.
- */
- static private class WeakRegistrar extends Registrar
- {
- private WeakReferenceKey weakComparisonKey; //FIXME not thread safe!
-
- public WeakRegistrar( EOEditingContext aContext )
- {
- super( aContext );
- weakComparisonKey = new WeakReferenceKey();
- }
-
- public NSArray registeredObjects()
- {
- Object object;
- WeakReferenceKey weakKey;
- NSMutableArray result = new NSMutableArray();
- Enumeration e = new NSArray( objectsToIDs.allKeys() ).objectEnumerator();
- while ( e.hasMoreElements() )
- {
- weakKey = (WeakReferenceKey) e.nextElement();
- object = weakKey.get();
- if ( object != null )
- {
- result.addObject( object );
- }
- else
- {
- // object has been released: perform cleanup
- disposeObject( null, weakKey );
- }
- }
- return result;
- }
-
- public Object objectForGlobalID( EOGlobalID aGlobalID )
- {
- WeakReference ref = (WeakReference) super.objectForGlobalID( aGlobalID );
- if ( ref == null ) return null;
- Object result = ref.get();
- if ( result == null )
- {
- // clean up manually
- IDsToObjects.removeObjectForKey( aGlobalID );
- Iterator i = new LinkedList( objectsToIDs.allKeysForObject( ref ) ).iterator();
- while ( i.hasNext() )
- {
- objectsToIDs.removeObjectForKey( i.next() );
- }
- disposeSnapshots( aGlobalID );
- }
- return result;
- }
-
- public byte[] getCommitSnapshot( Object anObject )
- {
- weakComparisonKey.set( anObject );
- return (byte[]) objectsToCommitSnapshots.objectForKey( weakComparisonKey );
- }
-
- public void setCommitSnapshot( Object anObject, byte[] aSnapshot )
- {
- if ( aSnapshot == null )
- {
- weakComparisonKey.set( anObject );
- objectsToCommitSnapshots.removeObjectForKey( weakComparisonKey );
- }
- else
- {
- objectsToCommitSnapshots.setObjectForKey(
- aSnapshot, new WeakReferenceKey( anObject ) );
- }
- }
-
- public byte[] getCurrentSnapshot( Object anObject )
- {
- weakComparisonKey.set( anObject );
- return (byte[]) objectsToCurrentSnapshots.objectForKey( weakComparisonKey );
- }
-
- public void setCurrentSnapshot( Object anObject, byte[] aSnapshot )
- {
- if ( aSnapshot == null )
- {
- weakComparisonKey.set( anObject );
- objectsToCurrentSnapshots.removeObjectForKey( weakComparisonKey );
- }
- else
- {
- objectsToCurrentSnapshots.setObjectForKey(
- aSnapshot, new WeakReferenceKey( anObject ) );
- }
- }
-
- public void registerObject( Object anObject, EOGlobalID aGlobalID )
- { // new net.wotonomy.ui.swing.ReferenceInspector( anObject );
- IDsToObjects.setObjectForKey( new WeakReference( anObject ), aGlobalID );
- objectsToIDs.setObjectForKey( aGlobalID, new WeakReferenceKey( anObject ) );
- EOObserverCenter.addObserver( context, anObject );
- }
-
- public void forgetObject( Object anObject )
- {
- disposeObject( anObject, null );
- }
-
- // must specify one or the other
- private void disposeObject( Object anObject, WeakReferenceKey key )
- {
- if ( key == null ) key = new WeakReferenceKey( anObject );
- EOGlobalID id = (EOGlobalID) objectsToIDs.objectForKey( key );
- if ( id != null ) IDsToObjects.removeObjectForKey( id );
- objectsToIDs.removeObjectForKey( key );
- disposeSnapshots( id );
- if ( anObject != null )
- {
- EOObserverCenter.removeObserver( context, anObject );
- }
- }
- }
-
- /**
- * Private class used to force a hashmap to
- * perform key comparisons by reference.
- */
- static private class ReferenceKey
- {
- int hashCode;
- Object referent;
-
- public ReferenceKey()
- {
- referent = null;
- hashCode = -1;
- }
-
- public ReferenceKey( Object anObject )
- {
- set( anObject );
- }
-
- public Object get()
- {
- return referent;
- }
-
- public void set( Object anObject )
- {
- referent = anObject;
- hashCode = anObject.hashCode();
- }
-
- /**
- * Returns the actual key's hash code.
- */
- public int hashCode()
- {
- return hashCode;
- }
-
- /**
- * Compares by reference.
- */
- public boolean equals( Object anObject )
- {
- if ( anObject == this ) return true;
- if ( anObject instanceof ReferenceKey )
- {
- return ((ReferenceKey)anObject).get() == referent;
- }
- return false;
- }
- }
-
- /**
- * Private class used to force a hashmap to
- * perform key comparisons by reference.
- */
- static private class WeakReferenceKey extends ReferenceKey
- {
- public WeakReferenceKey()
- {
- super();
- }
-
- public WeakReferenceKey( Object anObject )
- {
- super( anObject );
- }
-
- public Object get()
- {
- return ((WeakReference)referent).get();
- }
-
- public void set( Object anObject )
- {
- referent = new WeakReference( anObject );
- hashCode = anObject.hashCode();
- }
-
- /**
- * Compares by reference.
- */
- public boolean equals( Object anObject )
- {
- if ( anObject == this ) return true;
- if ( anObject instanceof ReferenceKey )
- {
- return ((ReferenceKey)anObject).get() == get();
- }
- return false;
- }
- }
-
- /**
- * Key combining an object with a string.
- * Object is compared by reference.
- */
- static private class CompoundKey
- {
- private Object object;
- private String string;
- private int hashCode;
-
- /**
- * Creates compound key.
- * Neither name nor object may be null.
- */
- public CompoundKey (
- Object anObject, String aString )
- {
- object = anObject;
- string = aString;
- hashCode = object.hashCode() + string.hashCode();
- }
-
- public int hashCode()
- {
- return hashCode;
- }
-
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof CompoundKey )
- {
- CompoundKey key = (CompoundKey) anObject;
- return ( ( key.object == object ) && ( key.string.equals( string ) ) );
- }
- return false;
- }
-
- public String toString()
- {
- return "[CompoundKey:"+object+":"+string+"]";
- }
- }
-
- /**
- * Used by EditingContext to delegate behavior to another class.
- * Note that EditingContext doesn't require its delegates to implement
- * this interface: rather, this interface defines the methods that
- * EditingContext will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface Delegate
- {
- /**
- * Called after the editing context has completed merge operations
- * on one or more objects after receiving an ObjectChangedInStore
- * notification.
- */
- void editingContextDidMergeChanges(
- EOEditingContext anEditingContext );
-
- /**
- * Called by objectsWithFetchSpecification.
- * If null, the editing context will pass the fetch specification
- * on to its parent store, as normal. Otherwise, the context
- * will use the returned array to service the request.
- */
- NSArray editingContextShouldFetchObjects(
- EOEditingContext anEditingContext,
- EOFetchSpecification fetchSpecification );
-
- /**
- * Called to determine whether an object should be invalidated.
- * Return false to prevent the object from being invalidated.
- * Default is true.
- */
- boolean editingContextShouldInvalidateObject(
- EOEditingContext anEditingContext,
- Object anObject,
- EOGlobalID aGlobalID );
-
- /**
- * Called to determine whether the editing context should attempt
- * to merge changes in the specified object that the parent store
- * says has changed via an ObjectChangedInStore notification.
- * Default is true. Return false if you wish to handle the merge
- * yourself, by extracting the values in the object now and comparing
- * them to the values when editingContextDidMergeChanges is called.
- */
- boolean editingContextShouldMergeChangesForObject(
- EOEditingContext anEditingContext,
- Object anObject );
-
- /**
- * Returns whether the editing context should ask its message handler
- * to display a message. Return false if the delegate will display the error.
- * Default is true.
- */
- boolean editingContextShouldPresentException(
- EOEditingContext anEditingContext,
- Throwable exception );
-
- /**
- * Returns whether the editing context should undo the most
- * recent set of changes that resulted in a validation failure.
- * Default is true.
- */
- boolean editingContextShouldUndoUserActionsAfterFailure(
- EOEditingContext anEditingContext );
-
- /**
- * Returns whether the editing context should validate the
- * most recent set of changes. Default is true.
- */
- boolean editingContextShouldValidateChanges(
- EOEditingContext anEditingContext );
-
- /**
- * Called before the editing context saves its changes
- * to the parent object store.
- */
- void editingContextWillSaveChanges(
- EOEditingContext anEditingContext );
-
- }
-
- /**
- * Editors register themselves with the editing context
- * so that they may receive notification before the context
- * commits changes. This is useful for associations whose
- * components do not immediately commit their changes to
- * the object they are editing.
- */
- public interface Editor
- {
- /**
- * Called before the editing context saves its changes
- * to the parent object store.
- */
- void editingContextWillSaveChanges(
- EOEditingContext anEditingContext );
-
- /**
- * Called to determine whether this editor has changes
- * that have not been committed to the object in the context.
- */
- boolean editorHasChangesForEditingContext(
- EOEditingContext anEditingContext );
-
- }
-
- /**
- * Used by EditingContext to delegate messaging handling to another class,
- * typically the display group that has the currently active association.
- * Note that EditingContext doesn't require its message handlers to implement
- * this interface: rather, this interface defines the methods that
- * EditingContext will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface MessageHandler
- {
- /**
- * Called to display a message for an error that occurred
- * in the specified editing context.
- */
- void editingContextPresentErrorMessage(
- EOEditingContext anEditingContext,
- String aMessage );
-
- /**
- * Called by the specified object store to determine whether
- * fetching should continue, where count is the current count
- * and limit is the limit as specified by the fetch specification.
- * Default is false.
- */
- boolean editingContextShouldContinueFetching(
- EOEditingContext anEditingContext,
- int count,
- int limit,
- EOObjectStore anObjectStore );
-
- }
-
+
+ // inner classes
+
+ /**
+ * Gatekeeper for all access to registered objects.
+ */
+ static private class Registrar {
+ EOEditingContext context;
+ NSMutableDictionary IDsToObjects;
+ NSMutableDictionary objectsToIDs;
+ NSMutableDictionary objectsToCommitSnapshots;
+ NSMutableDictionary objectsToCurrentSnapshots;
+
+ ReferenceKey comparisonKey; // FIXME not thread safe!
+
+ public Registrar(EOEditingContext aContext) {
+ context = aContext;
+ IDsToObjects = new NSMutableDictionary();
+ objectsToIDs = new NSMutableDictionary();
+ objectsToCommitSnapshots = new NSMutableDictionary();
+ objectsToCurrentSnapshots = new NSMutableDictionary();
+ comparisonKey = new ReferenceKey();
+ }
+
+ public NSArray registeredObjects() {
+ return IDsToObjects.allValues();
+ }
+
+ public NSArray registeredGlobalIDs() {
+ return IDsToObjects.allKeys();
+ }
+
+ public Object objectForGlobalID(EOGlobalID aGlobalID) {
+ return IDsToObjects.objectForKey(aGlobalID);
+ }
+
+ public EOGlobalID globalIDForObject(Object anObject) {
+ comparisonKey.set(anObject);
+ return (EOGlobalID) objectsToIDs.objectForKey(comparisonKey);
+ }
+
+ public byte[] getCommitSnapshot(Object anObject) {
+ comparisonKey.set(anObject);
+ return (byte[]) objectsToCommitSnapshots.objectForKey(comparisonKey);
+ }
+
+ public void setCommitSnapshot(Object anObject, byte[] aSnapshot) {
+ if (aSnapshot == null) {
+ comparisonKey.set(anObject);
+ objectsToCommitSnapshots.removeObjectForKey(comparisonKey);
+ } else {
+ objectsToCommitSnapshots.setObjectForKey(aSnapshot, new ReferenceKey(anObject));
+ }
+ }
+
+ public byte[] getCurrentSnapshot(Object anObject) {
+ comparisonKey.set(anObject);
+ return (byte[]) objectsToCurrentSnapshots.objectForKey(comparisonKey);
+ }
+
+ public void setCurrentSnapshot(Object anObject, byte[] aSnapshot) {
+ if (aSnapshot == null) {
+ comparisonKey.set(anObject);
+ objectsToCurrentSnapshots.removeObjectForKey(comparisonKey);
+ } else {
+ objectsToCurrentSnapshots.setObjectForKey(aSnapshot, new ReferenceKey(anObject));
+ }
+ }
+
+ public void registerObject(Object anObject, EOGlobalID aGlobalID) {
+ IDsToObjects.setObjectForKey(anObject, aGlobalID);
+ objectsToIDs.setObjectForKey(aGlobalID, new ReferenceKey(anObject));
+ EOObserverCenter.addObserver(context, anObject);
+ }
+
+ public void forgetObject(Object anObject) {
+ comparisonKey.set(anObject);
+ Object id = objectsToIDs.objectForKey(comparisonKey);
+ IDsToObjects.removeObjectForKey(id);
+ objectsToIDs.removeObjectForKey(comparisonKey);
+ EOObserverCenter.removeObserver(context, anObject);
+ }
+
+ public void disposeSnapshots(Object anObject) {
+ setCommitSnapshot(anObject, null);
+ setCurrentSnapshot(anObject, null);
+ }
+
+ }
+
+ /**
+ * Registrar that uses only WeakReferences. Used if retainsRegisteredObjects is
+ * false.
+ */
+ static private class WeakRegistrar extends Registrar {
+ private WeakReferenceKey weakComparisonKey; // FIXME not thread safe!
+
+ public WeakRegistrar(EOEditingContext aContext) {
+ super(aContext);
+ weakComparisonKey = new WeakReferenceKey();
+ }
+
+ public NSArray registeredObjects() {
+ Object object;
+ WeakReferenceKey weakKey;
+ NSMutableArray result = new NSMutableArray();
+ Enumeration e = new NSArray(objectsToIDs.allKeys()).objectEnumerator();
+ while (e.hasMoreElements()) {
+ weakKey = (WeakReferenceKey) e.nextElement();
+ object = weakKey.get();
+ if (object != null) {
+ result.addObject(object);
+ } else {
+ // object has been released: perform cleanup
+ disposeObject(null, weakKey);
+ }
+ }
+ return result;
+ }
+
+ public Object objectForGlobalID(EOGlobalID aGlobalID) {
+ WeakReference ref = (WeakReference) super.objectForGlobalID(aGlobalID);
+ if (ref == null)
+ return null;
+ Object result = ref.get();
+ if (result == null) {
+ // clean up manually
+ IDsToObjects.removeObjectForKey(aGlobalID);
+ Iterator i = new LinkedList(objectsToIDs.allKeysForObject(ref)).iterator();
+ while (i.hasNext()) {
+ objectsToIDs.removeObjectForKey(i.next());
+ }
+ disposeSnapshots(aGlobalID);
+ }
+ return result;
+ }
+
+ public byte[] getCommitSnapshot(Object anObject) {
+ weakComparisonKey.set(anObject);
+ return (byte[]) objectsToCommitSnapshots.objectForKey(weakComparisonKey);
+ }
+
+ public void setCommitSnapshot(Object anObject, byte[] aSnapshot) {
+ if (aSnapshot == null) {
+ weakComparisonKey.set(anObject);
+ objectsToCommitSnapshots.removeObjectForKey(weakComparisonKey);
+ } else {
+ objectsToCommitSnapshots.setObjectForKey(aSnapshot, new WeakReferenceKey(anObject));
+ }
+ }
+
+ public byte[] getCurrentSnapshot(Object anObject) {
+ weakComparisonKey.set(anObject);
+ return (byte[]) objectsToCurrentSnapshots.objectForKey(weakComparisonKey);
+ }
+
+ public void setCurrentSnapshot(Object anObject, byte[] aSnapshot) {
+ if (aSnapshot == null) {
+ weakComparisonKey.set(anObject);
+ objectsToCurrentSnapshots.removeObjectForKey(weakComparisonKey);
+ } else {
+ objectsToCurrentSnapshots.setObjectForKey(aSnapshot, new WeakReferenceKey(anObject));
+ }
+ }
+
+ public void registerObject(Object anObject, EOGlobalID aGlobalID) { // new
+ // net.wotonomy.ui.swing.ReferenceInspector(
+ // anObject );
+ IDsToObjects.setObjectForKey(new WeakReference(anObject), aGlobalID);
+ objectsToIDs.setObjectForKey(aGlobalID, new WeakReferenceKey(anObject));
+ EOObserverCenter.addObserver(context, anObject);
+ }
+
+ public void forgetObject(Object anObject) {
+ disposeObject(anObject, null);
+ }
+
+ // must specify one or the other
+ private void disposeObject(Object anObject, WeakReferenceKey key) {
+ if (key == null)
+ key = new WeakReferenceKey(anObject);
+ EOGlobalID id = (EOGlobalID) objectsToIDs.objectForKey(key);
+ if (id != null)
+ IDsToObjects.removeObjectForKey(id);
+ objectsToIDs.removeObjectForKey(key);
+ disposeSnapshots(id);
+ if (anObject != null) {
+ EOObserverCenter.removeObserver(context, anObject);
+ }
+ }
+ }
+
+ /**
+ * Private class used to force a hashmap to perform key comparisons by
+ * reference.
+ */
+ static private class ReferenceKey {
+ int hashCode;
+ Object referent;
+
+ public ReferenceKey() {
+ referent = null;
+ hashCode = -1;
+ }
+
+ public ReferenceKey(Object anObject) {
+ set(anObject);
+ }
+
+ public Object get() {
+ return referent;
+ }
+
+ public void set(Object anObject) {
+ referent = anObject;
+ hashCode = anObject.hashCode();
+ }
+
+ /**
+ * Returns the actual key's hash code.
+ */
+ public int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Compares by reference.
+ */
+ public boolean equals(Object anObject) {
+ if (anObject == this)
+ return true;
+ if (anObject instanceof ReferenceKey) {
+ return ((ReferenceKey) anObject).get() == referent;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Private class used to force a hashmap to perform key comparisons by
+ * reference.
+ */
+ static private class WeakReferenceKey extends ReferenceKey {
+ public WeakReferenceKey() {
+ super();
+ }
+
+ public WeakReferenceKey(Object anObject) {
+ super(anObject);
+ }
+
+ public Object get() {
+ return ((WeakReference) referent).get();
+ }
+
+ public void set(Object anObject) {
+ referent = new WeakReference(anObject);
+ hashCode = anObject.hashCode();
+ }
+
+ /**
+ * Compares by reference.
+ */
+ public boolean equals(Object anObject) {
+ if (anObject == this)
+ return true;
+ if (anObject instanceof ReferenceKey) {
+ return ((ReferenceKey) anObject).get() == get();
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Key combining an object with a string. Object is compared by reference.
+ */
+ static private class CompoundKey {
+ private Object object;
+ private String string;
+ private int hashCode;
+
+ /**
+ * Creates compound key. Neither name nor object may be null.
+ */
+ public CompoundKey(Object anObject, String aString) {
+ object = anObject;
+ string = aString;
+ hashCode = object.hashCode() + string.hashCode();
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public boolean equals(Object anObject) {
+ if (anObject instanceof CompoundKey) {
+ CompoundKey key = (CompoundKey) anObject;
+ return ((key.object == object) && (key.string.equals(string)));
+ }
+ return false;
+ }
+
+ public String toString() {
+ return "[CompoundKey:" + object + ":" + string + "]";
+ }
+ }
+
+ /**
+ * Used by EditingContext to delegate behavior to another class. Note that
+ * EditingContext doesn't require its delegates to implement this interface:
+ * rather, this interface defines the methods that EditingContext will attempt
+ * to invoke dynamically on its delegate. The delegate may choose to implement
+ * only a subset of the methods on the interface.
+ */
+ public interface Delegate {
+ /**
+ * Called after the editing context has completed merge operations on one or
+ * more objects after receiving an ObjectChangedInStore notification.
+ */
+ void editingContextDidMergeChanges(EOEditingContext anEditingContext);
+
+ /**
+ * Called by objectsWithFetchSpecification. If null, the editing context will
+ * pass the fetch specification on to its parent store, as normal. Otherwise,
+ * the context will use the returned array to service the request.
+ */
+ NSArray editingContextShouldFetchObjects(EOEditingContext anEditingContext,
+ EOFetchSpecification fetchSpecification);
+
+ /**
+ * Called to determine whether an object should be invalidated. Return false to
+ * prevent the object from being invalidated. Default is true.
+ */
+ boolean editingContextShouldInvalidateObject(EOEditingContext anEditingContext, Object anObject,
+ EOGlobalID aGlobalID);
+
+ /**
+ * Called to determine whether the editing context should attempt to merge
+ * changes in the specified object that the parent store says has changed via an
+ * ObjectChangedInStore notification. Default is true. Return false if you wish
+ * to handle the merge yourself, by extracting the values in the object now and
+ * comparing them to the values when editingContextDidMergeChanges is called.
+ */
+ boolean editingContextShouldMergeChangesForObject(EOEditingContext anEditingContext, Object anObject);
+
+ /**
+ * Returns whether the editing context should ask its message handler to display
+ * a message. Return false if the delegate will display the error. Default is
+ * true.
+ */
+ boolean editingContextShouldPresentException(EOEditingContext anEditingContext, Throwable exception);
+
+ /**
+ * Returns whether the editing context should undo the most recent set of
+ * changes that resulted in a validation failure. Default is true.
+ */
+ boolean editingContextShouldUndoUserActionsAfterFailure(EOEditingContext anEditingContext);
+
+ /**
+ * Returns whether the editing context should validate the most recent set of
+ * changes. Default is true.
+ */
+ boolean editingContextShouldValidateChanges(EOEditingContext anEditingContext);
+
+ /**
+ * Called before the editing context saves its changes to the parent object
+ * store.
+ */
+ void editingContextWillSaveChanges(EOEditingContext anEditingContext);
+
+ }
+
+ /**
+ * Editors register themselves with the editing context so that they may receive
+ * notification before the context commits changes. This is useful for
+ * associations whose components do not immediately commit their changes to the
+ * object they are editing.
+ */
+ public interface Editor {
+ /**
+ * Called before the editing context saves its changes to the parent object
+ * store.
+ */
+ void editingContextWillSaveChanges(EOEditingContext anEditingContext);
+
+ /**
+ * Called to determine whether this editor has changes that have not been
+ * committed to the object in the context.
+ */
+ boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext);
+
+ }
+
+ /**
+ * Used by EditingContext to delegate messaging handling to another class,
+ * typically the display group that has the currently active association. Note
+ * that EditingContext doesn't require its message handlers to implement this
+ * interface: rather, this interface defines the methods that EditingContext
+ * will attempt to invoke dynamically on its delegate. The delegate may choose
+ * to implement only a subset of the methods on the interface.
+ */
+ public interface MessageHandler {
+ /**
+ * Called to display a message for an error that occurred in the specified
+ * editing context.
+ */
+ void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage);
+
+ /**
+ * Called by the specified object store to determine whether fetching should
+ * continue, where count is the current count and limit is the limit as
+ * specified by the fetch specification. Default is false.
+ */
+ boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit,
+ EOObjectStore anObjectStore);
+
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.86 2003/12/18 15:37:38 mpowers
- * Changes to retain ability to work with objects that don't necessarily
- * implement EOEnterpriseObject. I would still like to preserve this case
- * for general usage, however the access package is free to assume that
- * those objects will be EOs and cast appropriately.
+ * Revision 1.86 2003/12/18 15:37:38 mpowers Changes to retain ability to work
+ * with objects that don't necessarily implement EOEnterpriseObject. I would
+ * still like to preserve this case for general usage, however the access
+ * package is free to assume that those objects will be EOs and cast
+ * appropriately.
*
- * Revision 1.85 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ * Revision 1.85 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
*
- * Revision 1.84 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.84 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.83 2003/02/13 15:24:33 mpowers
- * hasChanges is now derived, not tracked.
- * refaultObject now more consistently removes object from updated list.
+ * Revision 1.83 2003/02/13 15:24:33 mpowers hasChanges is now derived, not
+ * tracked. refaultObject now more consistently removes object from updated
+ * list.
*
- * Revision 1.82 2002/12/16 15:46:00 mpowers
- * Major refactoring to implement setInstancesRetainRegisteredObjects().
+ * Revision 1.82 2002/12/16 15:46:00 mpowers Major refactoring to implement
+ * setInstancesRetainRegisteredObjects().
*
- * Revision 1.81 2002/11/18 22:10:58 mpowers
- * Now resetting hasChanges flag on reset.
+ * Revision 1.81 2002/11/18 22:10:58 mpowers Now resetting hasChanges flag on
+ * reset.
*
- * Revision 1.80 2002/10/24 21:15:33 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.80 2002/10/24 21:15:33 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.79 2002/10/24 18:18:12 mpowers
- * NSArray's are now considered read-only, so we can return our internal
- * representation to reduce unnecessary object allocation.
+ * Revision 1.79 2002/10/24 18:18:12 mpowers NSArray's are now considered
+ * read-only, so we can return our internal representation to reduce unnecessary
+ * object allocation.
*
- * Revision 1.78 2002/06/21 21:44:33 mpowers
- * No longer marking deleted objects as updated (thanks to dwang).
+ * Revision 1.78 2002/06/21 21:44:33 mpowers No longer marking deleted objects
+ * as updated (thanks to dwang).
*
- * Revision 1.77 2002/05/20 15:10:17 mpowers
- * No longer refaulting if delegate does not wish to handle the merge.
+ * Revision 1.77 2002/05/20 15:10:17 mpowers No longer refaulting if delegate
+ * does not wish to handle the merge.
*
- * Revision 1.76 2002/03/26 21:46:06 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.76 2002/03/26 21:46:06 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
- * Revision 1.75 2002/03/06 16:14:57 mpowers
- * More attempts at ignoring update conflicts that come from ourself.
+ * Revision 1.75 2002/03/06 16:14:57 mpowers More attempts at ignoring update
+ * conflicts that come from ourself.
*
- * Revision 1.74 2002/02/21 21:57:50 mpowers
- * Implemented default merge behavior.
+ * Revision 1.74 2002/02/21 21:57:50 mpowers Implemented default merge behavior.
*
- * Revision 1.73 2002/02/20 16:46:54 mpowers
- * Implemented better support for EOEditingContext.Delegate.
+ * Revision 1.73 2002/02/20 16:46:54 mpowers Implemented better support for
+ * EOEditingContext.Delegate.
*
- * Revision 1.70 2002/02/19 22:26:05 mpowers
- * Implemented EOEditingContext.MessageHandler support.
+ * Revision 1.70 2002/02/19 22:26:05 mpowers Implemented
+ * EOEditingContext.MessageHandler support.
*
- * Revision 1.69 2002/02/19 16:33:42 mpowers
- * Implemented support for EditingContext.Editor
+ * Revision 1.69 2002/02/19 16:33:42 mpowers Implemented support for
+ * EditingContext.Editor
*
- * Revision 1.68 2002/02/13 22:00:34 mpowers
- * Fixed: invalidateAllObjects tries to invalidate inserted objects,
- * typically causing class cast exceptions involving EOTemporaryGlobalID.
+ * Revision 1.68 2002/02/13 22:00:34 mpowers Fixed: invalidateAllObjects tries
+ * to invalidate inserted objects, typically causing class cast exceptions
+ * involving EOTemporaryGlobalID.
*
- * Revision 1.67 2002/02/06 21:15:35 mpowers
- * No longer refaulting a dirty object when we receive an invalidation notif.
+ * Revision 1.67 2002/02/06 21:15:35 mpowers No longer refaulting a dirty object
+ * when we receive an invalidation notif.
*
- * Revision 1.66 2002/01/08 19:31:03 mpowers
- * refaultObject now correctly refaults the object.
+ * Revision 1.66 2002/01/08 19:31:03 mpowers refaultObject now correctly
+ * refaults the object.
*
- * Revision 1.65 2001/12/20 18:56:15 mpowers
- * Refinements to snapshotting and calling processRecentChanges.
+ * Revision 1.65 2001/12/20 18:56:15 mpowers Refinements to snapshotting and
+ * calling processRecentChanges.
*
- * Revision 1.64 2001/12/10 15:11:41 mpowers
- * Now only tracking a commit snapshot after an object has been modified.
+ * Revision 1.64 2001/12/10 15:11:41 mpowers Now only tracking a commit snapshot
+ * after an object has been modified.
*
- * Revision 1.63 2001/11/14 00:08:10 mpowers
- * Now marking context changed when objects are inserted or deleted
- * and when child contexts save their changes into this context.
+ * Revision 1.63 2001/11/14 00:08:10 mpowers Now marking context changed when
+ * objects are inserted or deleted and when child contexts save their changes
+ * into this context.
*
- * Revision 1.62 2001/11/07 14:49:31 mpowers
- * invalidateAllObjects now handles objects manually discarded in the course
- * of invalidation.
+ * Revision 1.62 2001/11/07 14:49:31 mpowers invalidateAllObjects now handles
+ * objects manually discarded in the course of invalidation.
*
- * Revision 1.61 2001/10/26 20:02:49 mpowers
- * No longer using NSNotificationQueue: all notifications are posted immed.
+ * Revision 1.61 2001/10/26 20:02:49 mpowers No longer using
+ * NSNotificationQueue: all notifications are posted immed.
*
- * Revision 1.60 2001/10/26 18:37:50 mpowers
- * Now using NSRunLoop to correctly flush recent changes before delayed
- * observers and AWT events.
+ * Revision 1.60 2001/10/26 18:37:50 mpowers Now using NSRunLoop to correctly
+ * flush recent changes before delayed observers and AWT events.
*
- * Revision 1.59 2001/10/23 22:29:59 mpowers
- * Now posting notifications immediately.
- * Recent changes are flushed at ObserverPrioritySixth, soon to change.
+ * Revision 1.59 2001/10/23 22:29:59 mpowers Now posting notifications
+ * immediately. Recent changes are flushed at ObserverPrioritySixth, soon to
+ * change.
*
- * Revision 1.58 2001/09/10 14:16:51 mpowers
- * EditingContexts now relay InvalidatedAllObjectsInStore notifications.
+ * Revision 1.58 2001/09/10 14:16:51 mpowers EditingContexts now relay
+ * InvalidatedAllObjectsInStore notifications.
*
- * Revision 1.57 2001/06/18 14:11:15 mpowers
- * Inserting a deleted object simply cancels the delete operation.
+ * Revision 1.57 2001/06/18 14:11:15 mpowers Inserting a deleted object simply
+ * cancels the delete operation.
*
- * Revision 1.56 2001/06/07 22:07:59 mpowers
- * Now handling delete notifications before update notifications.
- * Eliminated the case where deleted objects were also being put
- * on the updated list when notifying child contexts.
+ * Revision 1.56 2001/06/07 22:07:59 mpowers Now handling delete notifications
+ * before update notifications. Eliminated the case where deleted objects were
+ * also being put on the updated list when notifying child contexts.
*
- * Revision 1.55 2001/05/18 21:04:33 mpowers
- * Reimplemented EditingContext.initializeObject.
+ * Revision 1.55 2001/05/18 21:04:33 mpowers Reimplemented
+ * EditingContext.initializeObject.
*
- * Revision 1.54 2001/05/05 23:05:42 mpowers
- * Implemented Array Faults.
+ * Revision 1.54 2001/05/05 23:05:42 mpowers Implemented Array Faults.
*
- * Revision 1.53 2001/05/05 15:00:06 mpowers
- * Tested load-on-demand: still works.
- * Now using registerClone for consistency.
- * Editing context is temporarily posting notification on objectWillChange.
+ * Revision 1.53 2001/05/05 15:00:06 mpowers Tested load-on-demand: still works.
+ * Now using registerClone for consistency. Editing context is temporarily
+ * posting notification on objectWillChange.
*
- * Revision 1.52 2001/05/05 14:11:48 mpowers
- * Implemented registerClone.
+ * Revision 1.52 2001/05/05 14:11:48 mpowers Implemented registerClone.
*
- * Revision 1.51 2001/05/04 16:57:56 mpowers
- * Now correctly transposing references to editing contexts when
- * cloning/copying between editing contexts.
+ * Revision 1.51 2001/05/04 16:57:56 mpowers Now correctly transposing
+ * references to editing contexts when cloning/copying between editing contexts.
*
- * Revision 1.50 2001/05/02 17:58:41 mpowers
- * Removed debugging code, added comments.
+ * Revision 1.50 2001/05/02 17:58:41 mpowers Removed debugging code, added
+ * comments.
*
- * Revision 1.49 2001/05/02 15:47:40 mpowers
- * Fixed the pernicious problem with reverts: recordObject was recording
- * a snapshot of the clone before the transposition-copy happened,
- * so the revert object would lose all of its transposed relationships.
+ * Revision 1.49 2001/05/02 15:47:40 mpowers Fixed the pernicious problem with
+ * reverts: recordObject was recording a snapshot of the clone before the
+ * transposition-copy happened, so the revert object would lose all of its
+ * transposed relationships.
*
- * Revision 1.48 2001/05/02 12:39:05 mpowers
- * Fixed a nasty problem with transpose-cloning and faultForGlobalID.
- * Now we're forced to create a deep clone, registered it, and then
- * transpose it after it has been registered.
+ * Revision 1.48 2001/05/02 12:39:05 mpowers Fixed a nasty problem with
+ * transpose-cloning and faultForGlobalID. Now we're forced to create a deep
+ * clone, registered it, and then transpose it after it has been registered.
*
- * Revision 1.47 2001/04/30 13:15:24 mpowers
- * Child contexts re-initializing objects invalidated in parent now
- * propery transpose relationships.
+ * Revision 1.47 2001/04/30 13:15:24 mpowers Child contexts re-initializing
+ * objects invalidated in parent now propery transpose relationships.
*
- * Revision 1.46 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.46 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.45 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
+ * Revision 1.45 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
*
- * Revision 1.44 2001/04/28 16:18:44 mpowers
- * Implementing relationships.
+ * Revision 1.44 2001/04/28 16:18:44 mpowers Implementing relationships.
*
- * Revision 1.43 2001/04/28 14:12:23 mpowers
- * Refactored cloning/copying into KeyValueCodingUtilities.
+ * Revision 1.43 2001/04/28 14:12:23 mpowers Refactored cloning/copying into
+ * KeyValueCodingUtilities.
*
- * Revision 1.42 2001/04/27 00:27:11 mpowers
- * Provided description to not-implemented exceptions.
+ * Revision 1.42 2001/04/27 00:27:11 mpowers Provided description to
+ * not-implemented exceptions.
*
- * Revision 1.41 2001/04/26 01:16:44 mpowers
- * Major bug fix so we no longer accumulate objects in the all objects
- * list with every InvalidateAllObjectsInStore.
+ * Revision 1.41 2001/04/26 01:16:44 mpowers Major bug fix so we no longer
+ * accumulate objects in the all objects list with every
+ * InvalidateAllObjectsInStore.
*
- * Revision 1.40 2001/04/21 23:07:49 mpowers
- * Now only broadcasts notifications if there's actually a change.
+ * Revision 1.40 2001/04/21 23:07:49 mpowers Now only broadcasts notifications
+ * if there's actually a change.
*
- * Revision 1.39 2001/04/13 16:33:11 mpowers
- * Corrected the refaulting behavior.
+ * Revision 1.39 2001/04/13 16:33:11 mpowers Corrected the refaulting behavior.
*
- * Revision 1.38 2001/04/09 21:42:10 mpowers
- * Debugging and optimizing notifications.
+ * Revision 1.38 2001/04/09 21:42:10 mpowers Debugging and optimizing
+ * notifications.
*
- * Revision 1.37 2001/04/08 20:59:47 mpowers
- * objectsForFetchSpecification now relies on faultForGlobalID.
+ * Revision 1.37 2001/04/08 20:59:47 mpowers objectsForFetchSpecification now
+ * relies on faultForGlobalID.
*
- * Revision 1.36 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.36 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.35 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.35 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and
+ * Support instead of Introspector.
*
- * Revision 1.34 2001/03/28 14:06:29 mpowers
- * Implemented snapshots. Revert now uses snapshots.
+ * Revision 1.34 2001/03/28 14:06:29 mpowers Implemented snapshots. Revert now
+ * uses snapshots.
*
- * Revision 1.33 2001/03/20 23:20:33 mpowers
- * invalidating all objects now sets the dirty flag to false.
+ * Revision 1.33 2001/03/20 23:20:33 mpowers invalidating all objects now sets
+ * the dirty flag to false.
*
- * Revision 1.32 2001/03/19 21:44:36 mpowers
- * Reverts reinitialize for now.
+ * Revision 1.32 2001/03/19 21:44:36 mpowers Reverts reinitialize for now.
* Testing for inserted objects instead of temp id when invalidating object.
*
- * Revision 1.31 2001/03/15 21:10:26 mpowers
- * Implemented global id re-registration for newly saved inserts.
+ * Revision 1.31 2001/03/15 21:10:26 mpowers Implemented global id
+ * re-registration for newly saved inserts.
*
- * Revision 1.30 2001/03/13 21:41:34 mpowers
- * Broadcasting willChange for any change to hasChanges.
- * Fixed major bug with inserted objects treated as updated objects
- * in child display groups.
+ * Revision 1.30 2001/03/13 21:41:34 mpowers Broadcasting willChange for any
+ * change to hasChanges. Fixed major bug with inserted objects treated as
+ * updated objects in child display groups.
*
- * Revision 1.29 2001/03/09 22:10:30 mpowers
- * Fine tuned initializeObject.
+ * Revision 1.29 2001/03/09 22:10:30 mpowers Fine tuned initializeObject.
*
- * Revision 1.28 2001/03/06 23:23:55 mpowers
- * objectForGlobalID now returns null if not found.
- * objectsForFetchSpecification again does things the old way, for now.
+ * Revision 1.28 2001/03/06 23:23:55 mpowers objectForGlobalID now returns null
+ * if not found. objectsForFetchSpecification again does things the old way, for
+ * now.
*
- * Revision 1.27 2001/03/02 16:31:45 mpowers
- * Trying to better handle fetches from child contexts.
- * No longer trying to invalidate temporary objects.
+ * Revision 1.27 2001/03/02 16:31:45 mpowers Trying to better handle fetches
+ * from child contexts. No longer trying to invalidate temporary objects.
*
- * Revision 1.26 2001/02/28 16:25:19 mpowers
- * Now calling globalIDForObject internally.
+ * Revision 1.26 2001/02/28 16:25:19 mpowers Now calling globalIDForObject
+ * internally.
*
- * Revision 1.25 2001/02/27 17:36:55 mpowers
- * Objects inserted from child now preserve the existing temporary id.
+ * Revision 1.25 2001/02/27 17:36:55 mpowers Objects inserted from child now
+ * preserve the existing temporary id.
*
- * Revision 1.24 2001/02/27 02:11:17 mpowers
- * Now throwing exception when cloning fails.
- * Removed debugging printlns.
+ * Revision 1.24 2001/02/27 02:11:17 mpowers Now throwing exception when cloning
+ * fails. Removed debugging printlns.
*
- * Revision 1.23 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.23 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.22 2001/02/26 21:18:45 mpowers
- * Now marking edited objects from child contexts that were not already
- * recorded in parent as changed in saveChangesInEditingContext.
+ * Revision 1.22 2001/02/26 21:18:45 mpowers Now marking edited objects from
+ * child contexts that were not already recorded in parent as changed in
+ * saveChangesInEditingContext.
*
- * Revision 1.21 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.21 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.20 2001/02/24 17:03:22 mpowers
- * Implemented the notification queue, and changed editing context to use it.
+ * Revision 1.20 2001/02/24 17:03:22 mpowers Implemented the notification queue,
+ * and changed editing context to use it.
*
- * Revision 1.19 2001/02/23 23:44:15 mpowers
- * Fine-tuning notification handling.
+ * Revision 1.19 2001/02/23 23:44:15 mpowers Fine-tuning notification handling.
*
- * Revision 1.18 2001/02/22 22:56:57 mpowers
- * Only refaulting edited objects on parent store invalidateAll.
+ * Revision 1.18 2001/02/22 22:56:57 mpowers Only refaulting edited objects on
+ * parent store invalidateAll.
*
- * Revision 1.17 2001/02/22 20:54:39 mpowers
- * Implemented notification handling.
+ * Revision 1.17 2001/02/22 20:54:39 mpowers Implemented notification handling.
*
- * Revision 1.16 2001/02/21 22:10:55 mpowers
- * Editing context is now posting appropriate notifications.
+ * Revision 1.16 2001/02/21 22:10:55 mpowers Editing context is now posting
+ * appropriate notifications.
*
- * Revision 1.15 2001/02/21 21:17:32 mpowers
- * Now retaining a reference to the recent changes observer.
- * Better documented need to retain reference.
- * Started implementing notifications.
+ * Revision 1.15 2001/02/21 21:17:32 mpowers Now retaining a reference to the
+ * recent changes observer. Better documented need to retain reference. Started
+ * implementing notifications.
*
- * Revision 1.14 2001/02/20 17:24:22 mpowers
- * Now using reference keys in objectToID.
+ * Revision 1.14 2001/02/20 17:24:22 mpowers Now using reference keys in
+ * objectToID.
*
- * Revision 1.13 2001/02/20 16:45:36 mpowers
- * Child data sources now accept a data source instead of an editing context
- * for more flexibility. Child data sources now forward relationship
- * methods to parent source.
+ * Revision 1.13 2001/02/20 16:45:36 mpowers Child data sources now accept a
+ * data source instead of an editing context for more flexibility. Child data
+ * sources now forward relationship methods to parent source.
*
- * Revision 1.12 2001/02/16 22:51:29 mpowers
- * Now deep-cloning objects passed between editing contexts.
+ * Revision 1.12 2001/02/16 22:51:29 mpowers Now deep-cloning objects passed
+ * between editing contexts.
*
- * Revision 1.11 2001/02/16 18:34:19 mpowers
- * Implementing nested contexts.
+ * Revision 1.11 2001/02/16 18:34:19 mpowers Implementing nested contexts.
*
- * Revision 1.9 2001/02/15 21:13:30 mpowers
- * First draft implementation is complete. Now on to debugging.
+ * Revision 1.9 2001/02/15 21:13:30 mpowers First draft implementation is
+ * complete. Now on to debugging.
*
- * Revision 1.7 2001/02/13 23:24:29 mpowers
- * Implementing more of editing context.
+ * Revision 1.7 2001/02/13 23:24:29 mpowers Implementing more of editing
+ * context.
*
- * Revision 1.4 2001/02/09 22:09:34 mpowers
- * Completed implementation of EOObjectStore.
+ * Revision 1.4 2001/02/09 22:09:34 mpowers Completed implementation of
+ * EOObjectStore.
*
- * Revision 1.3 2001/02/06 15:24:11 mpowers
- * Widened parameters on abstract method to fix build.
+ * Revision 1.3 2001/02/06 15:24:11 mpowers Widened parameters on abstract
+ * method to fix build.
*
- * Revision 1.2 2001/02/05 03:45:37 mpowers
- * Starting work on EOEditingContext.
+ * Revision 1.2 2001/02/05 03:45:37 mpowers Starting work on EOEditingContext.
*
- * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers Contributing wotonomy.
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEnterpriseObject.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEnterpriseObject.java
index 112531c..db03a22 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEnterpriseObject.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOEnterpriseObject.java
@@ -22,198 +22,180 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* EOEnterpriseObject defines the required methods a data object
-* must implement to take full advantage of the control package.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * EOEnterpriseObject defines the required methods a data object must implement
+ * to take full advantage of the control package.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public interface EOEnterpriseObject
- extends EOKeyValueCodingAdditions,
- EORelationshipManipulation,
- EODeferredFaulting,
- EOValidation
-{
- /**
- * Returns a List of all property keys defined on this object.
- * This includes both attributes and relationships.
- */
- NSArray allPropertyKeys();
-
- /**
- * Returns a list of all attributes defined on this object.
- * Attributes are all properties that are not relationships.
- */
- NSArray attributeKeys();
-
- //void awakeFromClientUpdate(EOEditingContext aContext)
-
- /**
- * Called when the object has first been fetched into the
- * specified editing context.
- */
- void awakeFromFetch(EOEditingContext anEditingContext);
-
- /**
- * Called when the object has been inserted into the
- * specified editing context.
- */
- void awakeFromInsertion(EOEditingContext anEditingContext);
-
- /**
- * Returns a Map representing the delta of the current state
- * from the state represented in the specified snapshot.
- * The result will contain only the keys that have changed
- * and their values. Relationship keys will map to an NSArray
- * that contains an NSArray of added objects and an NSArray
- * of removed objects, in that order.
- */
- NSDictionary changesFromSnapshot(NSDictionary snapshot);
-
- /**
- * Returns a class description for this object.
- */
- EOClassDescription classDescription();
-
- /**
- * Returns a class description for the object at the
- * other end of the specified relationship key.
- */
- EOClassDescription classDescriptionForDestinationKey(String aKey);
-
- /**
- * Clears all property values for this object.
- * This method is called to clean-up an object that
- * will no longer be used, and implementations should
- * ensure that all references are set to null to
- * prevent problems with garbage-collection.
- */
- void clearProperties();
-
- /**
- * Returns the delete rule constant defined on EOClassDescription
- * for the relationship defined by the specified key.
- */
- int deleteRuleForRelationshipKey(String aRelationshipKey);
-
- /**
- * Returns the editing context in which this object is registered.
- */
- EOEditingContext editingContext();
-
- /**
- * Returns the name of the entity that this object represents.
- */
- String entityName();
-
- /**
- * Returns a String containing all property keys and values for
- * this object. Relationships should be represented by calling
- * eoShallowDescription() on the object.
- */
- String eoDescription();
-
- /**
- * Returns a String containing all attribute keys and values for
- * this object. Relationships are not included.
- */
- String eoShallowDescription();
-
- /**
- * Returns the key used to reference this object on the
- * object at the other end of the specified relationship.
- */
- String inverseForRelationshipKey(String aRelationshipKey);
-
- //Object invokeRemoteMethod(
- // String aMethodName, Class[] aTypeArray Object[] anArgumentArray)
-
- /**
- * Returns whether the specified relationship key represents
- * a to-many relationship.
- */
- boolean isToManyKey(String aKey);
-
- /**
- * Returns whether the objects at the other end of the specified
- * relationship should be deleted when this object is deleted.
- */
- boolean ownsDestinationObjectsForRelationshipKey(String aKey);
-
- //void prepareValuesForClient()
-
- /**
- * Called to perform the delete propagation for this object
- * on the specified editing context. All relationships
- * should be processed according to their corresponding
- * delete rule.
- */
- void propagateDeleteWithEditingContext(EOEditingContext aContext);
-
- /**
- * Applies the changes from the specified snapshot to
- * this object.
- * @see #changesFromSnapshot(NSDictionary)
- */
- void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot);
-
- /**
- * Returns a snapshot of the current state of this object.
- * All property keys are mapped to their values; nulls are
- * represented by NSNull.
- */
- NSDictionary snapshot();
-
- /**
- * Returns a List of the to-many relationship keys
- * for this object.
- */
- NSArray toManyRelationshipKeys();
-
- /**
- * Returns a List of the to-one relationship keys
- * for this object.
- */
- NSArray toOneRelationshipKeys();
-
- /**
- * Applies the specified snapshot to this object,
- * converting NSNulls to null and calling
- * takeStoredValueForKey for each key in the Map.
- */
- void updateFromSnapshot(NSDictionary aSnapshot);
-
- /**
- * Returns a short, stateful string representation
- * of this object.
- */
- String userPresentableDescription();
-
- /**
- * This method should be implemented to call
- * EOObserverCenter.objectWillChange( this ),
- * and it should be called by each setter method
- * on this object before changes are made to the
- * object's internal state.
- */
- void willChange();
+ extends EOKeyValueCodingAdditions, EORelationshipManipulation, EODeferredFaulting, EOValidation {
+ /**
+ * Returns a List of all property keys defined on this object. This includes
+ * both attributes and relationships.
+ */
+ NSArray allPropertyKeys();
+
+ /**
+ * Returns a list of all attributes defined on this object. Attributes are all
+ * properties that are not relationships.
+ */
+ NSArray attributeKeys();
+
+ // void awakeFromClientUpdate(EOEditingContext aContext)
+
+ /**
+ * Called when the object has first been fetched into the specified editing
+ * context.
+ */
+ void awakeFromFetch(EOEditingContext anEditingContext);
+
+ /**
+ * Called when the object has been inserted into the specified editing context.
+ */
+ void awakeFromInsertion(EOEditingContext anEditingContext);
+
+ /**
+ * Returns a Map representing the delta of the current state from the state
+ * represented in the specified snapshot. The result will contain only the keys
+ * that have changed and their values. Relationship keys will map to an NSArray
+ * that contains an NSArray of added objects and an NSArray of removed objects,
+ * in that order.
+ */
+ NSDictionary changesFromSnapshot(NSDictionary snapshot);
+
+ /**
+ * Returns a class description for this object.
+ */
+ EOClassDescription classDescription();
+
+ /**
+ * Returns a class description for the object at the other end of the specified
+ * relationship key.
+ */
+ EOClassDescription classDescriptionForDestinationKey(String aKey);
+
+ /**
+ * Clears all property values for this object. This method is called to clean-up
+ * an object that will no longer be used, and implementations should ensure that
+ * all references are set to null to prevent problems with garbage-collection.
+ */
+ void clearProperties();
+
+ /**
+ * Returns the delete rule constant defined on EOClassDescription for the
+ * relationship defined by the specified key.
+ */
+ int deleteRuleForRelationshipKey(String aRelationshipKey);
+
+ /**
+ * Returns the editing context in which this object is registered.
+ */
+ EOEditingContext editingContext();
+
+ /**
+ * Returns the name of the entity that this object represents.
+ */
+ String entityName();
+
+ /**
+ * Returns a String containing all property keys and values for this object.
+ * Relationships should be represented by calling eoShallowDescription() on the
+ * object.
+ */
+ String eoDescription();
+
+ /**
+ * Returns a String containing all attribute keys and values for this object.
+ * Relationships are not included.
+ */
+ String eoShallowDescription();
+
+ /**
+ * Returns the key used to reference this object on the object at the other end
+ * of the specified relationship.
+ */
+ String inverseForRelationshipKey(String aRelationshipKey);
+
+ // Object invokeRemoteMethod(
+ // String aMethodName, Class[] aTypeArray Object[] anArgumentArray)
+
+ /**
+ * Returns whether the specified relationship key represents a to-many
+ * relationship.
+ */
+ boolean isToManyKey(String aKey);
+
+ /**
+ * Returns whether the objects at the other end of the specified relationship
+ * should be deleted when this object is deleted.
+ */
+ boolean ownsDestinationObjectsForRelationshipKey(String aKey);
+
+ // void prepareValuesForClient()
+
+ /**
+ * Called to perform the delete propagation for this object on the specified
+ * editing context. All relationships should be processed according to their
+ * corresponding delete rule.
+ */
+ void propagateDeleteWithEditingContext(EOEditingContext aContext);
+
+ /**
+ * Applies the changes from the specified snapshot to this object.
+ *
+ * @see #changesFromSnapshot(NSDictionary)
+ */
+ void reapplyChangesFromDictionary(NSDictionary aDeltaSnapshot);
+
+ /**
+ * Returns a snapshot of the current state of this object. All property keys are
+ * mapped to their values; nulls are represented by NSNull.
+ */
+ NSDictionary snapshot();
+
+ /**
+ * Returns a List of the to-many relationship keys for this object.
+ */
+ NSArray toManyRelationshipKeys();
+
+ /**
+ * Returns a List of the to-one relationship keys for this object.
+ */
+ NSArray toOneRelationshipKeys();
+
+ /**
+ * Applies the specified snapshot to this object, converting NSNulls to null and
+ * calling takeStoredValueForKey for each key in the Map.
+ */
+ void updateFromSnapshot(NSDictionary aSnapshot);
+
+ /**
+ * Returns a short, stateful string representation of this object.
+ */
+ String userPresentableDescription();
+
+ /**
+ * This method should be implemented to call EOObserverCenter.objectWillChange(
+ * this ), and it should be called by each setter method on this object before
+ * changes are made to the object's internal state.
+ */
+ void willChange();
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaultHandler.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaultHandler.java
index 19dc2df..e407492 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaultHandler.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaultHandler.java
@@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EOFaultHandler defines the contract for objects that can
-* create and populate faults. In wotonomy, this interface is
-* currently only a marker interface.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * EOFaultHandler defines the contract for objects that can create and populate
+ * faults. In wotonomy, this interface is currently only a marker interface.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public abstract class EOFaultHandler {
protected Class _targetClass;
@@ -38,7 +37,7 @@ public abstract class EOFaultHandler {
public static EOFaultHandler handlerForFault(Object obj) {
if (!(obj instanceof EOFaulting))
throw new IllegalArgumentException("Object must implement EOFaulting");
- return ((EOFaulting)obj).faultHandler();
+ return ((EOFaulting) obj).faultHandler();
}
public static boolean isFault(Object obj) {
@@ -46,20 +45,20 @@ public abstract class EOFaultHandler {
return false;
boolean isit = (obj instanceof EOFaulting);
if (isit)
- isit = ((EOFaulting)obj).isFault();
+ isit = ((EOFaulting) obj).isFault();
return isit;
}
public static void makeObjectIntoFault(Object obj, EOFaultHandler handler) {
if (!(obj instanceof EOFaulting))
throw new IllegalArgumentException("Object must implement EOFaulting");
- ((EOFaulting)obj).turnIntoFault(handler);
+ ((EOFaulting) obj).turnIntoFault(handler);
}
public static void clearFault(Object obj) {
if (!(obj instanceof EOFaulting))
throw new IllegalArgumentException("Object must implement EOFaulting");
- ((EOFaulting)obj).clearFault();
+ ((EOFaulting) obj).clearFault();
}
public Class targetClass() {
@@ -87,16 +86,15 @@ public abstract class EOFaultHandler {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ * Revision 1.2 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaulting.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaulting.java
index 95b3e35..f468949 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaulting.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFaulting.java
@@ -19,61 +19,56 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EOFaulting defines the requirements for objects that
-* can be faulted by an EOFaultManager.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EOFaulting
-{
- /**
- * Called by EOFaultHandler to prepare the object to be turned into a fault.
- */
- void clearFault();
-
- /**
- * Returns this object's EOFaultHandler.
- */
- EOFaultHandler faultHandler();
-
- /**
- * Returns whether this object is currently a fault.
- * Returns true if this object has not yet retrieved any values.
- */
- boolean isFault();
-
- /**
- * Turns this object into a fault using the specified fault handler.
- */
- void turnIntoFault( EOFaultHandler aFaultHandler );
-
- /**
- * Called to completely fire the fault, reading all values.
- * This method may be implemented to call willRead(null).
- */
- void willRead();
-
- /**
- * Called to fire the fault for the specified key.
- * The fault manager is required to populate the specified key
- * with a value, and may populate any or all of the other values
- * on this object. A null key will populate all values on the object.
- * NOTE: This method is not part of the specification.
- */
- void willRead( String aKey );
+ * EOFaulting defines the requirements for objects that can be faulted by an
+ * EOFaultManager.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EOFaulting {
+ /**
+ * Called by EOFaultHandler to prepare the object to be turned into a fault.
+ */
+ void clearFault();
+
+ /**
+ * Returns this object's EOFaultHandler.
+ */
+ EOFaultHandler faultHandler();
+
+ /**
+ * Returns whether this object is currently a fault. Returns true if this object
+ * has not yet retrieved any values.
+ */
+ boolean isFault();
+
+ /**
+ * Turns this object into a fault using the specified fault handler.
+ */
+ void turnIntoFault(EOFaultHandler aFaultHandler);
+
+ /**
+ * Called to completely fire the fault, reading all values. This method may be
+ * implemented to call willRead(null).
+ */
+ void willRead();
+
+ /**
+ * Called to fire the fault for the specified key. The fault manager is required
+ * to populate the specified key with a value, and may populate any or all of
+ * the other values on this object. A null key will populate all values on the
+ * object. NOTE: This method is not part of the specification.
+ */
+ void willRead(String aKey);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFetchSpecification.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFetchSpecification.java
index 71f3b78..9ff353e 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFetchSpecification.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOFetchSpecification.java
@@ -30,439 +30,378 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOFetchSpecification defines the parameters used to request
-* objects from an EOObjectStore. They are commonly created
-* and passed to a EODataSource which fetches from its
-* EOEditingContext, which passes the call up to its root
-* EOObjectStore's objectsWithFetchSpecification method.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * EOFetchSpecification defines the parameters used to request objects from an
+ * EOObjectStore. They are commonly created and passed to a EODataSource which
+ * fetches from its EOEditingContext, which passes the call up to its root
+ * EOObjectStore's objectsWithFetchSpecification method.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOFetchSpecification implements EOKeyValueArchiving {
- private boolean fetchesRawRows;
- private String entityName;
- private NSDictionary hints;
- private boolean deep;
- private int fetchLimit;
- private boolean locksObjects;
- private NSArray prefetchingRelationshipKeyPaths;
- private boolean promptsAfterFetchLimit;
- private EOQualifier qualifier;
- private NSArray rawRowKeyPaths;
- private boolean refreshesRefetchedObjects;
- private boolean requiresAllQualifierBindingVariables;
- private NSArray sortOrderings;
- private boolean distinct;
-
- /**
- * Default constructor initializes internal state.
- */
- public EOFetchSpecification()
- {
- fetchesRawRows = false;
- entityName = null;
- hints = null;
- deep = true;
- fetchLimit = 0;
- locksObjects = false;
- prefetchingRelationshipKeyPaths = null;
- promptsAfterFetchLimit = false;
- qualifier = null;
- rawRowKeyPaths = null;
- refreshesRefetchedObjects = false;
- requiresAllQualifierBindingVariables = false;
- sortOrderings = null;
- distinct = false;
- }
-
- /**
- * Constructs a fetch specification for the specified entity type using
- * the specified qualifier and sort ordering.
- */
- public EOFetchSpecification( String anEntityName, EOQualifier aQualifier, List aSortOrderingList )
- {
- this();
- entityName = anEntityName;
- qualifier = aQualifier;
- sortOrderings = new NSArray( (Collection) aSortOrderingList );
- }
-
- /**
- * Constructs a fetch specification for the specified entity type using
- * the specified qualifier and sort ordering, distinct flag, deep flag,
- * and hints dictionary.
- */
- public EOFetchSpecification( String anEntityName, EOQualifier aQualifier, NSArray aSortOrderingList,
- boolean usesDistinct, boolean isDeep, Map aHintMap)
- {
- this();
- entityName = anEntityName;
- qualifier = aQualifier;
- sortOrderings = new NSArray( (Collection) aSortOrderingList );
- distinct = usesDistinct;
- deep = isDeep;
- hints = new NSMutableDictionary( (Map) aHintMap );
- }
-
- /**
- * Convenience to return the named fetch specification from the class description
- * corresponding to the specified entity name. Returns null if either entityName
- * or spec name cannot be resolved.
- */
- public static EOFetchSpecification fetchSpecificationNamed( String name, String entityName)
- {
- EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName( entityName );
- if ( classDesc == null ) return null;
- return classDesc.fetchSpecificationNamed( name );
- }
-
- /**
- * Implemented to return a new fetch specification that is a deep copy of this one.
- */
- public Object clone()
- {
- EOFetchSpecification clone = new EOFetchSpecification();
-
- clone.fetchesRawRows = this.fetchesRawRows;
- clone.entityName = this.entityName;
- if ( this.hints != null )
- clone.hints = new NSDictionary( (Map) this.hints );
- clone.deep = this.deep;
- clone.locksObjects = this.locksObjects;
- if ( this.prefetchingRelationshipKeyPaths != null )
- clone.prefetchingRelationshipKeyPaths =
- new NSArray( (List) prefetchingRelationshipKeyPaths );
- clone.promptsAfterFetchLimit = this.promptsAfterFetchLimit;
- if ( this.qualifier != null )
- clone.qualifier = this.qualifier; //FIXME: probably should clone?
- if ( this.rawRowKeyPaths != null )
- clone.rawRowKeyPaths = new NSArray( (List) this.rawRowKeyPaths );
- clone.refreshesRefetchedObjects = this.refreshesRefetchedObjects;
- clone.requiresAllQualifierBindingVariables =
- this.requiresAllQualifierBindingVariables;
- if ( this.sortOrderings != null )
- clone.sortOrderings = new NSArray( (List) this.sortOrderings );
- clone.distinct = this.distinct;
-
- return clone;
- }
-
- /**
- * Returns the name of the entity fetched by this fetch spec.
- */
- public String entityName()
- {
- return entityName;
- }
-
- /**
- * Returns the current fetch limit.
- * A fetch limit of zero indicates no fetch limit.
- * Zero is the default.
- */
- public int fetchLimit()
- {
- return fetchLimit;
- }
-
- /**
- * Returns whether this fetch spec will fetch raw rows.
- * Default is false.
- */
- public boolean fetchesRawRows()
- {
- return fetchesRawRows;
- }
-
- /**
- * Returns a fetch specification that resolves the bindings
- * in the specified map.
- */
- public EOFetchSpecification
- fetchSpecificationWithQualifierBindings(Map aBindingMap)
- {
- throw new WotonomyException( "Not implemented yet" );
- }
-
- /**
- * Returns a Map containing the hints used by this fetch specification,
- * or null if no hints have been specified.
- */
- public NSDictionary hints()
- {
- if ( hints == null ) return null;
- return new NSDictionary( (NSDictionary) hints );
- }
-
- /**
- * Returns whether entities related to the primary
- * entities are fetched by this fetch spec. If true, all relationships
- * whose destinations meet the qualifier criteria will be returned
- * in addition to primary results. If false, only the primary entities
- * will be returned. Default is true.
- */
- public boolean isDeep()
- {
- return deep;
- }
-
- /**
- * Returns whether this data source should lock objects that
- * are fetched. Default is false.
- */
- public boolean locksObjects()
- {
- return locksObjects;
- }
-
- /***
- * Returns a List of relationships for the fetched objects that
- * should also be fetched, or null if no such list has been specified.
- * Use this to avoid additional calls to the server to fetch
- * relationships that you know you will use.
- * NOTE: wotonomy allows you to specify non-relational keys
- * as well.
- */
- public NSArray prefetchingRelationshipKeyPaths()
- {
- return prefetchingRelationshipKeyPaths;
- }
-
- /**
- * Returns whether the user should be prompted to continue
- * when the fetch limit has been exceeded.
- * Default is false.
- */
- public boolean promptsAfterFetchLimit()
- {
- return promptsAfterFetchLimit;
- }
-
- /**
- * Returns the qualifier used by this fetch specification,
- * or null if none has been specified.
- */
- public EOQualifier qualifier()
- {
- return qualifier;
- }
-
- /**
- * Returns a List of keys or key paths for which
- * values should be returned when fetching raw rows,
- * or null if no raw row key paths have been specified.
- */
- public NSArray rawRowKeyPaths()
- {
- return rawRowKeyPaths;
- }
-
- /**
- * Returns whether fetched objects should replace
- * modified versions already fetched into an editing context.
- * If true, those changes will be lost.
- * Default is false.
- */
- public boolean refreshesRefetchedObjects()
- {
- return refreshesRefetchedObjects;
- }
-
- /**
- * Returns whether all qualifier bindings must be specified
- * in order to fetch. If true, an exception is thrown if
- * unspecified bindings exist. If false, unspecified bindings
- * will be removed from the qualifier. Default is false.
- */
- public boolean requiresAllQualifierBindingVariables()
- {
- return requiresAllQualifierBindingVariables;
- }
-
- /**
- * Sets the name of the entity fetched by this spec.
- */
- public void setEntityName(String aName)
- {
- entityName = aName;
- }
-
- /**
- * Sets whether this fetch spec will return raw rows.
- */
- public void setFetchesRawRows(boolean shouldFetchRawRows)
- {
- fetchesRawRows = shouldFetchRawRows;
- }
-
- /**
- * Sets the limit on the number of records returned for this fetch spec.
- * Zero indicates no limit on fetches.
- */
- public void setFetchLimit(int aLimit)
- {
- fetchLimit = aLimit;
- }
-
- /**
- * Sets the hints passed by this fetch spec.
- */
- public void setHints(Map aHintMap)
- {
- if ( aHintMap == null )
- {
- hints = null;
- }
- else
- {
- hints = new NSDictionary( (Map) aHintMap );
- }
- }
-
- /**
- * Sets whether this fetch specification fetches deeply.
- */
- public void setIsDeep(boolean isDeep)
- {
- deep = isDeep;
- }
-
- /**
- * Sets whether this fetch spec locks objects that
- * are returned by the fetch.
- */
- public void setLocksObjects(boolean shouldLockObjects)
- {
- locksObjects = shouldLockObjects;
- }
-
- /**
- * Sets the prefetch key paths that should be used as an optimization
- * hint to the server. NOTE: wotonomy allows you to specify non-relationship
- * keys as well.
- */
- public void setPrefetchingRelationshipKeyPaths(List aKeyPathList)
- {
- if ( aKeyPathList == null )
- {
- prefetchingRelationshipKeyPaths = null;
- }
- else
- {
- prefetchingRelationshipKeyPaths = new NSArray( (List) aKeyPathList );
- }
- }
-
- /**
- * Sets whether the user should be prompted when the fetch limit has been
- * reached.
- */
- public void setPromptsAfterFetchLimit(boolean shouldPrompt)
- {
- promptsAfterFetchLimit = shouldPrompt;
- }
-
- /**
- * Sets the qualifier used by this fetch specification.
- */
- public void setQualifier(EOQualifier aQualifier)
- {
- qualifier = aQualifier;
- }
-
- /**
- * Sets the key paths to be returned if this fetch spec
- * is returning raw rows.
- */
- public void setRawRowKeyPaths(List aKeyPathList)
- {
- if ( aKeyPathList == null )
- {
- rawRowKeyPaths = null;
- }
- else
- {
- rawRowKeyPaths = new NSArray( (List) aKeyPathList );
- }
- }
-
- /**
- * Sets whether modified objects in an editing context should
- * be replaced by newer versions returned by this fetch spec.
- */
- public void setRefreshesRefetchedObjects(boolean shouldRefresh)
- {
- refreshesRefetchedObjects = shouldRefresh;
- }
-
- /**
- * Sets whether this fetch spec should require all bindings to be
- * resolved before executing.
- */
- public void setRequiresAllQualifierBindingVariables(boolean shouldRequireAll)
- {
- requiresAllQualifierBindingVariables = shouldRequireAll;
- }
-
- /**
- * Sets the sort orderings used by this fetch spec.
- */
- public void setSortOrderings(List aSortList)
- {
- if ( aSortList == null )
- {
- sortOrderings = null;
- }
- else
- {
- sortOrderings = new NSArray( (List) aSortList );
- }
- }
-
- /**
- * Sets whether this fetch spec should return only distinct
- * objects.
- */
- public void setUsesDistinct(boolean shouldUseDistinct)
- {
- distinct = shouldUseDistinct;
- }
-
- /**
- * Returns a List of the sort orderings used by this fetch spec,
- * or null if none have been specified.
- */
- public NSArray sortOrderings()
- {
- return sortOrderings;
- }
-
- /**
- * Returns a string representation of this fetch specification.
- */
- public String toString()
- {
- return "[FetchSpecification:qualifier=("+qualifier+"),sortOrderings="+sortOrderings+"]";
- }
-
- /**
- * Returns whether this fetch specification will return only one
- * reference to each distinct object returned by the fetch.
- * Default is false.
- */
- public boolean usesDistinct()
- {
- return distinct;
- }
+ private boolean fetchesRawRows;
+ private String entityName;
+ private NSDictionary hints;
+ private boolean deep;
+ private int fetchLimit;
+ private boolean locksObjects;
+ private NSArray prefetchingRelationshipKeyPaths;
+ private boolean promptsAfterFetchLimit;
+ private EOQualifier qualifier;
+ private NSArray rawRowKeyPaths;
+ private boolean refreshesRefetchedObjects;
+ private boolean requiresAllQualifierBindingVariables;
+ private NSArray sortOrderings;
+ private boolean distinct;
+
+ /**
+ * Default constructor initializes internal state.
+ */
+ public EOFetchSpecification() {
+ fetchesRawRows = false;
+ entityName = null;
+ hints = null;
+ deep = true;
+ fetchLimit = 0;
+ locksObjects = false;
+ prefetchingRelationshipKeyPaths = null;
+ promptsAfterFetchLimit = false;
+ qualifier = null;
+ rawRowKeyPaths = null;
+ refreshesRefetchedObjects = false;
+ requiresAllQualifierBindingVariables = false;
+ sortOrderings = null;
+ distinct = false;
+ }
+
+ /**
+ * Constructs a fetch specification for the specified entity type using the
+ * specified qualifier and sort ordering.
+ */
+ public EOFetchSpecification(String anEntityName, EOQualifier aQualifier, List aSortOrderingList) {
+ this();
+ entityName = anEntityName;
+ qualifier = aQualifier;
+ sortOrderings = new NSArray((Collection) aSortOrderingList);
+ }
+
+ /**
+ * Constructs a fetch specification for the specified entity type using the
+ * specified qualifier and sort ordering, distinct flag, deep flag, and hints
+ * dictionary.
+ */
+ public EOFetchSpecification(String anEntityName, EOQualifier aQualifier, NSArray aSortOrderingList,
+ boolean usesDistinct, boolean isDeep, Map aHintMap) {
+ this();
+ entityName = anEntityName;
+ qualifier = aQualifier;
+ sortOrderings = new NSArray((Collection) aSortOrderingList);
+ distinct = usesDistinct;
+ deep = isDeep;
+ hints = new NSMutableDictionary((Map) aHintMap);
+ }
+
+ /**
+ * Convenience to return the named fetch specification from the class
+ * description corresponding to the specified entity name. Returns null if
+ * either entityName or spec name cannot be resolved.
+ */
+ public static EOFetchSpecification fetchSpecificationNamed(String name, String entityName) {
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName(entityName);
+ if (classDesc == null)
+ return null;
+ return classDesc.fetchSpecificationNamed(name);
+ }
+
+ /**
+ * Implemented to return a new fetch specification that is a deep copy of this
+ * one.
+ */
+ public Object clone() {
+ EOFetchSpecification clone = new EOFetchSpecification();
+
+ clone.fetchesRawRows = this.fetchesRawRows;
+ clone.entityName = this.entityName;
+ if (this.hints != null)
+ clone.hints = new NSDictionary((Map) this.hints);
+ clone.deep = this.deep;
+ clone.locksObjects = this.locksObjects;
+ if (this.prefetchingRelationshipKeyPaths != null)
+ clone.prefetchingRelationshipKeyPaths = new NSArray((List) prefetchingRelationshipKeyPaths);
+ clone.promptsAfterFetchLimit = this.promptsAfterFetchLimit;
+ if (this.qualifier != null)
+ clone.qualifier = this.qualifier; // FIXME: probably should clone?
+ if (this.rawRowKeyPaths != null)
+ clone.rawRowKeyPaths = new NSArray((List) this.rawRowKeyPaths);
+ clone.refreshesRefetchedObjects = this.refreshesRefetchedObjects;
+ clone.requiresAllQualifierBindingVariables = this.requiresAllQualifierBindingVariables;
+ if (this.sortOrderings != null)
+ clone.sortOrderings = new NSArray((List) this.sortOrderings);
+ clone.distinct = this.distinct;
+
+ return clone;
+ }
+
+ /**
+ * Returns the name of the entity fetched by this fetch spec.
+ */
+ public String entityName() {
+ return entityName;
+ }
+
+ /**
+ * Returns the current fetch limit. A fetch limit of zero indicates no fetch
+ * limit. Zero is the default.
+ */
+ public int fetchLimit() {
+ return fetchLimit;
+ }
+
+ /**
+ * Returns whether this fetch spec will fetch raw rows. Default is false.
+ */
+ public boolean fetchesRawRows() {
+ return fetchesRawRows;
+ }
+
+ /**
+ * Returns a fetch specification that resolves the bindings in the specified
+ * map.
+ */
+ public EOFetchSpecification fetchSpecificationWithQualifierBindings(Map aBindingMap) {
+ throw new WotonomyException("Not implemented yet");
+ }
+
+ /**
+ * Returns a Map containing the hints used by this fetch specification, or null
+ * if no hints have been specified.
+ */
+ public NSDictionary hints() {
+ if (hints == null)
+ return null;
+ return new NSDictionary((NSDictionary) hints);
+ }
+
+ /**
+ * Returns whether entities related to the primary entities are fetched by this
+ * fetch spec. If true, all relationships whose destinations meet the qualifier
+ * criteria will be returned in addition to primary results. If false, only the
+ * primary entities will be returned. Default is true.
+ */
+ public boolean isDeep() {
+ return deep;
+ }
+
+ /**
+ * Returns whether this data source should lock objects that are fetched.
+ * Default is false.
+ */
+ public boolean locksObjects() {
+ return locksObjects;
+ }
+
+ /***
+ * Returns a List of relationships for the fetched objects that should also be
+ * fetched, or null if no such list has been specified. Use this to avoid
+ * additional calls to the server to fetch relationships that you know you will
+ * use. NOTE: wotonomy allows you to specify non-relational keys as well.
+ */
+ public NSArray prefetchingRelationshipKeyPaths() {
+ return prefetchingRelationshipKeyPaths;
+ }
+
+ /**
+ * Returns whether the user should be prompted to continue when the fetch limit
+ * has been exceeded. Default is false.
+ */
+ public boolean promptsAfterFetchLimit() {
+ return promptsAfterFetchLimit;
+ }
+
+ /**
+ * Returns the qualifier used by this fetch specification, or null if none has
+ * been specified.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns a List of keys or key paths for which values should be returned when
+ * fetching raw rows, or null if no raw row key paths have been specified.
+ */
+ public NSArray rawRowKeyPaths() {
+ return rawRowKeyPaths;
+ }
+
+ /**
+ * Returns whether fetched objects should replace modified versions already
+ * fetched into an editing context. If true, those changes will be lost. Default
+ * is false.
+ */
+ public boolean refreshesRefetchedObjects() {
+ return refreshesRefetchedObjects;
+ }
+
+ /**
+ * Returns whether all qualifier bindings must be specified in order to fetch.
+ * If true, an exception is thrown if unspecified bindings exist. If false,
+ * unspecified bindings will be removed from the qualifier. Default is false.
+ */
+ public boolean requiresAllQualifierBindingVariables() {
+ return requiresAllQualifierBindingVariables;
+ }
+
+ /**
+ * Sets the name of the entity fetched by this spec.
+ */
+ public void setEntityName(String aName) {
+ entityName = aName;
+ }
+
+ /**
+ * Sets whether this fetch spec will return raw rows.
+ */
+ public void setFetchesRawRows(boolean shouldFetchRawRows) {
+ fetchesRawRows = shouldFetchRawRows;
+ }
+
+ /**
+ * Sets the limit on the number of records returned for this fetch spec. Zero
+ * indicates no limit on fetches.
+ */
+ public void setFetchLimit(int aLimit) {
+ fetchLimit = aLimit;
+ }
+
+ /**
+ * Sets the hints passed by this fetch spec.
+ */
+ public void setHints(Map aHintMap) {
+ if (aHintMap == null) {
+ hints = null;
+ } else {
+ hints = new NSDictionary((Map) aHintMap);
+ }
+ }
+
+ /**
+ * Sets whether this fetch specification fetches deeply.
+ */
+ public void setIsDeep(boolean isDeep) {
+ deep = isDeep;
+ }
+
+ /**
+ * Sets whether this fetch spec locks objects that are returned by the fetch.
+ */
+ public void setLocksObjects(boolean shouldLockObjects) {
+ locksObjects = shouldLockObjects;
+ }
+
+ /**
+ * Sets the prefetch key paths that should be used as an optimization hint to
+ * the server. NOTE: wotonomy allows you to specify non-relationship keys as
+ * well.
+ */
+ public void setPrefetchingRelationshipKeyPaths(List aKeyPathList) {
+ if (aKeyPathList == null) {
+ prefetchingRelationshipKeyPaths = null;
+ } else {
+ prefetchingRelationshipKeyPaths = new NSArray((List) aKeyPathList);
+ }
+ }
+
+ /**
+ * Sets whether the user should be prompted when the fetch limit has been
+ * reached.
+ */
+ public void setPromptsAfterFetchLimit(boolean shouldPrompt) {
+ promptsAfterFetchLimit = shouldPrompt;
+ }
+
+ /**
+ * Sets the qualifier used by this fetch specification.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
+
+ /**
+ * Sets the key paths to be returned if this fetch spec is returning raw rows.
+ */
+ public void setRawRowKeyPaths(List aKeyPathList) {
+ if (aKeyPathList == null) {
+ rawRowKeyPaths = null;
+ } else {
+ rawRowKeyPaths = new NSArray((List) aKeyPathList);
+ }
+ }
+
+ /**
+ * Sets whether modified objects in an editing context should be replaced by
+ * newer versions returned by this fetch spec.
+ */
+ public void setRefreshesRefetchedObjects(boolean shouldRefresh) {
+ refreshesRefetchedObjects = shouldRefresh;
+ }
+
+ /**
+ * Sets whether this fetch spec should require all bindings to be resolved
+ * before executing.
+ */
+ public void setRequiresAllQualifierBindingVariables(boolean shouldRequireAll) {
+ requiresAllQualifierBindingVariables = shouldRequireAll;
+ }
+
+ /**
+ * Sets the sort orderings used by this fetch spec.
+ */
+ public void setSortOrderings(List aSortList) {
+ if (aSortList == null) {
+ sortOrderings = null;
+ } else {
+ sortOrderings = new NSArray((List) aSortList);
+ }
+ }
+
+ /**
+ * Sets whether this fetch spec should return only distinct objects.
+ */
+ public void setUsesDistinct(boolean shouldUseDistinct) {
+ distinct = shouldUseDistinct;
+ }
+
+ /**
+ * Returns a List of the sort orderings used by this fetch spec, or null if none
+ * have been specified.
+ */
+ public NSArray sortOrderings() {
+ return sortOrderings;
+ }
+
+ /**
+ * Returns a string representation of this fetch specification.
+ */
+ public String toString() {
+ return "[FetchSpecification:qualifier=(" + qualifier + "),sortOrderings=" + sortOrderings + "]";
+ }
+
+ /**
+ * Returns whether this fetch specification will return only one reference to
+ * each distinct object returned by the fetch. Default is false.
+ */
+ public boolean usesDistinct() {
+ return distinct;
+ }
public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
arch.encodeObject("EOFetchSpecification", "class");
arch.encodeObject(entityName(), "entityName");
arch.encodeInt(fetchLimit(), "fetchLimit");
- //flags
+ // flags
if (isDeep())
arch.encodeObject("YES", "isDeep");
arch.encodeObject(qualifier(), "qualifier");
@@ -479,11 +418,11 @@ public class EOFetchSpecification implements EOKeyValueArchiving {
if (usesDistinct())
arch.encodeObject("YES", "usesDistinct");
- //encode arrays
- if (sortOrderings() != null) {
+ // encode arrays
+ if (sortOrderings() != null) {
NSMutableArray arr = new NSMutableArray(sortOrderings().count());
for (int i = 0; i < sortOrderings.count(); i++) {
- EOSortOrdering so = (EOSortOrdering)sortOrderings().objectAtIndex(i);
+ EOSortOrdering so = (EOSortOrdering) sortOrderings().objectAtIndex(i);
EOKeyValueArchiver ar2 = new EOKeyValueArchiver();
so.encodeWithKeyValueArchiver(ar2);
arr.addObject(ar2.dictionary());
@@ -500,18 +439,18 @@ public class EOFetchSpecification implements EOKeyValueArchiving {
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver unarch) {
EOFetchSpecification fs = new EOFetchSpecification();
- fs.setEntityName((String)unarch.decodeObjectForKey("entityName"));
+ fs.setEntityName((String) unarch.decodeObjectForKey("entityName"));
fs.setFetchLimit(unarch.decodeIntForKey("fetchLimit"));
fs.setIsDeep(unarch.decodeBoolForKey("isDeep"));
fs.setRefreshesRefetchedObjects(unarch.decodeBoolForKey("refreshesRefetchedObjects"));
- //Sort orderings
- NSArray arr = (NSArray)unarch.decodeObjectForKey("sortOrderings");
- if (arr != null && arr.count() > 0) {
+ // Sort orderings
+ NSArray arr = (NSArray) unarch.decodeObjectForKey("sortOrderings");
+ if (arr != null && arr.count() > 0) {
NSMutableArray orderings = new NSMutableArray(arr.count());
for (int i = 0; i < arr.count(); i++) {
- NSDictionary so = (NSDictionary)arr.objectAtIndex(i);
- String selname = (String)so.objectForKey("selectorName");
+ NSDictionary so = (NSDictionary) arr.objectAtIndex(i);
+ String selname = (String) so.objectForKey("selectorName");
NSSelector selector = EOSortOrdering.CompareAscending;
if (selname.startsWith("compareDescending"))
selector = EOSortOrdering.CompareDescending;
@@ -519,47 +458,43 @@ public class EOFetchSpecification implements EOKeyValueArchiving {
selector = EOSortOrdering.CompareCaseInsensitiveAscending;
else if (selname.startsWith("compareCaseInsensitiveDescending"))
selector = EOSortOrdering.CompareCaseInsensitiveDescending;
- EOSortOrdering eoso = new EOSortOrdering((String)so.objectForKey("key"), selector);
+ EOSortOrdering eoso = new EOSortOrdering((String) so.objectForKey("key"), selector);
orderings.addObject(eoso);
}
fs.setSortOrderings(orderings);
}
- //raw rows
- arr = (NSArray)unarch.decodeObjectForKey("rawRowKeyPaths");
+ // raw rows
+ arr = (NSArray) unarch.decodeObjectForKey("rawRowKeyPaths");
if (arr != null && arr.count() > 0) {
fs.setFetchesRawRows(true);
fs.setRawRowKeyPaths(arr);
}
- //qualifier
- fs.setQualifier((EOQualifier)unarch.decodeObjectForKey("qualifier"));
+ // qualifier
+ fs.setQualifier((EOQualifier) unarch.decodeObjectForKey("qualifier"));
return fs;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/11 18:19:01 chochos
- * encoding/decoding with EOKeyValueArchiving now works properly
+ * Revision 1.4 2003/08/11 18:19:01 chochos encoding/decoding with
+ * EOKeyValueArchiving now works properly
*
- * Revision 1.3 2003/08/09 01:22:20 chochos
- * implements EOKeyValueArchiving (and unarchiving)
+ * Revision 1.3 2003/08/09 01:22:20 chochos implements EOKeyValueArchiving (and
+ * unarchiving)
*
- * Revision 1.2 2001/11/24 17:32:57 mpowers
- * We now have a real implementation.
+ * Revision 1.2 2001/11/24 17:32:57 mpowers We now have a real implementation.
*
- * Revision 1.1 2001/02/05 03:45:37 mpowers
- * Starting work on EOEditingContext.
+ * Revision 1.1 2001/02/05 03:45:37 mpowers Starting work on EOEditingContext.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGenericRecord.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGenericRecord.java
index 4358ecf..9d732f9 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGenericRecord.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGenericRecord.java
@@ -22,130 +22,112 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSNull;
/**
-* EOGenericRecord extends EOCustomObject to provide a
-* general-purpose implementation, relying entirely on the
-* class description for entity-specific behavior, and
-* storing data in a dictionary.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOGenericRecord extends EOCustomObject
-{
- private EOClassDescription classDescription;
- private NSMutableDictionary dataDictionary;
-
- /**
- * Default constructor.
- */
- protected EOGenericRecord()
- {
- classDescription = null;
- dataDictionary = new NSMutableDictionary();
- }
-
- /**
- * Preferred constructor.
- */
- public EOGenericRecord( EOClassDescription aDescription )
- {
- this();
- classDescription = aDescription;
- }
-
- /**
- * Overridden to return true so that deferred faults are used.
- */
- public static boolean usesDeferredFaultCreation()
- {
- return true;
- }
-
- /**
- * Compatibility constructor: aContext and anID are ignored.
- */
- public EOGenericRecord(
- EOEditingContext aContext, EOClassDescription aDescription, EOGlobalID anID )
- {
- this( aDescription );
- }
-
- /**
- * Returns a class description for this object.
- * Overridden to return the class description passed
- * into the constructor.
- */
- public EOClassDescription classDescription()
- {
- return classDescription;
- }
-
- // interface EOKeyValueCoding
-
- /**
- * Calls storedValueForKey.
- */
- public Object valueForKey( String aKey )
- {
- return storedValueForKey( aKey );
- }
-
- /**
- * Calls willChange and then calls takeStoredValueForKey.
- */
- public void takeValueForKey( Object aValue, String aKey )
- {
- willChange();
- takeStoredValueForKey( aValue, aKey );
- }
-
- /**
- * Calls willRead for the specified key,
- * and returns the corresponding value from
- * the data dictionary. Keys that do not
- * exist will return null.
- */
- public Object storedValueForKey( String aKey )
- {
- willRead( aKey );
- Object result = dataDictionary.objectForKey( aKey );
- if ( NSNull.nullValue().equals( result ) ) result = null;
- return result;
- }
-
- /**
- * Writes the specified value into the data dictionary
- * for the specified key. Nulls are stored as NSNulls
- * in the dictionary.
- * No checking is performed to determine whether the
- * key is a valid attribute key.
- */
- public void takeStoredValueForKey( Object aValue, String aKey )
- {
- if ( aValue == null ) aValue = NSNull.nullValue();
- dataDictionary.setObjectForKey( aValue, aKey );
- }
+ * EOGenericRecord extends EOCustomObject to provide a general-purpose
+ * implementation, relying entirely on the class description for entity-specific
+ * behavior, and storing data in a dictionary.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOGenericRecord extends EOCustomObject {
+ private EOClassDescription classDescription;
+ private NSMutableDictionary dataDictionary;
+
+ /**
+ * Default constructor.
+ */
+ protected EOGenericRecord() {
+ classDescription = null;
+ dataDictionary = new NSMutableDictionary();
+ }
+
+ /**
+ * Preferred constructor.
+ */
+ public EOGenericRecord(EOClassDescription aDescription) {
+ this();
+ classDescription = aDescription;
+ }
+
+ /**
+ * Overridden to return true so that deferred faults are used.
+ */
+ public static boolean usesDeferredFaultCreation() {
+ return true;
+ }
+
+ /**
+ * Compatibility constructor: aContext and anID are ignored.
+ */
+ public EOGenericRecord(EOEditingContext aContext, EOClassDescription aDescription, EOGlobalID anID) {
+ this(aDescription);
+ }
+
+ /**
+ * Returns a class description for this object. Overridden to return the class
+ * description passed into the constructor.
+ */
+ public EOClassDescription classDescription() {
+ return classDescription;
+ }
+
+ // interface EOKeyValueCoding
+
+ /**
+ * Calls storedValueForKey.
+ */
+ public Object valueForKey(String aKey) {
+ return storedValueForKey(aKey);
+ }
+
+ /**
+ * Calls willChange and then calls takeStoredValueForKey.
+ */
+ public void takeValueForKey(Object aValue, String aKey) {
+ willChange();
+ takeStoredValueForKey(aValue, aKey);
+ }
+
+ /**
+ * Calls willRead for the specified key, and returns the corresponding value
+ * from the data dictionary. Keys that do not exist will return null.
+ */
+ public Object storedValueForKey(String aKey) {
+ willRead(aKey);
+ Object result = dataDictionary.objectForKey(aKey);
+ if (NSNull.nullValue().equals(result))
+ result = null;
+ return result;
+ }
+
+ /**
+ * Writes the specified value into the data dictionary for the specified key.
+ * Nulls are stored as NSNulls in the dictionary. No checking is performed to
+ * determine whether the key is a valid attribute key.
+ */
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ if (aValue == null)
+ aValue = NSNull.nullValue();
+ dataDictionary.setObjectForKey(aValue, aKey);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2001/11/18 18:57:10 mpowers
- * Implemented EOGenericRecord.
+ * Revision 1.1 2001/11/18 18:57:10 mpowers Implemented EOGenericRecord.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGlobalID.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGlobalID.java
index 1b4ccbe..346362c 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGlobalID.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOGlobalID.java
@@ -21,63 +21,51 @@ package net.wotonomy.control;
import java.io.Serializable;
/**
-* A pure java implementation of EOGlobalID.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public abstract class EOGlobalID implements Cloneable, Serializable
-{
- /**
- * ObjectStores broadcast this notification when they
- * replace a temporary global id with a permanent one.
- * EditingContexts listen for these notifications to
- * update their mapping of global ids to objects.
- * The object of the notification is null, and the user
- * info contains a mapping of the old temporary ids to
- * the new permanent ids.
- */
- public static final String GlobalIDChangedNotification
- = "GlobalIDChangedNotification";
-
- /**
- * Returns whether this id is a temporary id.
- * Temporary ids are generated for newly created
- * objects that have not been persisted. When
- * persisted, the temporary id is discarded in favor
- * of the one generated by the object store.
- */
- public abstract boolean isTemporary();
-
- /**
- * Returns a copy of this object.
- * This implementation calls super.clone().
- */
- public Object clone() throws CloneNotSupportedException
- {
- return super.clone();
- }
+ * A pure java implementation of EOGlobalID.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public abstract class EOGlobalID implements Cloneable, Serializable {
+ /**
+ * ObjectStores broadcast this notification when they replace a temporary global
+ * id with a permanent one. EditingContexts listen for these notifications to
+ * update their mapping of global ids to objects. The object of the notification
+ * is null, and the user info contains a mapping of the old temporary ids to the
+ * new permanent ids.
+ */
+ public static final String GlobalIDChangedNotification = "GlobalIDChangedNotification";
+
+ /**
+ * Returns whether this id is a temporary id. Temporary ids are generated for
+ * newly created objects that have not been persisted. When persisted, the
+ * temporary id is discarded in favor of the one generated by the object store.
+ */
+ public abstract boolean isTemporary();
+
+ /**
+ * Returns a copy of this object. This implementation calls super.clone().
+ */
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.4 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.3 2001/03/15 21:10:26 mpowers
- * Implemented global id re-registration for newly saved inserts.
+ * Revision 1.3 2001/03/15 21:10:26 mpowers Implemented global id
+ * re-registration for newly saved inserts.
*
- * Revision 1.2 2001/02/15 21:13:30 mpowers
- * First draft implementation is complete. Now on to debugging.
+ * Revision 1.2 2001/02/15 21:13:30 mpowers First draft implementation is
+ * complete. Now on to debugging.
*
- * Revision 1.1 2001/02/05 03:45:37 mpowers
- * Starting work on EOEditingContext.
+ * Revision 1.1 2001/02/05 03:45:37 mpowers Starting work on EOEditingContext.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOIntegralKeyGlobalID.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOIntegralKeyGlobalID.java
index ee7aac1..14f7925 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOIntegralKeyGlobalID.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOIntegralKeyGlobalID.java
@@ -18,11 +18,11 @@
package net.wotonomy.control;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class EOIntegralKeyGlobalID extends EOKeyGlobalID {
protected Number keyValue;
@@ -32,28 +32,36 @@ public class EOIntegralKeyGlobalID extends EOKeyGlobalID {
keyValue = value;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#keyValues()
*/
public Object[] keyValues() {
- return new Object[]{ keyValue };
+ return new Object[] { keyValue };
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#_keyValuesNoCopy()
*/
public Object[] _keyValuesNoCopy() {
- return new Object[]{ keyValue };
+ return new Object[] { keyValue };
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#keyCount()
*/
public int keyCount() {
return 1;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOGlobalID#isTemporary()
*/
public boolean isTemporary() {
@@ -62,11 +70,9 @@ public class EOIntegralKeyGlobalID extends EOKeyGlobalID {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/19 01:59:01 chochos
- * Added the wotonomy headers
+ * Revision 1.2 2003/08/19 01:59:01 chochos Added the wotonomy headers
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyComparisonQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyComparisonQualifier.java
index 97baaab..ef9c244 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyComparisonQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyComparisonQualifier.java
@@ -22,13 +22,11 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOKeyComparisonQualifier
- extends EOQualifier
- implements EOKeyValueArchiving, EOQualifierEvaluation {
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOKeyComparisonQualifier extends EOQualifier implements EOKeyValueArchiving, EOQualifierEvaluation {
private String _leftKey;
private String _rightKey;
@@ -54,29 +52,31 @@ public class EOKeyComparisonQualifier
}
/**
- * Evaluates this qualifier for the specified object,
- * and returns whether the object is qualified.
- * selector() is invoked on the value for key() on the
- * specified object, with value() as the parameter.
- */
+ * Evaluates this qualifier for the specified object, and returns whether the
+ * object is qualified. selector() is invoked on the value for key() on the
+ * specified object, with value() as the parameter.
+ */
public boolean evaluateWithObject(Object eo) {
try {
Object lvalue, rvalue;
- if ( eo instanceof EOKeyValueCoding) {
- lvalue = ((EOKeyValueCoding)eo).valueForKey(leftKey());
- rvalue = ((EOKeyValueCoding)eo).valueForKey(rightKey());
+ if (eo instanceof EOKeyValueCoding) {
+ lvalue = ((EOKeyValueCoding) eo).valueForKey(leftKey());
+ rvalue = ((EOKeyValueCoding) eo).valueForKey(rightKey());
} else {
lvalue = EOKeyValueCodingSupport.valueForKey(eo, leftKey());
rvalue = EOKeyValueCodingSupport.valueForKey(eo, rightKey());
}
- return ((Boolean)_selector.invoke( lvalue, rvalue)).booleanValue();
+ return ((Boolean) _selector.invoke(lvalue, rvalue)).booleanValue();
} catch (Exception exc) {
- throw new WotonomyException( exc );
+ throw new WotonomyException(exc);
}
}
- /* (non-Javadoc)
- * @see net.wotonomy.control.EOKeyValueArchiving#encodeWithKeyValueArchiver(net.wotonomy.control.EOKeyValueArchiver)
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.wotonomy.control.EOKeyValueArchiving#encodeWithKeyValueArchiver(net.
+ * wotonomy.control.EOKeyValueArchiver)
*/
public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
arch.encodeObject("EOKeyComparisonQualifier", "class");
@@ -108,10 +108,10 @@ public class EOKeyComparisonQualifier
}
public static Object decodeWithKeyValueArchiver(EOKeyValueUnarchiver arch) {
- String k = (String)arch.decodeObjectForKey("key");
- String v = (String)arch.decodeObjectForKey("value");
+ String k = (String) arch.decodeObjectForKey("key");
+ String v = (String) arch.decodeObjectForKey("value");
NSSelector sel = null;
- String sname = (String)arch.decodeObjectForKey("selectorName");
+ String sname = (String) arch.decodeObjectForKey("selectorName");
if (sname.equals("isEqualTo:"))
sel = EOQualifier.QualifierOperatorEqual;
else if (sname.equals("isNotEqualTo:"))
@@ -136,16 +136,15 @@ public class EOKeyComparisonQualifier
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/12 01:42:36 chochos
- * this qualifier was missing
+ * Revision 1.1 2003/08/12 01:42:36 chochos this qualifier was missing
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyGlobalID.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyGlobalID.java
index 76c4d05..7034f03 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyGlobalID.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyGlobalID.java
@@ -28,119 +28,117 @@ import net.wotonomy.foundation.NSCoder;
import net.wotonomy.foundation.NSCoding;
/**
-* The model object which represents the mapping between database
-* fields and object properties, lists available entities, lists
-* connection dictionaries, and has fetch specifications.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * The model object which represents the mapping between database fields and
+ * object properties, lists available entities, lists connection dictionaries,
+ * and has fetch specifications.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
-public abstract class EOKeyGlobalID extends EOGlobalID
- implements NSCoding {
+public abstract class EOKeyGlobalID extends EOGlobalID implements NSCoding {
protected String _entityName;
protected int _hash;
- protected EOKeyGlobalID(String entityName, int hashCode) {
- super();
- _entityName = entityName;
- _hash = hashCode;
- }
+ protected EOKeyGlobalID(String entityName, int hashCode) {
+ super();
+ _entityName = entityName;
+ _hash = hashCode;
+ }
- protected void _prepClone(EOKeyGlobalID gid) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ protected void _prepClone(EOKeyGlobalID gid) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public static EOKeyGlobalID globalIDWithEntityName(String s, Object aobj[]) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static EOKeyGlobalID globalIDWithEntityName(String s, Object aobj[]) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public static EOKeyGlobalID _defaultGlobalIDWithEntityName(String s, Object aobj[]) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static EOKeyGlobalID _defaultGlobalIDWithEntityName(String s, Object aobj[]) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public String entityName() {
- return _entityName;
- }
+ public String entityName() {
+ return _entityName;
+ }
- public String _literalEntityName() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public String _literalEntityName() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public boolean _isFinal() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public boolean _isFinal() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void _setGuessedEntityName(String s) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void _setGuessedEntityName(String s) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public String _guessedEntityName() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public String _guessedEntityName() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void _setSubEntityName(String s) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void _setSubEntityName(String s) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public String _subEntityName() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public String _subEntityName() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public int hashCode() {
- return _hash;
- }
+ public int hashCode() {
+ return _hash;
+ }
- public abstract Object[] keyValues();
+ public abstract Object[] keyValues();
- public abstract Object[] _keyValuesNoCopy();
+ public abstract Object[] _keyValuesNoCopy();
- public abstract int keyCount();
+ public abstract int keyCount();
- public NSArray keyValuesArray() {
- return new NSArray(keyValues());
- }
+ public NSArray keyValuesArray() {
+ return new NSArray(keyValues());
+ }
- public static Object decodeObject(NSCoder nscoder) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static Object decodeObject(NSCoder nscoder) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public static EOKeyGlobalID _adjustForInheritance(EOKeyGlobalID eokeyglobalid, String s, String s1) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static EOKeyGlobalID _adjustForInheritance(EOKeyGlobalID eokeyglobalid, String s, String s1) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void encodeWithCoder(NSCoder nscoder) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void encodeWithCoder(NSCoder nscoder) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public Class classForCoder() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public Class classForCoder() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- protected Object readResolve() throws ObjectStreamException {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ protected Object readResolve() throws ObjectStreamException {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/19 01:50:54 chochos
- * added two concrete implementations of EOKeyGlobalID.
+ * Revision 1.2 2003/08/19 01:50:54 chochos added two concrete implementations
+ * of EOKeyGlobalID.
*
- * Revision 1.1 2002/07/14 21:59:06 mpowers
- * Contributions from cgruber.
+ * Revision 1.1 2002/07/14 21:59:06 mpowers Contributions from cgruber.
*
- * Revision 1.1 2002/06/25 00:11:09 cgruber
- * Add EOKeyGlobalID, but it won't work without NSCoder.
+ * Revision 1.1 2002/06/25 00:11:09 cgruber Add EOKeyGlobalID, but it won't work
+ * without NSCoder.
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiver.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiver.java
index 3e2f808..e759c1a 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiver.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiver.java
@@ -23,15 +23,14 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSSelector;
/**
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOKeyValueArchiver {
- //for the delegate
- public static final NSSelector sel = new NSSelector("referenceToEncodeForObject",
- new Class[]{ Object.class });
+ // for the delegate
+ public static final NSSelector sel = new NSSelector("referenceToEncodeForObject", new Class[] { Object.class });
NSMutableDictionary dict = new NSMutableDictionary();
private Object _delegate;
@@ -57,7 +56,7 @@ public class EOKeyValueArchiver {
}
if (obj instanceof EOKeyValueArchiving) {
EOKeyValueArchiver arch = new EOKeyValueArchiver();
- ((EOKeyValueArchiving)obj).encodeWithKeyValueArchiver(arch);
+ ((EOKeyValueArchiving) obj).encodeWithKeyValueArchiver(arch);
dict.setObjectForKey(arch.dictionary(), key);
return;
}
@@ -85,22 +84,23 @@ public class EOKeyValueArchiver {
public void setDelegate(Object delegate) {
_delegate = delegate;
}
+
public Object delegate() {
return _delegate;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/09 01:17:53 chochos
- * Part of the EOKeyValueArchiving protocol (archives objects into NSDictionaries and vice-versa)
+ * Revision 1.1 2003/08/09 01:17:53 chochos Part of the EOKeyValueArchiving
+ * protocol (archives objects into NSDictionaries and vice-versa)
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiving.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiving.java
index 0d9f78c..97a1338 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiving.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueArchiving.java
@@ -18,24 +18,23 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
- * Remember that this method is also part of the interface:
- * public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver unarchiver)
+ * Remember that this method is also part of the interface: public static Object
+ * decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver unarchiver)
*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public interface EOKeyValueArchiving {
public abstract void encodeWithKeyValueArchiver(EOKeyValueArchiver archiver);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/09 01:17:53 chochos
- * Part of the EOKeyValueArchiving protocol (archives objects into NSDictionaries and vice-versa)
+ * Revision 1.1 2003/08/09 01:17:53 chochos Part of the EOKeyValueArchiving
+ * protocol (archives objects into NSDictionaries and vice-versa)
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCoding.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCoding.java
index b3cf926..490738c 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCoding.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCoding.java
@@ -21,109 +21,95 @@ package net.wotonomy.control;
import net.wotonomy.foundation.NSKeyValueCoding;
/**
-* EOKeyValueCoding defines an interface for classes that
-* need to have more control over the wotonomy's property
-* introspection facilities. <br><br>
-*
-* On an object that implements this interface, wotonomy
-* will call these methods, and otherwise use the static
-* methods on EOKeyValueCodingSupport. <br><br>
-*
-* EOKeyValueCodingSupport implements the default behaviors
-* for each of these methods, so classes implementing this
-* interface can call those methods to acheive the same
-* behavior. <br><br>
-*
-* valueForKey and takeValueForKey are called in response
-* to user actions, like viewing an object or updating its
-* value in a user interface. These should call the public
-* getter and setter methods on the object itself and the
-* operations should be subject to validation. <br><br>
-*
-* storedValueForKey and takeStoredValueForKey are called
-* in response to wotonomy actions, like snapshotting,
-* faulting, commits, and reverts. These operations should
-* bypass the public methods and directly modify the internal
-* state of the object without validation.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EOKeyValueCoding extends NSKeyValueCoding
-{
- /**
- * Returns the value for the specified property.
- * If the property does not exist, this method should
- * call handleQueryWithUnboundKey.
- */
- Object valueForKey( String aKey );
+ * EOKeyValueCoding defines an interface for classes that need to have more
+ * control over the wotonomy's property introspection facilities. <br>
+ * <br>
+ *
+ * On an object that implements this interface, wotonomy will call these
+ * methods, and otherwise use the static methods on EOKeyValueCodingSupport.
+ * <br>
+ * <br>
+ *
+ * EOKeyValueCodingSupport implements the default behaviors for each of these
+ * methods, so classes implementing this interface can call those methods to
+ * acheive the same behavior. <br>
+ * <br>
+ *
+ * valueForKey and takeValueForKey are called in response to user actions, like
+ * viewing an object or updating its value in a user interface. These should
+ * call the public getter and setter methods on the object itself and the
+ * operations should be subject to validation. <br>
+ * <br>
+ *
+ * storedValueForKey and takeStoredValueForKey are called in response to
+ * wotonomy actions, like snapshotting, faulting, commits, and reverts. These
+ * operations should bypass the public methods and directly modify the internal
+ * state of the object without validation.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EOKeyValueCoding extends NSKeyValueCoding {
+ /**
+ * Returns the value for the specified property. If the property does not exist,
+ * this method should call handleQueryWithUnboundKey.
+ */
+ Object valueForKey(String aKey);
- /**
- * Sets the property to the specified value.
- * If the property does not exist, this method should
- * call handleTakeValueForUnboundKey.
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey.
- */
- void takeValueForKey( Object aValue, String aKey );
+ /**
+ * Sets the property to the specified value. If the property does not exist,
+ * this method should call handleTakeValueForUnboundKey. If the property is of a
+ * type that cannot allow null (e.g. primitive types) and aValue is null, this
+ * method should call unableToSetNullForKey.
+ */
+ void takeValueForKey(Object aValue, String aKey);
- /**
- * Returns the value for the private field that
- * corresponds to the specified property.
- */
- Object storedValueForKey( String aKey );
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property.
+ */
+ Object storedValueForKey(String aKey);
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value.
- */
- void takeStoredValueForKey( Object aValue, String aKey );
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value.
+ */
+ void takeStoredValueForKey(Object aValue, String aKey);
- /**
- * Called by valueForKey when the specified key is
- * not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- Object handleQueryWithUnboundKey( String aKey );
+ /**
+ * Called by valueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ Object handleQueryWithUnboundKey(String aKey);
- /**
- * Called by takeValueForKey when the specified key
- * is not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- void handleTakeValueForUnboundKey( Object aValue, String aKey );
+ /**
+ * Called by takeValueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ void handleTakeValueForUnboundKey(Object aValue, String aKey);
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types. Implementing
- * classes should handle this case appropriately
- * or otherwise throw an exception.
- */
- void unableToSetNullForKey( String aKey );
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types. Implementing classes should
+ * handle this case appropriately or otherwise throw an exception.
+ */
+ void unableToSetNullForKey(String aKey);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.3 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.2 2001/03/28 16:12:30 mpowers
- * Documented interface.
+ * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface.
*
- * Revision 1.1 2001/03/27 23:25:05 mpowers
- * Contributing interface, no docs yet.
+ * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingAdditions.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingAdditions.java
index bc48f58..d1bb2c0 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingAdditions.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingAdditions.java
@@ -25,152 +25,127 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSKeyValueCodingAdditions;
/**
-* EOKeyValueCodingAdditions defines an interface for classes
-* that need to have more control over the wotonomy's bulk
-* property copying and cloning facilities. <br><br>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public interface EOKeyValueCodingAdditions extends EOKeyValueCoding, NSKeyValueCodingAdditions
-{
-
- /**
- * Static utilities methods that
- * call the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public class Utility extends NSKeyValueCodingAdditions.Utility
- {
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static void takeValuesFromDictionary(
- Object object, Map dictionary)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- ((NSKeyValueCodingAdditions)object).takeValuesFromDictionary(dictionary);
- } else {
- DefaultImplementation.takeValuesFromDictionary(object, dictionary);
- }
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
-/*
- public static void takeValuesFromDictionaryWithMapping(
- Object object, NSDictionary dictionary, NSDictionary mapping)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- ((NSKeyValueCodingAdditions)object).takeValuesFromDictionaryWithMapping(dictionary, mapping);
- } else {
- DefaultImplementation.takeValuesFromDictionaryWithMapping(object, dictionary, mapping);
- }
- }
-*/
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
- public static NSDictionary valuesForKeys(
- Object object, List keys)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- return ((NSKeyValueCodingAdditions)object).valuesForKeys(keys);
- } else {
- return DefaultImplementation.valuesForKeys(object, keys);
- }
- }
-
- /**
- * Calls the appropriate method if the object implements
- * NSKeyValueCodingAdditions, otherwise calls the method
- * on DefaultImplementation.
- */
-/*
- public static NSDictionary valuesForKeysWithMapping(
- Object object, NSDictionary mapping)
- {
- if (object instanceof NSKeyValueCodingAdditions) {
- return ((NSKeyValueCodingAdditions)object).valuesForKeysWithMapping(mapping);
- } else {
- return DefaultImplementation.valuesForKeysWithMapping(object, mapping);
- }
- }
-*/
- }
-
- /**
- * Provides a reflection-based implementation for classes that
- * don't implement NSKeyValueCodingAdditions.
- */
- public class DefaultImplementation extends NSKeyValueCodingAdditions.DefaultImplementation
- {
- public static void takeValuesFromDictionary(
- Object object, NSDictionary dictionary)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public static void takeValuesFromDictionaryWithMapping(
- Object object, NSDictionary dictionary, NSDictionary mapping)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public static NSDictionary valuesForKeys(
- Object object, List keys)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public static NSDictionary valuesForKeysWithMapping(
- Object object, Map mapping)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
- }
+ * EOKeyValueCodingAdditions defines an interface for classes that need to have
+ * more control over the wotonomy's bulk property copying and cloning
+ * facilities. <br>
+ * <br>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public interface EOKeyValueCodingAdditions extends EOKeyValueCoding, NSKeyValueCodingAdditions {
+
+ /**
+ * Static utilities methods that call the appropriate method if the object
+ * implements NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public class Utility extends NSKeyValueCodingAdditions.Utility {
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static void takeValuesFromDictionary(Object object, Map dictionary) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ ((NSKeyValueCodingAdditions) object).takeValuesFromDictionary(dictionary);
+ } else {
+ DefaultImplementation.takeValuesFromDictionary(object, dictionary);
+ }
+ }
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ /*
+ * public static void takeValuesFromDictionaryWithMapping( Object object,
+ * NSDictionary dictionary, NSDictionary mapping) { if (object instanceof
+ * NSKeyValueCodingAdditions) {
+ * ((NSKeyValueCodingAdditions)object).takeValuesFromDictionaryWithMapping(
+ * dictionary, mapping); } else {
+ * DefaultImplementation.takeValuesFromDictionaryWithMapping(object, dictionary,
+ * mapping); } }
+ */
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ public static NSDictionary valuesForKeys(Object object, List keys) {
+ if (object instanceof NSKeyValueCodingAdditions) {
+ return ((NSKeyValueCodingAdditions) object).valuesForKeys(keys);
+ } else {
+ return DefaultImplementation.valuesForKeys(object, keys);
+ }
+ }
+
+ /**
+ * Calls the appropriate method if the object implements
+ * NSKeyValueCodingAdditions, otherwise calls the method on
+ * DefaultImplementation.
+ */
+ /*
+ * public static NSDictionary valuesForKeysWithMapping( Object object,
+ * NSDictionary mapping) { if (object instanceof NSKeyValueCodingAdditions) {
+ * return ((NSKeyValueCodingAdditions)object).valuesForKeysWithMapping(mapping);
+ * } else { return DefaultImplementation.valuesForKeysWithMapping(object,
+ * mapping); } }
+ */
+ }
+
+ /**
+ * Provides a reflection-based implementation for classes that don't implement
+ * NSKeyValueCodingAdditions.
+ */
+ public class DefaultImplementation extends NSKeyValueCodingAdditions.DefaultImplementation {
+ public static void takeValuesFromDictionary(Object object, NSDictionary dictionary) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public static void takeValuesFromDictionaryWithMapping(Object object, NSDictionary dictionary,
+ NSDictionary mapping) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public static NSDictionary valuesForKeys(Object object, List keys) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public static NSDictionary valuesForKeysWithMapping(Object object, Map mapping) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.4 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.3 2001/12/10 15:25:11 mpowers
- * Now properly extending EOKeyValueCoding.
+ * Revision 1.3 2001/12/10 15:25:11 mpowers Now properly extending
+ * EOKeyValueCoding.
*
- * Revision 1.2 2001/04/28 14:12:23 mpowers
- * Refactored cloning/copying into KeyValueCodingUtilities.
+ * Revision 1.2 2001/04/28 14:12:23 mpowers Refactored cloning/copying into
+ * KeyValueCodingUtilities.
*
- * Revision 1.1 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.1 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
- * Revision 1.2 2001/03/28 16:12:30 mpowers
- * Documented interface.
+ * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface.
*
- * Revision 1.1 2001/03/27 23:25:05 mpowers
- * Contributing interface, no docs yet.
+ * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingSupport.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingSupport.java
index 89e3e91..70cf63c 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingSupport.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueCodingSupport.java
@@ -25,211 +25,161 @@ import net.wotonomy.foundation.internal.NullPrimitiveException;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOKeyValueCodingSupport defines default behavior for
-* classes implementing EOKeyValueSupport. <br><br>
-*
-* On an object that does not implement EOKeyValueCoding,
-* wotonomy will call the methods on this class directly.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOKeyValueCodingSupport
-{
- /**
- * Returns the value for the specified property key
- * on the specified object. <br><br>
- *
- * If the property does not exist, this method calls
- * handleQueryWithUnboundKey on the object if it
- * implements EOKeyValueCoding, otherwise calls
- * handleQueryWithUnboundKey on this class. <br><br>
- */
- static public Object valueForKey(
- Object anObject, String aKey )
- {
- //TODO: may need to handle "." nesting here so
- // that handleQueryWithUnboundKey gets called for
- // for the nested object, not the parent object
-
- //Correction: need to handle key paths in
- // KeyValueCodingAdditionsSupport.
-
- try
- {
- return Introspector.get( anObject, aKey );
- }
- catch ( IntrospectorException exc )
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey );
- }
- return handleQueryWithUnboundKey( anObject, aKey );
- }
- }
-
- /**
- * Sets the property to the specified value on
- * the specified object.
- *
- * If the property does not exist, this method calls
- * handleTakeValueForUnboundKey on the object if it
- * implements EOKeyValueCoding, otherwise calls
- * handleTakeValueForUnboundKey on this class.
- *
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey
- * on the object if it implements EOKeyValueCoding,
- * otherwise calls unableToSetNullForKey on this class.
- */
- static public void takeValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- //TODO: may need to handle "." nesting here so
- // that handleTakeValueForUnboundKey gets called for
- // for the nested object, not the parent object
-
- try
- {
- Introspector.set( anObject, aKey, aValue );
- }
- catch ( NullPrimitiveException exc )
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).unableToSetNullForKey( aKey );
- }
- else
- {
- unableToSetNullForKey( anObject, aKey );
- }
- }
- catch ( MissingPropertyException exc )
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).handleTakeValueForUnboundKey(
- aValue, aKey );
- }
- else
- {
- handleTakeValueForUnboundKey( anObject, aValue, aKey );
- }
- }
-
- }
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property on
- * the specified object.
- *
- * This implementation currently calls valueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public Object storedValueForKey(
- Object anObject, String aKey )
- {
- //TODO: this currently just calls valueForKey
- return valueForKey( anObject, aKey );
- }
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value on the
- * specified object.
- *
- * This implementation currently calls takeValueForKey,
- * because java security currently prevents us from
- * accessing the fields of another object.
- */
- static public void takeStoredValueForKey(
- Object anObject, Object aValue, String aKey )
- {
- //TODO: this currently just calls takeValueForKey
- takeValueForKey( anObject, aValue, aKey );
- }
-
- /**
- * Called by valueForKey when the specified key is
- * not found on the specified object, if that object
- * does not implement EOKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public Object handleQueryWithUnboundKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object: "
- + aKey + " : " + anObject );
- }
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on the specified object, if that object
- * does not implement EOKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void handleTakeValueForUnboundKey(
- Object anObject, Object aValue, String aKey )
- {
- throw new WotonomyException(
- "Key not found for object while setting value: "
- + aKey + " : " + anObject + " : " + aValue );
- }
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types, if the specified
- * object does not implement EOKeyValueCoding.
- *
- * This implementation throws a WotonomyException.
- */
- static public void unableToSetNullForKey(
- Object anObject, String aKey )
- {
- throw new WotonomyException(
- "Tried to key on object to null: "
- + aKey + " : " + anObject );
- }
+ * EOKeyValueCodingSupport defines default behavior for classes implementing
+ * EOKeyValueSupport. <br>
+ * <br>
+ *
+ * On an object that does not implement EOKeyValueCoding, wotonomy will call the
+ * methods on this class directly.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOKeyValueCodingSupport {
+ /**
+ * Returns the value for the specified property key on the specified object.
+ * <br>
+ * <br>
+ *
+ * If the property does not exist, this method calls handleQueryWithUnboundKey
+ * on the object if it implements EOKeyValueCoding, otherwise calls
+ * handleQueryWithUnboundKey on this class. <br>
+ * <br>
+ */
+ static public Object valueForKey(Object anObject, String aKey) {
+ // TODO: may need to handle "." nesting here so
+ // that handleQueryWithUnboundKey gets called for
+ // for the nested object, not the parent object
+
+ // Correction: need to handle key paths in
+ // KeyValueCodingAdditionsSupport.
+
+ try {
+ return Introspector.get(anObject, aKey);
+ } catch (IntrospectorException exc) {
+ if (anObject instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey);
+ }
+ return handleQueryWithUnboundKey(anObject, aKey);
+ }
+ }
+
+ /**
+ * Sets the property to the specified value on the specified object.
+ *
+ * If the property does not exist, this method calls
+ * handleTakeValueForUnboundKey on the object if it implements EOKeyValueCoding,
+ * otherwise calls handleTakeValueForUnboundKey on this class.
+ *
+ * If the property is of a type that cannot allow null (e.g. primitive types)
+ * and aValue is null, this method should call unableToSetNullForKey on the
+ * object if it implements EOKeyValueCoding, otherwise calls
+ * unableToSetNullForKey on this class.
+ */
+ static public void takeValueForKey(Object anObject, Object aValue, String aKey) {
+ // TODO: may need to handle "." nesting here so
+ // that handleTakeValueForUnboundKey gets called for
+ // for the nested object, not the parent object
+
+ try {
+ Introspector.set(anObject, aKey, aValue);
+ } catch (NullPrimitiveException exc) {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).unableToSetNullForKey(aKey);
+ } else {
+ unableToSetNullForKey(anObject, aKey);
+ }
+ } catch (MissingPropertyException exc) {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey);
+ } else {
+ handleTakeValueForUnboundKey(anObject, aValue, aKey);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property on the specified object.
+ *
+ * This implementation currently calls valueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public Object storedValueForKey(Object anObject, String aKey) {
+ // TODO: this currently just calls valueForKey
+ return valueForKey(anObject, aKey);
+ }
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value on the specified object.
+ *
+ * This implementation currently calls takeValueForKey, because java security
+ * currently prevents us from accessing the fields of another object.
+ */
+ static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) {
+ // TODO: this currently just calls takeValueForKey
+ takeValueForKey(anObject, aValue, aKey);
+ }
+
+ /**
+ * Called by valueForKey when the specified key is not found on the specified
+ * object, if that object does not implement EOKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public Object handleQueryWithUnboundKey(Object anObject, String aKey) {
+ throw new WotonomyException("Key not found for object: " + aKey + " : " + anObject);
+ }
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on the
+ * specified object, if that object does not implement EOKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) {
+ throw new WotonomyException(
+ "Key not found for object while setting value: " + aKey + " : " + anObject + " : " + aValue);
+ }
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types, if the specified object does
+ * not implement EOKeyValueCoding.
+ *
+ * This implementation throws a WotonomyException.
+ */
+ static public void unableToSetNullForKey(Object anObject, String aKey) {
+ throw new WotonomyException("Tried to key on object to null: " + aKey + " : " + anObject);
+ }
}
-
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.5 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.4 2001/05/18 21:04:33 mpowers
- * Reimplemented EditingContext.initializeObject.
+ * Revision 1.4 2001/05/18 21:04:33 mpowers Reimplemented
+ * EditingContext.initializeObject.
*
- * Revision 1.3 2001/04/27 00:28:29 mpowers
- * Fixed a return value.
+ * Revision 1.3 2001/04/27 00:28:29 mpowers Fixed a return value.
*
- * Revision 1.2 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.2 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.1 2001/03/28 17:49:33 mpowers
- * Implemented EOKeyValueCodingSupport.
+ * Revision 1.1 2001/03/28 17:49:33 mpowers Implemented EOKeyValueCodingSupport.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueQualifier.java
index 799955e..4ced471 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueQualifier.java
@@ -24,100 +24,80 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOKeyValueQualifier performs a property-based
-* comparison against a specified value. The comparison
-* is specified in the form of a NSSelector. The
-* selector is expected to take two arguments, the
-* property value on an object and the comparison value,
-* and return a Boolean indicating whether the object
-* is qualified. EOQualifier defines selectors that
-* may be used in creating EOKeyValueQualifiers.
-*
-* @author michael@mpowers.net
-* @author yjcheung@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOKeyValueQualifier extends EOQualifier
- implements EOKeyValueArchiving, EOQualifierEvaluation
-{
- private String key;
- private NSSelector selector;
- private Object value;
-
- /**
- * Constructor specifying a property key, a selector,
- * and a value for comparison. The selector may be
- * one of the constant selectors defined on EOQualifier.
- */
- public EOKeyValueQualifier(
- String aKey,
- NSSelector aSelector,
- Object aValue )
- {
- key = aKey;
- selector = aSelector;
- value = aValue;
- }
-
- /**
- * Returns the key for this qualifier.
- */
- public String key()
- {
- return key;
- }
-
- /**
- * Returns the selector for this qualifier.
- */
- public NSSelector selector()
- {
- return selector;
- }
-
- /**
- * Returns the value for this qualifier.
- */
- public Object value()
- {
- return value;
- }
-
- /**
- * Evaluates this qualifier for the specified object,
- * and returns whether the object is qualified.
- * selector() is invoked on the value for key() on the
- * specified object, with value() as the parameter.
- */
- public boolean evaluateWithObject( Object anObject )
- {
- try
- {
- Object value;
- if ( anObject instanceof EOKeyValueCoding )
- {
- value = ((EOKeyValueCoding)anObject).valueForKey( key() );
- }
- else
- {
- value = EOKeyValueCodingSupport.valueForKey( anObject, key() );
- }
- return ((Boolean)selector.invoke( value(), value)).booleanValue();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
- /**
- * Returns a string representation of this qualifier.
- */
- public String toString()
- {
- return "( " + key + " " + selector + " " + value + " )";
- }
+ * EOKeyValueQualifier performs a property-based comparison against a specified
+ * value. The comparison is specified in the form of a NSSelector. The selector
+ * is expected to take two arguments, the property value on an object and the
+ * comparison value, and return a Boolean indicating whether the object is
+ * qualified. EOQualifier defines selectors that may be used in creating
+ * EOKeyValueQualifiers.
+ *
+ * @author michael@mpowers.net
+ * @author yjcheung@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOKeyValueQualifier extends EOQualifier implements EOKeyValueArchiving, EOQualifierEvaluation {
+ private String key;
+ private NSSelector selector;
+ private Object value;
+
+ /**
+ * Constructor specifying a property key, a selector, and a value for
+ * comparison. The selector may be one of the constant selectors defined on
+ * EOQualifier.
+ */
+ public EOKeyValueQualifier(String aKey, NSSelector aSelector, Object aValue) {
+ key = aKey;
+ selector = aSelector;
+ value = aValue;
+ }
+
+ /**
+ * Returns the key for this qualifier.
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Returns the selector for this qualifier.
+ */
+ public NSSelector selector() {
+ return selector;
+ }
+
+ /**
+ * Returns the value for this qualifier.
+ */
+ public Object value() {
+ return value;
+ }
+
+ /**
+ * Evaluates this qualifier for the specified object, and returns whether the
+ * object is qualified. selector() is invoked on the value for key() on the
+ * specified object, with value() as the parameter.
+ */
+ public boolean evaluateWithObject(Object anObject) {
+ try {
+ Object value;
+ if (anObject instanceof EOKeyValueCoding) {
+ value = ((EOKeyValueCoding) anObject).valueForKey(key());
+ } else {
+ value = EOKeyValueCodingSupport.valueForKey(anObject, key());
+ }
+ return ((Boolean) selector.invoke(value(), value)).booleanValue();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
+ /**
+ * Returns a string representation of this qualifier.
+ */
+ public String toString() {
+ return "( " + key + " " + selector + " " + value + " )";
+ }
public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
arch.encodeObject("EOKeyValueQualifier", "class");
@@ -159,10 +139,10 @@ public class EOKeyValueQualifier extends EOQualifier
}
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
- String k = (String)arch.decodeObjectForKey("key");
+ String k = (String) arch.decodeObjectForKey("key");
Object v = arch.decodeObjectForKey("value");
NSSelector sel = null;
- String sname = (String)arch.decodeObjectForKey("selectorName");
+ String sname = (String) arch.decodeObjectForKey("selectorName");
if (sname.equals("isEqualTo:"))
sel = EOQualifier.QualifierOperatorEqual;
else if (sname.equals("isNotEqualTo:"))
@@ -188,46 +168,42 @@ public class EOKeyValueQualifier extends EOQualifier
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.10 2003/08/12 01:43:04 chochos
- * formally implement EOQualifierEvaluation
+ * Revision 1.10 2003/08/12 01:43:04 chochos formally implement
+ * EOQualifierEvaluation
*
- * Revision 1.9 2003/08/11 19:39:30 chochos
- * special conditions for NSKeyValueCoding.NullValue -> EONull
+ * Revision 1.9 2003/08/11 19:39:30 chochos special conditions for
+ * NSKeyValueCoding.NullValue -> EONull
*
- * Revision 1.8 2003/08/09 01:22:51 chochos
- * qualifiers implement EOKeyValueArchiving
+ * Revision 1.8 2003/08/09 01:22:51 chochos qualifiers implement
+ * EOKeyValueArchiving
*
- * Revision 1.7 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2001/10/31 15:26:06 mpowers
- * Fixed typo.
+ * Revision 1.6 2001/10/31 15:26:06 mpowers Fixed typo.
*
- * Revision 1.5 2001/10/31 15:25:14 mpowers
- * Cleanup of qualifiers.
+ * Revision 1.5 2001/10/31 15:25:14 mpowers Cleanup of qualifiers.
*
- * Revision 1.4 2001/10/30 22:57:28 mpowers
- * EOQualifier framework is now working.
+ * Revision 1.4 2001/10/30 22:57:28 mpowers EOQualifier framework is now
+ * working.
*
- * Revision 1.3 2001/09/13 15:25:56 mpowers
- * Started implementation of the EOQualifier framework.
+ * Revision 1.3 2001/09/13 15:25:56 mpowers Started implementation of the
+ * EOQualifier framework.
*
- * Revision 1.2 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.2 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
- * Revision 1.1 2001/02/27 03:33:04 mpowers
- * Initial draft of the key-value qualifier.
+ * Revision 1.1 2001/02/27 03:33:04 mpowers Initial draft of the key-value
+ * qualifier.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueUnarchiver.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueUnarchiver.java
index caed8a4..5238c70 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueUnarchiver.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOKeyValueUnarchiver.java
@@ -22,17 +22,18 @@ import java.lang.reflect.Method;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSKeyValueCoding;
-/** Creates objects from dictionaries that were created with
- * EOKeyValueArchiver.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+/**
+ * Creates objects from dictionaries that were created with EOKeyValueArchiver.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOKeyValueUnarchiver {
NSDictionary dict;
Object _delegate;
- protected static final Class[] METHOD_ARGS = new Class[]{ EOKeyValueUnarchiver.class };
+ protected static final Class[] METHOD_ARGS = new Class[] { EOKeyValueUnarchiver.class };
public EOKeyValueUnarchiver(NSDictionary archive) {
super();
@@ -54,7 +55,7 @@ public class EOKeyValueUnarchiver {
if (x == null)
return 0;
if (x instanceof Number)
- return ((Number)x).intValue();
+ return ((Number) x).intValue();
try {
int i = Integer.parseInt(x.toString());
return i;
@@ -68,7 +69,7 @@ public class EOKeyValueUnarchiver {
if (x == null)
return null;
if (x instanceof NSDictionary) {
- NSDictionary d = (NSDictionary)x;
+ NSDictionary d = (NSDictionary) x;
if (d.objectForKey("class") != null) {
String cname = d.objectForKey("class").toString();
Class _class = null;
@@ -82,11 +83,11 @@ public class EOKeyValueUnarchiver {
if (d.objectForKey("value") != null)
return d.objectForKey("value").toString();
} else if (cname.equals("EONull")) {
- return NSKeyValueCoding.NullValue;
+ return NSKeyValueCoding.NullValue;
} else if (cname.equals("EOFetchSpecification")) {
_class = EOFetchSpecification.class;
} else if (cname.equals("EOKeyValueQualifier")) {
- _class = EOKeyValueQualifier.class;
+ _class = EOKeyValueQualifier.class;
} else if (cname.equals("EONotQualifier")) {
_class = EONotQualifier.class;
} else if (cname.equals("EOAndQualifier")) {
@@ -95,12 +96,12 @@ public class EOKeyValueUnarchiver {
_class = EOOrQualifier.class;
} else if (cname.equals("EOSortOrdering")) {
_class = EOSortOrdering.class;
- } else if (cname.indexOf(".") < 0) { //Load a class without package
+ } else if (cname.indexOf(".") < 0) { // Load a class without package
try {
_class = Class.forName("net.wotonomy.control." + cname);
} catch (ClassNotFoundException ex) {
}
- //search for the class in access
+ // search for the class in access
if (_class == null) {
try {
_class = Class.forName("net.wotonomy.access." + cname);
@@ -117,7 +118,7 @@ public class EOKeyValueUnarchiver {
return x;
try {
Method met = _class.getMethod("decodeWithKeyValueUnarchiver", METHOD_ARGS);
- return met.invoke(null, new Object[]{ new EOKeyValueUnarchiver(d) });
+ return met.invoke(null, new Object[] { new EOKeyValueUnarchiver(d) });
} catch (Exception ex) {
ex.printStackTrace();
return x;
@@ -144,22 +145,23 @@ public class EOKeyValueUnarchiver {
public void setDelegate(Object del) {
_delegate = del;
}
+
public Object delegate() {
return _delegate;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/11 18:17:41 chochos
- * decoding of objects now works properly
+ * Revision 1.2 2003/08/11 18:17:41 chochos decoding of objects now works
+ * properly
*
*/ \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONotQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONotQualifier.java
index d086840..1068fd7 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONotQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONotQualifier.java
@@ -21,54 +21,46 @@ package net.wotonomy.control;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EONotQualifiier negates a specified qualifier,
-* evaluating to the opposite of the specified qualifier.
-*
-* @author michael@mpowers.net
-* @author yjcheung@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EONotQualifier extends EOQualifier
- implements EOKeyValueArchiving, EOQualifierEvaluation
-{
- private EOQualifier qualifier;
+ * EONotQualifiier negates a specified qualifier, evaluating to the opposite of
+ * the specified qualifier.
+ *
+ * @author michael@mpowers.net
+ * @author yjcheung@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EONotQualifier extends EOQualifier implements EOKeyValueArchiving, EOQualifierEvaluation {
+ private EOQualifier qualifier;
- public EONotQualifier(
- EOQualifier aQualifier )
- {
- qualifier = aQualifier;
- }
+ public EONotQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
- /**
- * Returns the qualifier that this qualifier negates.
- */
- public EOQualifier qualifier()
- {
- return qualifier;
- }
+ /**
+ * Returns the qualifier that this qualifier negates.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
- /**
- * Evaluates this qualifier for the specified object,
- * and returns whether the object is qualified.
- * evaluateWithObject is invoked on qualifier
- * and the result is negated and returned.
- */
- public boolean evaluateWithObject( Object anObject )
- {
- return !(qualifier.evaluateWithObject(anObject));
- }
+ /**
+ * Evaluates this qualifier for the specified object, and returns whether the
+ * object is qualified. evaluateWithObject is invoked on qualifier and the
+ * result is negated and returned.
+ */
+ public boolean evaluateWithObject(Object anObject) {
+ return !(qualifier.evaluateWithObject(anObject));
+ }
- /**
- * Returns a string representation of this qualifier.
- */
- public String toString()
- {
- return (new StringBuffer("Not ").append(qualifier.toString()).toString());
- }
+ /**
+ * Returns a string representation of this qualifier.
+ */
+ public String toString() {
+ return (new StringBuffer("Not ").append(qualifier.toString()).toString());
+ }
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
- EOQualifier q = (EOQualifier)arch.decodeObjectForKey("qualifier");
+ EOQualifier q = (EOQualifier) arch.decodeObjectForKey("qualifier");
if (q == null)
return null;
return new EONotQualifier(q);
@@ -78,7 +70,7 @@ public class EONotQualifier extends EOQualifier
arch.encodeObject("EONotQualifier", "class");
if (qualifier instanceof EOKeyValueArchiving) {
EOKeyValueArchiver ar2 = new EOKeyValueArchiver();
- ((EOKeyValueArchiving)qualifier).encodeWithKeyValueArchiver(ar2);
+ ((EOKeyValueArchiving) qualifier).encodeWithKeyValueArchiver(ar2);
arch.encodeObject(ar2.dictionary(), "qualifiers");
} else
throw new WotonomyException("Cannot archive instance of " + qualifier.getClass().getName());
@@ -87,43 +79,37 @@ public class EONotQualifier extends EOQualifier
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2003/08/12 01:43:04 chochos
- * formally implement EOQualifierEvaluation
+ * Revision 1.9 2003/08/12 01:43:04 chochos formally implement
+ * EOQualifierEvaluation
*
- * Revision 1.8 2003/08/11 19:39:30 chochos
- * special conditions for NSKeyValueCoding.NullValue -> EONull
+ * Revision 1.8 2003/08/11 19:39:30 chochos special conditions for
+ * NSKeyValueCoding.NullValue -> EONull
*
- * Revision 1.7 2003/08/09 01:24:19 chochos
- * implements EOKeyValueArchiving
+ * Revision 1.7 2003/08/09 01:24:19 chochos implements EOKeyValueArchiving
*
- * Revision 1.6 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.6 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.5 2001/10/31 15:25:14 mpowers
- * Cleanup of qualifiers.
+ * Revision 1.5 2001/10/31 15:25:14 mpowers Cleanup of qualifiers.
*
- * Revision 1.4 2001/10/30 22:57:28 mpowers
- * EOQualifier framework is now working.
+ * Revision 1.4 2001/10/30 22:57:28 mpowers EOQualifier framework is now
+ * working.
*
- * Revision 1.3 2001/09/13 15:42:20 mpowers
- * Fixed another cut/paste typo.
+ * Revision 1.3 2001/09/13 15:42:20 mpowers Fixed another cut/paste typo.
*
- * Revision 1.2 2001/09/13 15:41:34 mpowers
- * Fixed typo.
+ * Revision 1.2 2001/09/13 15:41:34 mpowers Fixed typo.
*
- * Revision 1.1 2001/09/13 15:38:19 mpowers
- * Started implementation of the EOQualifier framework.
+ * Revision 1.1 2001/09/13 15:38:19 mpowers Started implementation of the
+ * EOQualifier framework.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONullValue.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONullValue.java
index 3b4544e..1ecce4d 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONullValue.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EONullValue.java
@@ -23,91 +23,84 @@ import java.io.Serializable;
import net.wotonomy.foundation.NSNull;
/**
-* EONullValue is used to represent null in Collections classes
-* because List and Map do not specify whether null values
-* are allowed and because NSArray and NSDictionary explicitly
-* do not allow null values. <br><br>
-*
-* Use of the static singleton method nullValue() is required
-* by this implementation because Java cannot return a singleton
-* instance from a constructor. <br><br>
-*
-* This implementation duplicates NSNull, but the singleton instances
-* are of course different. Be careful. I have no idea why this
-* class was even created, given that NSNull exists.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EONullValue implements Serializable
-{
- private static final EONullValue instance = new EONullValue();
-
- /**
- * Create a new instance of EONullValue.
- */
- private EONullValue ()
- {
- }
+ * EONullValue is used to represent null in Collections classes because List and
+ * Map do not specify whether null values are allowed and because NSArray and
+ * NSDictionary explicitly do not allow null values. <br>
+ * <br>
+ *
+ * Use of the static singleton method nullValue() is required by this
+ * implementation because Java cannot return a singleton instance from a
+ * constructor. <br>
+ * <br>
+ *
+ * This implementation duplicates NSNull, but the singleton instances are of
+ * course different. Be careful. I have no idea why this class was even created,
+ * given that NSNull exists.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EONullValue implements Serializable {
+ private static final EONullValue instance = new EONullValue();
- /**
- * Constructor specifying name and object.
- */
- public static EONullValue nullValue ()
- {
- return instance;
- }
+ /**
+ * Create a new instance of EONullValue.
+ */
+ private EONullValue() {
+ }
- /**
- * Returns a human-readable string representation.
- */
- public String toString()
- {
- return "[null]";
- }
-
- /**
- * Hashcode of all instances is zero.
- */
- public int hashCode()
- {
- return 0;
- }
-
- /**
- * Implemented to return true for any instance of EONullValue
- * and for any instance of NSNull.
- */
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof EONullValue ) return true;
- if ( anObject instanceof NSNull ) return true;
- return false;
- }
+ /**
+ * Constructor specifying name and object.
+ */
+ public static EONullValue nullValue() {
+ return instance;
+ }
+
+ /**
+ * Returns a human-readable string representation.
+ */
+ public String toString() {
+ return "[null]";
+ }
+
+ /**
+ * Hashcode of all instances is zero.
+ */
+ public int hashCode() {
+ return 0;
+ }
+
+ /**
+ * Implemented to return true for any instance of EONullValue and for any
+ * instance of NSNull.
+ */
+ public boolean equals(Object anObject) {
+ if (anObject instanceof EONullValue)
+ return true;
+ if (anObject instanceof NSNull)
+ return true;
+ return false;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2001/03/01 20:35:38 mpowers
- * Implemented equals and hashCode.
+ * Revision 1.2 2001/03/01 20:35:38 mpowers Implemented equals and hashCode.
*
- * Revision 1.1 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.1 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStore.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStore.java
index cd18e36..4f60045 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStore.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStore.java
@@ -24,297 +24,234 @@ import java.util.Map;
import net.wotonomy.foundation.NSArray;
/**
-* EOObjectStore defines an object repository that tracks
-* object creations, deletions, and updates made by
-* EOEditingContexts. <br><br>
-*
-* A concrete implementation would probably write these
-* changes to some kind of persistent storage, like a
-* database. <br><br>
-*
-* EOEditingContext is itself a subclass of EOObjectStore
-* that requires an EOObjectStore parent for committing
-* its changes. This means that EOEditingContexts can
-* use other EOEditingContexts as their parent, but there
-* still must exist an EOObjectStore as the root of the
-* editing graph.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public abstract class EOObjectStore
-{
- /**
- * Key for the user info of ObjectsChangedInStoreNotifications.
- * The key should retrieve an array of deleted EOGlobalIDs.
- */
- public static final String DeletedKey = "deleted";
+ * EOObjectStore defines an object repository that tracks object creations,
+ * deletions, and updates made by EOEditingContexts. <br>
+ * <br>
+ *
+ * A concrete implementation would probably write these changes to some kind of
+ * persistent storage, like a database. <br>
+ * <br>
+ *
+ * EOEditingContext is itself a subclass of EOObjectStore that requires an
+ * EOObjectStore parent for committing its changes. This means that
+ * EOEditingContexts can use other EOEditingContexts as their parent, but there
+ * still must exist an EOObjectStore as the root of the editing graph.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public abstract class EOObjectStore {
+ /**
+ * Key for the user info of ObjectsChangedInStoreNotifications. The key should
+ * retrieve an array of deleted EOGlobalIDs.
+ */
+ public static final String DeletedKey = "deleted";
+
+ /**
+ * Key for the user info of ObjectsChangedInStoreNotifications. The key should
+ * retrieve an array of inserted EOGlobalIDs.
+ */
+ public static final String InsertedKey = "inserted";
+
+ /**
+ * Key for the user info of ObjectsChangedInStoreNotifications. The key should
+ * retrieve an array of updated EOGlobalIDs. EOEditingContexts should refault
+ * their copies of these objects.
+ */
+ public static final String UpdatedKey = "updated";
+
+ /**
+ * Key for the user info of ObjectsChangedInStoreNotification. The key should
+ * retrieve an array of EOGlobalIDs.
+ */
+ public static final String InvalidatedKey = "invalidated";
+
+ /**
+ * Key for the NSNotification posted when this object store is asked to
+ * invalidate all objects. Object of the notification will be this object store,
+ * and user info will contain the InvalidatedKey.
+ */
+ public static final String InvalidatedAllObjectsInStoreNotification = "EOInvalidatedAllObjectsInStoreNotification";
+
+ /**
+ * Key for the NSNotification posted when this object store is changed. Object
+ * of the notification will be this object store, and user info will contain
+ * InsertedKey, UpdatedKey, DeletedKey, and InvalidatedKey.
+ */
+ public static final String ObjectsChangedInStoreNotification = "EOObjectsChangedInStoreNotification";
- /**
- * Key for the user info of ObjectsChangedInStoreNotifications.
- * The key should retrieve an array of inserted EOGlobalIDs.
- */
- public static final String InsertedKey = "inserted";
+ /**
+ * Default constructor is responsible for initializing internal state.
+ */
+ public EOObjectStore() {
+ }
- /**
- * Key for the user info of ObjectsChangedInStoreNotifications.
- * The key should retrieve an array of updated EOGlobalIDs.
- * EOEditingContexts should refault their copies of these objects.
- */
- public static final String UpdatedKey = "updated";
+ /**
+ * Called by editing contexts when they no longer need to track the specified
+ * id. You will not need to call this method, but you use use it for a hint that
+ * the specified global id is not in use by that child editing context.
+ */
+ public void editingContextDidForgetObjectWithGlobalID(EOEditingContext aContext, EOGlobalID aGlobalID) {
+ }
- /**
- * Key for the user info of ObjectsChangedInStoreNotification.
- * The key should retrieve an array of EOGlobalIDs.
- */
- public static final String InvalidatedKey = "invalidated";
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship, or may return a placeholder array
+ * that will defer the fetch until accessed (an array fault). All objects must
+ * be registered the specified editing context. The specified relationship key
+ * must produce a result of type Collection for the source object or an
+ * exception is thrown.
+ */
+ public abstract NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationship,
+ EOEditingContext aContext);
- /**
- * Key for the NSNotification posted when this object store
- * is asked to invalidate all objects. Object of the notification
- * will be this object store, and user info will contain the
- * InvalidatedKey.
- */
- public static final String
- InvalidatedAllObjectsInStoreNotification =
- "EOInvalidatedAllObjectsInStoreNotification";
+ /**
+ * Returns the object for the specified id. The returned object may be a fault.
+ * The object will be registered in the specified editing context.
+ */
+ public abstract /* EOEnterpriseObject */ Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext);
- /**
- * Key for the NSNotification posted when this object store
- * is changed. Object of the notification will be this object
- * store, and user info will contain InsertedKey, UpdatedKey,
- * DeletedKey, and InvalidatedKey.
- */
- public static final String
- ObjectsChangedInStoreNotification =
- "EOObjectsChangedInStoreNotification";
-
- /**
- * Default constructor is responsible for initializing
- * internal state.
- */
- public EOObjectStore ()
- {
- }
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. The fault should belong to the
+ * specified editing context.
+ */
+ public abstract /* EOEnterpriseObject */ Object faultForRawRow(Map aDictionary, String anEntityName,
+ EOEditingContext aContext);
- /**
- * Called by editing contexts when they no longer
- * need to track the specified id. You will not need
- * to call this method, but you use use it for a hint
- * that the specified global id is not in use by that
- * child editing context.
- */
- public void editingContextDidForgetObjectWithGlobalID (
- EOEditingContext aContext,
- EOGlobalID aGlobalID )
- {
- }
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship, or may return a placeholder array that
- * will defer the fetch until accessed (an array fault).
- * All objects must be registered the specified editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public abstract NSArray arrayFaultWithSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext );
-
- /**
- * Returns the object for the specified id.
- * The returned object may be a fault.
- * The object will be registered in the
- * specified editing context.
- */
- public abstract /*EOEnterpriseObject*/ Object faultForGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext );
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary. The fault should
- * belong to the specified editing context.
- */
- public abstract /*EOEnterpriseObject*/ Object faultForRawRow (
- Map aDictionary,
- String anEntityName,
- EOEditingContext aContext );
-
- /**
- * Given a newly instantiated object, this method
- * initializes its properties to values appropriate
- * for the specified id. The object should already
- * belong to the specified editing context.
- * This method is called to populate faults.
- */
- public abstract void initializeObject (
- /*EOEnterpriseObject*/ Object eo,
- EOGlobalID aGlobalID,
- EOEditingContext aContext );
-
- /**
- * Remove all values from all objects in memory,
- * turning them into faults, and posts an NSNotification
- * that all objects have been invalidated.
- * The notification should be named with the string
- * constant InvalidatedAllObjectsInStoreNotification
- * with this object store as the object and no user info.
- */
- public abstract void invalidateAllObjects ();
-
- /**
- * Removes values with the specified ids from memory,
- * turning them into faults, and posts a notification
- * that those objects have been invalidated.
- * The notification should be named with the string
- * constant ObjectsChangedInStoreNotification
- * with this object store as the object and user info
- * containing a key named InvalidateKey that returns
- * a List of the EOGlobalIDs of the invalidated objects.
- */
- public abstract void invalidateObjectsWithGlobalIDs (
- List aList );
-
- /**
- * Returns whether the object corresponding to the
- * specified id is locked. The concept of object
- * locking is implementation-specific.
- */
- public abstract boolean isObjectLockedWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext );
-
- /**
- * Locks the object corresponding to the
- * specified id is locked. The concept of object
- * locking is implementation-specific.
- * The lock may be released when objects are
- * invalidated or commited, but this behavior
- * is not required.
- */
- public abstract void lockObjectWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext );
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship. This method may not return an array fault
- * because array faults call this method to fetch on demand.
- * All objects must be registered the specified editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public abstract NSArray objectsForSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext );
-
- /**
- * Returns a List of objects the meet the criteria of
- * the supplied specification. Faults are not allowed in the array.
- * Each object is registered with the specified editing context.
- * If any object is already fetched in the specified context,
- * it is not refetched and that object should be used in the array.
- */
- public abstract NSArray objectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec,
- EOEditingContext aContext );
-
- /**
- * Removes all values from the specified object,
- * converting it into a fault for the specified id.
- * New or deleted objects should not be refaulted.
- */
- public abstract void refaultObject (
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext );
-
- /**
- * Writes all changes in the specified editing context
- * to the respository. The object store is expected to
- * post a notification that should be named with the string
- * constant ObjectsChangedInStoreNotification
- * with this object store as the object and user info
- * containing keys named UpdatedKey, InsertedKey, and
- * DeletedKey that return Lists of the EOGlobalIDs of the
- * corresponding objects.
- */
- public abstract void saveChangesInEditingContext (
- EOEditingContext aContext );
+ /**
+ * Given a newly instantiated object, this method initializes its properties to
+ * values appropriate for the specified id. The object should already belong to
+ * the specified editing context. This method is called to populate faults.
+ */
+ public abstract void initializeObject(/* EOEnterpriseObject */ Object eo, EOGlobalID aGlobalID,
+ EOEditingContext aContext);
+
+ /**
+ * Remove all values from all objects in memory, turning them into faults, and
+ * posts an NSNotification that all objects have been invalidated. The
+ * notification should be named with the string constant
+ * InvalidatedAllObjectsInStoreNotification with this object store as the object
+ * and no user info.
+ */
+ public abstract void invalidateAllObjects();
+
+ /**
+ * Removes values with the specified ids from memory, turning them into faults,
+ * and posts a notification that those objects have been invalidated. The
+ * notification should be named with the string constant
+ * ObjectsChangedInStoreNotification with this object store as the object and
+ * user info containing a key named InvalidateKey that returns a List of the
+ * EOGlobalIDs of the invalidated objects.
+ */
+ public abstract void invalidateObjectsWithGlobalIDs(List aList);
+
+ /**
+ * Returns whether the object corresponding to the specified id is locked. The
+ * concept of object locking is implementation-specific.
+ */
+ public abstract boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext);
+
+ /**
+ * Locks the object corresponding to the specified id is locked. The concept of
+ * object locking is implementation-specific. The lock may be released when
+ * objects are invalidated or commited, but this behavior is not required.
+ */
+ public abstract void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext);
+
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship. This method may not return an array
+ * fault because array faults call this method to fetch on demand. All objects
+ * must be registered the specified editing context. The specified relationship
+ * key must produce a result of type Collection for the source object or an
+ * exception is thrown.
+ */
+ public abstract NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationship,
+ EOEditingContext aContext);
+
+ /**
+ * Returns a List of objects the meet the criteria of the supplied
+ * specification. Faults are not allowed in the array. Each object is registered
+ * with the specified editing context. If any object is already fetched in the
+ * specified context, it is not refetched and that object should be used in the
+ * array.
+ */
+ public abstract NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext);
+
+ /**
+ * Removes all values from the specified object, converting it into a fault for
+ * the specified id. New or deleted objects should not be refaulted.
+ */
+ public abstract void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext);
+
+ /**
+ * Writes all changes in the specified editing context to the respository. The
+ * object store is expected to post a notification that should be named with the
+ * string constant ObjectsChangedInStoreNotification with this object store as
+ * the object and user info containing keys named UpdatedKey, InsertedKey, and
+ * DeletedKey that return Lists of the EOGlobalIDs of the corresponding objects.
+ */
+ public abstract void saveChangesInEditingContext(EOEditingContext aContext);
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.15 2003/12/18 15:37:38 mpowers
- * Changes to retain ability to work with objects that don't necessarily
- * implement EOEnterpriseObject. I would still like to preserve this case
- * for general usage, however the access package is free to assume that
- * those objects will be EOs and cast appropriately.
+ * Revision 1.15 2003/12/18 15:37:38 mpowers Changes to retain ability to work
+ * with objects that don't necessarily implement EOEnterpriseObject. I would
+ * still like to preserve this case for general usage, however the access
+ * package is free to assume that those objects will be EOs and cast
+ * appropriately.
*
- * Revision 1.14 2003/08/19 01:53:12 chochos
- * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ * Revision 1.14 2003/08/19 01:53:12 chochos EOObjectStore had some incompatible
+ * return types (Object instead of EOEnterpriseObject, in fault methods mostly).
+ * It's internally consistent but I hope it doesn't break anything based on
+ * this, even though fault methods mostly throw exceptions for now.
*
- * Revision 1.13 2002/02/13 21:20:15 mpowers
- * Updated comments.
+ * Revision 1.13 2002/02/13 21:20:15 mpowers Updated comments.
*
- * Revision 1.12 2001/05/05 23:05:42 mpowers
- * Implemented Array Faults.
+ * Revision 1.12 2001/05/05 23:05:42 mpowers Implemented Array Faults.
*
- * Revision 1.11 2001/02/21 21:17:32 mpowers
- * Now retaining a reference to the recent changes observer.
- * Better documented need to retain reference.
- * Started implementing notifications.
+ * Revision 1.11 2001/02/21 21:17:32 mpowers Now retaining a reference to the
+ * recent changes observer. Better documented need to retain reference. Started
+ * implementing notifications.
*
- * Revision 1.10 2001/02/16 22:51:29 mpowers
- * Now deep-cloning objects passed between editing contexts.
+ * Revision 1.10 2001/02/16 22:51:29 mpowers Now deep-cloning objects passed
+ * between editing contexts.
*
- * Revision 1.9 2001/02/16 18:34:19 mpowers
- * Implementing nested contexts.
+ * Revision 1.9 2001/02/16 18:34:19 mpowers Implementing nested contexts.
*
- * Revision 1.8 2001/02/15 21:13:30 mpowers
- * First draft implementation is complete. Now on to debugging.
+ * Revision 1.8 2001/02/15 21:13:30 mpowers First draft implementation is
+ * complete. Now on to debugging.
*
- * Revision 1.7 2001/02/14 23:03:02 mpowers
- * A near-complete first draft of EOEditingContext.
+ * Revision 1.7 2001/02/14 23:03:02 mpowers A near-complete first draft of
+ * EOEditingContext.
*
- * Revision 1.6 2001/02/13 23:24:29 mpowers
- * Implementing more of editing context.
+ * Revision 1.6 2001/02/13 23:24:29 mpowers Implementing more of editing
+ * context.
*
- * Revision 1.5 2001/02/12 20:36:36 mpowers
- * Documented methods.
+ * Revision 1.5 2001/02/12 20:36:36 mpowers Documented methods.
*
- * Revision 1.4 2001/02/09 22:09:34 mpowers
- * Completed implementation of EOObjectStore.
+ * Revision 1.4 2001/02/09 22:09:34 mpowers Completed implementation of
+ * EOObjectStore.
*
- * Revision 1.3 2001/02/06 15:24:11 mpowers
- * Widened parameters on abstract method to fix build.
+ * Revision 1.3 2001/02/06 15:24:11 mpowers Widened parameters on abstract
+ * method to fix build.
*
- * Revision 1.2 2001/02/06 14:57:42 mpowers
- * Defined abstract methods.
+ * Revision 1.2 2001/02/06 14:57:42 mpowers Defined abstract methods.
*
- * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStoreCoordinator.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStoreCoordinator.java
index e9a3a6a..c2ad03d 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStoreCoordinator.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObjectStoreCoordinator.java
@@ -27,178 +27,172 @@ import java.util.Map;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSNotification;
+
/**
-* A representation of a channel of communication to the database.
-*
-* @author cgruber@israfil.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
+ * A representation of a channel of communication to the database.
+ *
+ * @author cgruber@israfil.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
public class EOObjectStoreCoordinator extends EOObjectStore {
- public static final String CooperatingObjectStoreWasAddedNotification = "EOCooperatingObjectStoreWasAddedNotification";
- public static final String CooperatingObjectStoreWasRemovedNotification = "EOCooperatingObjectStoreWasRemovedNotification";
- public static final String CooperatingObjectStoreNeededNotification = "EOCooperatingObjectStoreNeededNotification";
- public static final String GlobalIDKey = "globalID";
- public static final String FetchSpecificationKey = "fetchSpecification";
- public static final String ObjectKey = "object";
+ public static final String CooperatingObjectStoreWasAddedNotification = "EOCooperatingObjectStoreWasAddedNotification";
+ public static final String CooperatingObjectStoreWasRemovedNotification = "EOCooperatingObjectStoreWasRemovedNotification";
+ public static final String CooperatingObjectStoreNeededNotification = "EOCooperatingObjectStoreNeededNotification";
+ public static final String GlobalIDKey = "globalID";
+ public static final String FetchSpecificationKey = "fetchSpecification";
+ public static final String ObjectKey = "object";
- public static synchronized EOObjectStoreCoordinator defaultCoordinator() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static synchronized EOObjectStoreCoordinator defaultCoordinator() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public static synchronized void setDefaultCoordinator(EOObjectStoreCoordinator eoobjectstorecoordinator) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public static synchronized void setDefaultCoordinator(EOObjectStoreCoordinator eoobjectstorecoordinator) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public EOObjectStoreCoordinator() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public EOObjectStoreCoordinator() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void dispose() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void dispose() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- private NSArray _sources() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ private NSArray _sources() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSArray cooperatingObjectStores() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSArray cooperatingObjectStores() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void addCooperatingObjectStore(EOCooperatingObjectStore eocooperatingobjectstore) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void addCooperatingObjectStore(EOCooperatingObjectStore eocooperatingobjectstore) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void removeCooperatingObjectStore(EOCooperatingObjectStore eocooperatingobjectstore) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void removeCooperatingObjectStore(EOCooperatingObjectStore eocooperatingobjectstore) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public EOCooperatingObjectStore objectStoreForGlobalID(EOGlobalID eoglobalid) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public EOCooperatingObjectStore objectStoreForGlobalID(EOGlobalID eoglobalid) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public EOCooperatingObjectStore objectStoreForObject(EOEnterpriseObject eoenterpriseobject) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public EOCooperatingObjectStore objectStoreForObject(EOEnterpriseObject eoenterpriseobject) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public EOCooperatingObjectStore objectStoreForFetchSpecification(EOFetchSpecification eofetchspecification) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public EOCooperatingObjectStore objectStoreForFetchSpecification(EOFetchSpecification eofetchspecification) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- EOCooperatingObjectStore objectStoreForEntityNamed(String s) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ EOCooperatingObjectStore objectStoreForEntityNamed(String s) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void forwardUpdateForObject(EOEnterpriseObject eoenterpriseobject, NSDictionary nsdictionary) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void forwardUpdateForObject(EOEnterpriseObject eoenterpriseobject, NSDictionary nsdictionary) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSDictionary valuesForKeys(NSArray nsarray, EOEnterpriseObject eoenterpriseobject) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSDictionary valuesForKeys(NSArray nsarray, EOEnterpriseObject eoenterpriseobject) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void saveChangesInEditingContext(EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void saveChangesInEditingContext(EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSArray objectsWithFetchSpecification(EOFetchSpecification eofetchspecification, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification eofetchspecification,
+ EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public boolean isObjectLockedWithGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public boolean isObjectLockedWithGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void lockObjectWithGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void lockObjectWithGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public /*EOEnterpriseObject*/ Object faultForGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public /* EOEnterpriseObject */ Object faultForGlobalID(EOGlobalID eoglobalid, EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public /*EOEnterpriseObject*/ Object faultForRawRow(NSDictionary nsdictionary, String s, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public /* EOEnterpriseObject */ Object faultForRawRow(NSDictionary nsdictionary, String s,
+ EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSArray arrayFaultWithSourceGlobalID(EOGlobalID eoglobalid, String s, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID eoglobalid, String s, EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void editingContextDidForgetObjectWithGlobalID(EOEditingContext eoeditingcontext, EOGlobalID eoglobalid) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void editingContextDidForgetObjectWithGlobalID(EOEditingContext eoeditingcontext, EOGlobalID eoglobalid) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSArray objectsForSourceGlobalID(EOGlobalID eoglobalid, String s, EOEditingContext eoeditingcontext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSArray objectsForSourceGlobalID(EOGlobalID eoglobalid, String s, EOEditingContext eoeditingcontext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void invalidateObjectsWithGlobalIDs(NSArray nsarray) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void invalidateObjectsWithGlobalIDs(NSArray nsarray) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void invalidateAllObjects() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void invalidateAllObjects() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void _objectsChangedInSubStore(NSNotification nsnotification) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void _objectsChangedInSubStore(NSNotification nsnotification) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void _invalidatedAllObjectsInSubStore(NSNotification nsnotification) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void _invalidatedAllObjectsInSubStore(NSNotification nsnotification) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public void setUserInfo(NSDictionary nsdictionary) {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public void setUserInfo(NSDictionary nsdictionary) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
- public NSDictionary userInfo() {
- throw new UnsupportedOperationException("Not Yet Implemented");
- }
+ public NSDictionary userInfo() {
+ throw new UnsupportedOperationException("Not Yet Implemented");
+ }
/**
- * @see net.wotonomy.control.EOObjectStore#faultForRawRow(Map, String, EOEditingContext)
+ * @see net.wotonomy.control.EOObjectStore#faultForRawRow(Map, String,
+ * EOEditingContext)
*/
- public /*EOEnterpriseObject*/ Object faultForRawRow(
- Map aDictionary,
- String anEntityName,
- EOEditingContext aContext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
+ public /* EOEnterpriseObject */ Object faultForRawRow(Map aDictionary, String anEntityName,
+ EOEditingContext aContext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
}
-
/**
- * @see net.wotonomy.control.EOObjectStore#initializeObject(Object, EOGlobalID, EOEditingContext)
+ * @see net.wotonomy.control.EOObjectStore#initializeObject(Object, EOGlobalID,
+ * EOEditingContext)
*/
- public void initializeObject(
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
+ public void initializeObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
}
-
/**
* @see net.wotonomy.control.EOObjectStore#invalidateObjectsWithGlobalIDs(List)
*/
public void invalidateObjectsWithGlobalIDs(List aList) {
- throw new UnsupportedOperationException("Not Yet Implemented");
+ throw new UnsupportedOperationException("Not Yet Implemented");
}
-
/**
- * @see net.wotonomy.control.EOObjectStore#refaultObject(Object, EOGlobalID, EOEditingContext)
+ * @see net.wotonomy.control.EOObjectStore#refaultObject(Object, EOGlobalID,
+ * EOEditingContext)
*/
- public void refaultObject(
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext) {
- throw new UnsupportedOperationException("Not Yet Implemented");
+ public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ throw new UnsupportedOperationException("Not Yet Implemented");
}
-
}
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java
index d42130c..a8710ef 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java
@@ -34,514 +34,423 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSMutableArray;
/**
-* EOObserverCenter is a static singleton-like class
-* that manages EOObservings that want to be notified
-* of changes to those objects that call
-* notifyObserversObjectWillChange() before their
-* properties change. <br><br>
-*
-* Implementation note: Because Java implements the
-* Observer pattern in java.util.Observable, this
-* class knows how to register itself as an Observer
-* with Observables as well. However, users should
-* note that Observables only notify their Observers
-* of changes after their property has changed.
-* EODelayedObservers would see no difference because
-* they always receive their notification after all
-* changes have taken place. <br><br>
-*
-* This implementation uses weak references for observers
-* and observables. The advantage to this approach is
-* that you do not need to explicitly unregister observers
-* or observables; they will be unregistered when they are
-* garbage-collected. Note that you will need to retain
-* a reference to any objects you register or they may
-* become unregistered if no other object references them.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOObserverCenter implements Observer
-{
- /**
- * Would much rather use a WeakHashMap, but that class
- * compares by value, and we need to compare by reference.
- * This means we need to recreate a weak hashmap with
- * the ReferenceKey class below. Using hashtable for
- * thread safety.
- */
+ * EOObserverCenter is a static singleton-like class that manages EOObservings
+ * that want to be notified of changes to those objects that call
+ * notifyObserversObjectWillChange() before their properties change. <br>
+ * <br>
+ *
+ * Implementation note: Because Java implements the Observer pattern in
+ * java.util.Observable, this class knows how to register itself as an Observer
+ * with Observables as well. However, users should note that Observables only
+ * notify their Observers of changes after their property has changed.
+ * EODelayedObservers would see no difference because they always receive their
+ * notification after all changes have taken place. <br>
+ * <br>
+ *
+ * This implementation uses weak references for observers and observables. The
+ * advantage to this approach is that you do not need to explicitly unregister
+ * observers or observables; they will be unregistered when they are
+ * garbage-collected. Note that you will need to retain a reference to any
+ * objects you register or they may become unregistered if no other object
+ * references them.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOObserverCenter implements Observer {
+ /**
+ * Would much rather use a WeakHashMap, but that class compares by value, and we
+ * need to compare by reference. This means we need to recreate a weak hashmap
+ * with the ReferenceKey class below. Using hashtable for thread safety.
+ */
private static Map observableToObservers = new Hashtable();
-
+
private static List omniscients = new LinkedList();
-
+
// suppression count
private static int suppressions = 0;
-
+
// singleton instance - needed for Observer
private static EOObserverCenter instance = null;
-
- // optimization: remember last request and result
- private static Object lastRequest;
- private static NSArray lastResult;
-
+
+ // optimization: remember last request and result
+ private static Object lastRequest;
+ private static NSArray lastResult;
+
/**
- * Registers the specified EOObserving for
- * notifications from the specified object.
- * An EOObserving can only be registered
- * once for a given object.
- */
- public static void addObserver(
- EOObserving anObserver, Object anObject )
- {
+ * Registers the specified EOObserving for notifications from the specified
+ * object. An EOObserving can only be registered once for a given object.
+ */
+ public static void addObserver(EOObserving anObserver, Object anObject) {
// atomic operation
- synchronized ( instance() )
- {
+ synchronized (instance()) {
// find observer list
- List observers = (List)
- observableToObservers.get( new ReferenceKey( anObject ) );
-
+ List observers = (List) observableToObservers.get(new ReferenceKey(anObject));
+
// if observer list not found, create and add item
- if ( observers == null )
- {
+ if (observers == null) {
observers = new ArrayList();
- observers.add( new WeakReference( anObserver ) );
- processQueue();
- observableToObservers.put( new ReferenceKey( anObject, queue ), observers );
+ observers.add(new WeakReference(anObserver));
+ processQueue();
+ observableToObservers.put(new ReferenceKey(anObject, queue), observers);
// support for java.util.Observable
- if ( anObject instanceof Observable )
- {
- ((Observable)anObject).addObserver( instance() );
+ if (anObject instanceof Observable) {
+ ((Observable) anObject).addObserver(instance());
}
- }
- else // observer list found - scan for observer
- if ( indexOf( observers, anObserver ) < 0 )
- {
+ } else // observer list found - scan for observer
+ if (indexOf(observers, anObserver) < 0) {
// observer not found, register it
- observers.add( new WeakReference( anObserver ) );
+ observers.add(new WeakReference(anObserver));
}
-
- lastRequest = null;
- lastResult = null;
+
+ lastRequest = null;
+ lastResult = null;
}
}
/**
- * Registers the specified EOObserving for notifications
- * on all object changes. An EOObserving can be
- * registered as an omniscient observer at most once.
- * Use omniscient observers with caution.
- */
- public static void addOmniscientObserver(
- EOObserving anObserver )
- {
- if ( indexOf( omniscients, anObserver ) < 0 )
- {
- omniscients.add( anObserver );
+ * Registers the specified EOObserving for notifications on all object changes.
+ * An EOObserving can be registered as an omniscient observer at most once. Use
+ * omniscient observers with caution.
+ */
+ public static void addOmniscientObserver(EOObserving anObserver) {
+ if (indexOf(omniscients, anObserver) < 0) {
+ omniscients.add(anObserver);
}
}
/**
- * Notifies all EOObservings registered for
- * notifications for the specified object.
- * This method is typically called by objects
- * that wish to broadcast a notification before
- * a property change takes place, passing itself
- * as the argument.
- */
- public static void notifyObserversObjectWillChange(
- Object anObject )
- {
- if ( observerNotificationSuppressCount() == 0 )
- {
- List observers = observersForObject( anObject );
+ * Notifies all EOObservings registered for notifications for the specified
+ * object. This method is typically called by objects that wish to broadcast a
+ * notification before a property change takes place, passing itself as the
+ * argument.
+ */
+ public static void notifyObserversObjectWillChange(Object anObject) {
+ if (observerNotificationSuppressCount() == 0) {
+ List observers = observersForObject(anObject);
EOObserving o;
Iterator it = observers.iterator();
- while ( it.hasNext() )
- {
+ while (it.hasNext()) {
o = (EOObserving) it.next();
- o.objectWillChange( anObject );
+ o.objectWillChange(anObject);
}
}
}
/**
- * Returns an observer that is an instance of
- * the specified class and
- * that is registered for notifications about
- * the specified object. If more than one
- * such observer exists, which observer is
- * returned is undetermined - use
- * observersForObject instead. If no observer
- * exists, returns null.
- */
- public static EOObserving observerForObject(
- Object anObject, Class aClass )
- {
- List result = observersForObject( anObject );
- if ( result.size() == 0 ) return null;
-
+ * Returns an observer that is an instance of the specified class and that is
+ * registered for notifications about the specified object. If more than one
+ * such observer exists, which observer is returned is undetermined - use
+ * observersForObject instead. If no observer exists, returns null.
+ */
+ public static EOObserving observerForObject(Object anObject, Class aClass) {
+ List result = observersForObject(anObject);
+ if (result.size() == 0)
+ return null;
+
Object o;
Iterator it = result.iterator();
- while ( it.hasNext() )
- {
+ while (it.hasNext()) {
o = it.next();
- if ( aClass.isAssignableFrom( o.getClass() ) )
- {
- return (EOObserving) o;
+ if (aClass.isAssignableFrom(o.getClass())) {
+ return (EOObserving) o;
}
}
return null;
}
/**
- * Returns the number of times that notifications
- * have been suppressed. This is also the number
- * of times that enableObserverNotification must
- * be called to allow notifications to take place.
- */
- public static int observerNotificationSuppressCount()
- {
+ * Returns the number of times that notifications have been suppressed. This is
+ * also the number of times that enableObserverNotification must be called to
+ * allow notifications to take place.
+ */
+ public static int observerNotificationSuppressCount() {
return suppressions;
}
/**
- * Returns a List of observers for the
- * specified object. Returns an empty List
- * if no observer has registered for that
- * object.
- */
- public static NSArray observersForObject(
- Object anObject )
- {
- synchronized ( instance() )
- {
- // optimization: this is called very frequently
- // from the same object calling willChange() a
- // number of times in a row as it is updating.
- if ( lastRequest == anObject )
- {
- return lastResult;
- }
-
- NSArray result;
-
- List references = observerListForObject( anObject );
- if ( references == null )
- {
- result = NSArray.EmptyArray;
- }
- else
- {
- result = new NSMutableArray();
- Object observer;
- Iterator it = references.iterator();
- while ( it.hasNext() )
- {
- observer = ((Reference)it.next()).get();
- if ( observer != null )
- {
- result.add( observer );
- }
- else // reference has expired
- {
- processQueue();
- it.remove(); // remove from list
- // if last observer, unregister observable
- if ( references.size() == 0 )
- {
- observableToObservers.remove( new ReferenceKey( anObject ) );
- }
- }
- }
- }
-
- lastRequest = anObject;
- lastResult = result;
-
- return result;
- }
-
+ * Returns a List of observers for the specified object. Returns an empty List
+ * if no observer has registered for that object.
+ */
+ public static NSArray observersForObject(Object anObject) {
+ synchronized (instance()) {
+ // optimization: this is called very frequently
+ // from the same object calling willChange() a
+ // number of times in a row as it is updating.
+ if (lastRequest == anObject) {
+ return lastResult;
+ }
+
+ NSArray result;
+
+ List references = observerListForObject(anObject);
+ if (references == null) {
+ result = NSArray.EmptyArray;
+ } else {
+ result = new NSMutableArray();
+ Object observer;
+ Iterator it = references.iterator();
+ while (it.hasNext()) {
+ observer = ((Reference) it.next()).get();
+ if (observer != null) {
+ result.add(observer);
+ } else // reference has expired
+ {
+ processQueue();
+ it.remove(); // remove from list
+ // if last observer, unregister observable
+ if (references.size() == 0) {
+ observableToObservers.remove(new ReferenceKey(anObject));
+ }
+ }
+ }
+ }
+
+ lastRequest = anObject;
+ lastResult = result;
+
+ return result;
+ }
+
}
-
+
/**
- * Returns a reference to the actual list of
- * observers for the given object, or null if it
- * doesn't exist.
- */
- private static List observerListForObject( Object anObject )
- {
- return (List) observableToObservers.get( new ReferenceKey( anObject ) );
+ * Returns a reference to the actual list of observers for the given object, or
+ * null if it doesn't exist.
+ */
+ private static List observerListForObject(Object anObject) {
+ return (List) observableToObservers.get(new ReferenceKey(anObject));
}
/**
- * Unregisters the specified observer for
- * notifications from the specified object.
- */
- public static void removeObserver(
- EOObserving anObserver, Object anObject )
- {
+ * Unregisters the specified observer for notifications from the specified
+ * object.
+ */
+ public static void removeObserver(EOObserving anObserver, Object anObject) {
// atomic operation
- synchronized ( instance() )
- {
- lastRequest = null;
- lastResult = null;
-
- List result = observerListForObject( anObject );
- if ( result == null ) return;
- int index = indexOf( result, anObserver );
- if ( index == -1 ) return;
-
+ synchronized (instance()) {
+ lastRequest = null;
+ lastResult = null;
+
+ List result = observerListForObject(anObject);
+ if (result == null)
+ return;
+ int index = indexOf(result, anObserver);
+ if (index == -1)
+ return;
+
// remove observer from list
- result.remove( index );
-
+ result.remove(index);
+
// if last observer, unregister observable
- if ( result.size() == 0 )
- {
- processQueue();
- observableToObservers.remove( new ReferenceKey( anObject ) );
+ if (result.size() == 0) {
+ processQueue();
+ observableToObservers.remove(new ReferenceKey(anObject));
}
}
}
/**
- * Unregisters the specified omniscient observer.
- */
- public static void removeOmniscientObserver(
- EOObserving anObserver )
- {
- int index = indexOf( omniscients, anObserver );
- if ( index != -1 )
- {
- omniscients.remove( index );
+ * Unregisters the specified omniscient observer.
+ */
+ public static void removeOmniscientObserver(EOObserving anObserver) {
+ int index = indexOf(omniscients, anObserver);
+ if (index != -1) {
+ omniscients.remove(index);
}
}
/**
- * Enables notifications after they have been
- * suppressed by suppressObserverNotification.
- * If notifications have been suppressed
- * multiple times, this method must be called
- * an equal number of times to resume notifications.
- * If notifications are not currently suppressed,
- * this method does nothing.
- */
- public static void enableObserverNotification()
- {
- if ( suppressions > 0 ) suppressions--;
+ * Enables notifications after they have been suppressed by
+ * suppressObserverNotification. If notifications have been suppressed multiple
+ * times, this method must be called an equal number of times to resume
+ * notifications. If notifications are not currently suppressed, this method
+ * does nothing.
+ */
+ public static void enableObserverNotification() {
+ if (suppressions > 0)
+ suppressions--;
}
/**
- * Causes notifications to be suppressed until
- * the next matching call to enableObserverNotification.
- * If this method is called more than once,
- * enableObserverNotification must be called an
- * equal number of times for notifications to resume.
- * This method always causes notifications to cease
- * immediately.
- */
- public static void suppressObserverNotification()
- {
+ * Causes notifications to be suppressed until the next matching call to
+ * enableObserverNotification. If this method is called more than once,
+ * enableObserverNotification must be called an equal number of times for
+ * notifications to resume. This method always causes notifications to cease
+ * immediately.
+ */
+ public static void suppressObserverNotification() {
suppressions++;
}
-
+
/**
- * Because we're comparing by reference, we need to
- * test for the existence of the object directly.
- * @return the index or -1 if not found.
- */
- private static int indexOf( List aList, Object anObject )
- {
- if ( anObject == null ) return -1;
-
- synchronized ( aList )
- {
+ * Because we're comparing by reference, we need to test for the existence of
+ * the object directly.
+ *
+ * @return the index or -1 if not found.
+ */
+ private static int indexOf(List aList, Object anObject) {
+ if (anObject == null)
+ return -1;
+
+ synchronized (aList) {
int len = aList.size();
- for ( int i = 0; i < len; i++ )
- {
+ for (int i = 0; i < len; i++) {
// compare by reference
- if ( anObject == ((Reference)aList.get(i)).get() )
- {
+ if (anObject == ((Reference) aList.get(i)).get()) {
return i;
}
}
}
return -1;
}
-
+
/**
- * Private singleton instance, so we can be an observer.
- */
- private static EOObserverCenter instance()
- {
- if ( instance == null )
- {
+ * Private singleton instance, so we can be an observer.
+ */
+ private static EOObserverCenter instance() {
+ if (instance == null) {
instance = new EOObserverCenter();
}
return instance;
}
-
+
+ /**
+ * Interface Observer
+ */
+ public void update(Observable o, Object arg) {
+ notifyObserversObjectWillChange(o);
+ }
+
+ /* Reference queue for cleared WeakKeys */
+ private static ReferenceQueue queue = new ReferenceQueue();
+
+ /*
+ * Remove all invalidated entries from the map, that is, remove all entries
+ * whose keys have been discarded. This method should be invoked once by each
+ * public mutator in this class. We don't invoke this method in public accessors
+ * because that can lead to surprising ConcurrentModificationExceptions.
+ */
+ private static void processQueue() {
+ synchronized (instance()) {
+ ReferenceKey rk;
+ while ((rk = (ReferenceKey) queue.poll()) != null) {
+ // System.out.println( "EOObserverCenter.processQueue: removing object" );
+ observableToObservers.remove(rk);
+ }
+ }
+ }
+
/**
- * Interface Observer
- */
- public void update( Observable o, Object arg )
- {
- notifyObserversObjectWillChange( o );
+ * Private class used to force a hashmap to perform key comparisons by
+ * reference. Retains a weak reference just like WeakHashMap.
+ */
+ static private class ReferenceKey extends WeakReference {
+ private int hashCode;
+
+ /**
+ * Called to create a disposable reference key, used for retrieving values from
+ * the hashtable.
+ */
+ public ReferenceKey(Object anObject) {
+ super(anObject);
+ hashCode = anObject.hashCode();
+ }
+
+ /**
+ * Called to create a reference key that will be used as a key in the hashtable,
+ * so we need the reference queue to later remove the key from the table when
+ * referred object is no longer in use.
+ */
+ public ReferenceKey(Object anObject, ReferenceQueue aQueue) {
+ super(anObject, aQueue);
+ hashCode = anObject.hashCode();
+ }
+
+ /**
+ * Passes through to actual key's hash code.
+ */
+ public int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Compares by reference.
+ */
+ public boolean equals(Object anObject) {
+ if (!(anObject instanceof ReferenceKey))
+ return false;
+ Object key = get();
+ if (key == null)
+ return false;
+ return (key == ((ReferenceKey) anObject).get());
+ }
}
-
- /* Reference queue for cleared WeakKeys */
- private static ReferenceQueue queue = new ReferenceQueue();
-
- /* Remove all invalidated entries from the map, that is, remove all entries
- whose keys have been discarded. This method should be invoked once by
- each public mutator in this class. We don't invoke this method in
- public accessors because that can lead to surprising
- ConcurrentModificationExceptions. */
- private static void processQueue()
- {
- synchronized ( instance() )
- {
- ReferenceKey rk;
- while ((rk = (ReferenceKey)queue.poll()) != null)
- {
- //System.out.println( "EOObserverCenter.processQueue: removing object" );
- observableToObservers.remove(rk);
- }
- }
- }
-
- /**
- * Private class used to force a hashmap to
- * perform key comparisons by reference.
- * Retains a weak reference just like WeakHashMap.
- */
- static private class ReferenceKey extends WeakReference
- {
- private int hashCode;
-
- /**
- * Called to create a disposable reference key,
- * used for retrieving values from the hashtable.
- */
- public ReferenceKey( Object anObject )
- {
- super( anObject );
- hashCode = anObject.hashCode();
- }
-
- /**
- * Called to create a reference key that will be
- * used as a key in the hashtable, so we need the
- * reference queue to later remove the key from the
- * table when referred object is no longer in use.
- */
- public ReferenceKey( Object anObject, ReferenceQueue aQueue )
- {
- super( anObject, aQueue );
- hashCode = anObject.hashCode();
- }
-
- /**
- * Passes through to actual key's hash code.
- */
- public int hashCode()
- {
- return hashCode;
- }
-
- /**
- * Compares by reference.
- */
- public boolean equals( Object anObject )
- {
- if ( ! ( anObject instanceof ReferenceKey ) ) return false;
- Object key = get();
- if ( key == null ) return false;
- return ( key == ((ReferenceKey)anObject).get() );
- }
- }
-
- private static String debugString()
- {
- String result = "";
- int count = 0;
- synchronized ( instance() )
- {
- Object anObject;
- Iterator it = observableToObservers.keySet().iterator();
- while ( it.hasNext() )
- {
- result += ((Reference)it.next()).get() + " : ";
- count++;
- /*
- Iterator values = ((List)it.next()).iterator();
- while ( values.hasNext() )
- {
- anObject = ((Reference)values.next()).get();
- if ( anObject != null )
- {
-// if ( anObject instanceof net.wotonomy.ui.MasterDetailAssociation )
- result += anObject.getClass().toString() + " : ";
- count++;
- }
- }
- */
- }
- result += "["+count+"]";
+
+ private static String debugString() {
+ String result = "";
+ int count = 0;
+ synchronized (instance()) {
+ Object anObject;
+ Iterator it = observableToObservers.keySet().iterator();
+ while (it.hasNext()) {
+ result += ((Reference) it.next()).get() + " : ";
+ count++;
+ /*
+ * Iterator values = ((List)it.next()).iterator(); while ( values.hasNext() ) {
+ * anObject = ((Reference)values.next()).get(); if ( anObject != null ) { // if
+ * ( anObject instanceof net.wotonomy.ui.MasterDetailAssociation ) result +=
+ * anObject.getClass().toString() + " : "; count++; } }
+ */
+ }
+ result += "[" + count + "]";
}
- return result;
- }
-
+ return result;
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2002/10/24 18:18:12 mpowers
- * NSArray's are now considered read-only, so we can return our internal
- * representation to reduce unnecessary object allocation.
+ * Revision 1.9 2002/10/24 18:18:12 mpowers NSArray's are now considered
+ * read-only, so we can return our internal representation to reduce unnecessary
+ * object allocation.
*
- * Revision 1.8 2001/02/21 21:17:32 mpowers
- * Now retaining a reference to the recent changes observer.
- * Better documented need to retain reference.
- * Started implementing notifications.
+ * Revision 1.8 2001/02/21 21:17:32 mpowers Now retaining a reference to the
+ * recent changes observer. Better documented need to retain reference. Started
+ * implementing notifications.
*
- * Revision 1.7 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.7 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.6 2001/02/05 18:45:45 mpowers
- * Reduced access back to private for utility methods.
+ * Revision 1.6 2001/02/05 18:45:45 mpowers Reduced access back to private for
+ * utility methods.
*
- * Revision 1.5 2001/02/05 18:42:32 mpowers
- * Updated documentation throughout project.
+ * Revision 1.5 2001/02/05 18:42:32 mpowers Updated documentation throughout
+ * project.
*
- * Revision 1.4 2001/01/18 16:57:47 mpowers
- * Added debug facility.
+ * Revision 1.4 2001/01/18 16:57:47 mpowers Added debug facility.
*
- * Revision 1.3 2001/01/10 16:28:53 mpowers
- * Implemented a compare-by-reference weak hashtable
- * because WeakHashMap compared by value and we can't
- * assume that display groups won't contain objects
- * whose values are equivalent.
+ * Revision 1.3 2001/01/10 16:28:53 mpowers Implemented a compare-by-reference
+ * weak hashtable because WeakHashMap compared by value and we can't assume that
+ * display groups won't contain objects whose values are equivalent.
*
- * Revision 1.2 2001/01/09 20:10:19 mpowers
- * Now using weak references to track observables and their observers.
+ * Revision 1.2 2001/01/09 20:10:19 mpowers Now using weak references to track
+ * observables and their observers.
*
- * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers Contributing wotonomy.
*
- * Revision 1.8 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.8 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverProxy.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverProxy.java
index e616a33..ce8c9a7 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverProxy.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverProxy.java
@@ -21,84 +21,67 @@ package net.wotonomy.control;
import net.wotonomy.foundation.NSSelector;
/**
-* A convenience observer for objects that do not or cannot
-* subclass EODelayedObserver. EOObserverProxy will invoke
-* an NSSelector on an object when it receives a subjectChanged
-* message.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class EOObserverProxy
- extends EODelayedObserver
-{
- protected Object target;
- protected NSSelector selector;
- protected int priority;
-
- /**
- * Constructs an EODelayedObserver that will invoke the specified selector
- * on the specified object, and will run at the specified priority.
- */
- public EOObserverProxy (
- Object anObject, NSSelector aSelector, int aPriority )
- {
- target = anObject;
- selector = aSelector;
- priority = aPriority;
- }
+ * A convenience observer for objects that do not or cannot subclass
+ * EODelayedObserver. EOObserverProxy will invoke an NSSelector on an object
+ * when it receives a subjectChanged message.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class EOObserverProxy extends EODelayedObserver {
+ protected Object target;
+ protected NSSelector selector;
+ protected int priority;
- /**
- * Constructs an EODelayedObserver that will invoke the specified selector
- * on the specified object, and will run at ObserverPriorityThird priority,
- * which is the default.
- */
- public EOObserverProxy (
- Object anObject, NSSelector aSelector )
- {
- this( anObject, aSelector, ObserverPriorityThird );
- }
+ /**
+ * Constructs an EODelayedObserver that will invoke the specified selector on
+ * the specified object, and will run at the specified priority.
+ */
+ public EOObserverProxy(Object anObject, NSSelector aSelector, int aPriority) {
+ target = anObject;
+ selector = aSelector;
+ priority = aPriority;
+ }
- /**
- * Returns the priority of this observer in the queue.
- * This implementation returns the priority specified
- * in the constructor.
- */
- public int priority ()
- {
- return priority;
- }
+ /**
+ * Constructs an EODelayedObserver that will invoke the specified selector on
+ * the specified object, and will run at ObserverPriorityThird priority, which
+ * is the default.
+ */
+ public EOObserverProxy(Object anObject, NSSelector aSelector) {
+ this(anObject, aSelector, ObserverPriorityThird);
+ }
+
+ /**
+ * Returns the priority of this observer in the queue. This implementation
+ * returns the priority specified in the constructor.
+ */
+ public int priority() {
+ return priority;
+ }
+
+ /**
+ * Notifies observer that one or more objects that it is observing have changed.
+ * The observer should check all objects it is observing for changes.
+ */
+ public void subjectChanged() {
+ try {
+ selector.invoke(target);
+ } catch (Exception exc) {
+ System.out.println("Error notifying observer: ");
+ exc.printStackTrace();
+ }
+ }
- /**
- * Notifies observer that one or more objects that
- * it is observing have changed. The observer should
- * check all objects it is observing for changes.
- */
- public void subjectChanged ()
- {
- try
- {
- selector.invoke( target );
- }
- catch ( Exception exc )
- {
- System.out.println( "Error notifying observer: " );
- exc.printStackTrace();
- }
- }
-
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/10/22 21:55:32 mpowers
- * This turns out to be a really useful class.
+ * Revision 1.1 2001/10/22 21:55:32 mpowers This turns out to be a really useful
+ * class.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserving.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserving.java
index 8ec6e5c..d6a3101 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserving.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserving.java
@@ -19,33 +19,27 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* A pure java implementation of EOObserving.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EOObserving
-{
- /**
- * Called when the specified object is about to change.
- */
- void objectWillChange ( Object anObject );
+ * A pure java implementation of EOObserving.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EOObserving {
+ /**
+ * Called when the specified object is about to change.
+ */
+ void objectWillChange(Object anObject);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOOrQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOOrQualifier.java
index 7f4b1c6..fe31abe 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOOrQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOOrQualifier.java
@@ -28,90 +28,76 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOOrQualifier contains other EOQualifiers,
-* evaluating as true if any of the contained
-* qualifiers evaluate as true.
-*
-* @author michael@mpowers.net
-* @author yjcheung@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOOrQualifier extends EOQualifier
- implements EOKeyValueArchiving, EOQualifierEvaluation
-{
- private List qualifiers;
-
- public EOOrQualifier(
- List aQualifierList )
- {
- qualifiers = new LinkedList( aQualifierList );
- }
-
- /**
- * Returns a List of qualifiers contained by this qualifier.
- */
- public NSArray qualifiers()
- {
- return new NSArray( qualifiers );
- }
-
- /**
- * Add a new qualifier to the list.
- */
- public void addQualifier(EOQualifier qualifier)
- {
- qualifiers.add(qualifier);
- }
-
- /**
- * Evaluates this qualifier for the specified object,
- * and returns whether the object is qualified.
- * selector() is invoked on the value for key() on the
- * specified object, with value() as the parameter.
- *
- * Note: this has a lazy "or" implementation. Ex. Qal1 or Qal2.
- * If Qal1 is evaluated to be true, then it returns true without
- * further evaluate Qal2.
- */
- public boolean evaluateWithObject( Object anObject )
- {
- Iterator it = qualifiers.iterator();
- while( it.hasNext() )
- {
- if ( ((EOQualifier) it.next()).evaluateWithObject(anObject) )
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns a string representation of this qualifier.
- */
- public String toString()
- {
- StringBuffer myBuf = new StringBuffer("(");
- Iterator it = qualifiers.iterator();
- while (it.hasNext())
- {
- myBuf = myBuf.append(((EOQualifier) it.next()).toString()).append(" or ");
- }
- String myStr = myBuf.toString();
- myStr = myStr.substring(0, myStr.lastIndexOf(" or ")).concat(")");
- return myStr;
- }
+ * EOOrQualifier contains other EOQualifiers, evaluating as true if any of the
+ * contained qualifiers evaluate as true.
+ *
+ * @author michael@mpowers.net
+ * @author yjcheung@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOOrQualifier extends EOQualifier implements EOKeyValueArchiving, EOQualifierEvaluation {
+ private List qualifiers;
+
+ public EOOrQualifier(List aQualifierList) {
+ qualifiers = new LinkedList(aQualifierList);
+ }
+
+ /**
+ * Returns a List of qualifiers contained by this qualifier.
+ */
+ public NSArray qualifiers() {
+ return new NSArray(qualifiers);
+ }
+
+ /**
+ * Add a new qualifier to the list.
+ */
+ public void addQualifier(EOQualifier qualifier) {
+ qualifiers.add(qualifier);
+ }
+
+ /**
+ * Evaluates this qualifier for the specified object, and returns whether the
+ * object is qualified. selector() is invoked on the value for key() on the
+ * specified object, with value() as the parameter.
+ *
+ * Note: this has a lazy "or" implementation. Ex. Qal1 or Qal2. If Qal1 is
+ * evaluated to be true, then it returns true without further evaluate Qal2.
+ */
+ public boolean evaluateWithObject(Object anObject) {
+ Iterator it = qualifiers.iterator();
+ while (it.hasNext()) {
+ if (((EOQualifier) it.next()).evaluateWithObject(anObject)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation of this qualifier.
+ */
+ public String toString() {
+ StringBuffer myBuf = new StringBuffer("(");
+ Iterator it = qualifiers.iterator();
+ while (it.hasNext()) {
+ myBuf = myBuf.append(((EOQualifier) it.next()).toString()).append(" or ");
+ }
+ String myStr = myBuf.toString();
+ myStr = myStr.substring(0, myStr.lastIndexOf(" or ")).concat(")");
+ return myStr;
+ }
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
- NSArray a = (NSArray)arch.decodeObjectForKey("qualifiers");
+ NSArray a = (NSArray) arch.decodeObjectForKey("qualifiers");
if (a == null)
return null;
NSMutableArray l = new NSMutableArray();
for (int i = 0; i < a.count(); i++) {
- NSDictionary d = (NSDictionary)a.objectAtIndex(i);
+ NSDictionary d = (NSDictionary) a.objectAtIndex(i);
EOKeyValueUnarchiver ua = new EOKeyValueUnarchiver(d);
- EOQualifier q = (EOQualifier)EOQualifier.decodeWithKeyValueUnarchiver(ua);
+ EOQualifier q = (EOQualifier) EOQualifier.decodeWithKeyValueUnarchiver(ua);
if (q != null)
l.addObject(q);
}
@@ -121,11 +107,11 @@ public class EOOrQualifier extends EOQualifier
public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
arch.encodeObject("EOOrQualifier", "class");
NSMutableArray arr = new NSMutableArray(qualifiers.size());
- for (int i = 0; i < qualifiers.size(); i++) {
- EOQualifier q = (EOQualifier)qualifiers.get(i);
+ for (int i = 0; i < qualifiers.size(); i++) {
+ EOQualifier q = (EOQualifier) qualifiers.get(i);
if (q instanceof EOKeyValueArchiving) {
EOKeyValueArchiver ar2 = new EOKeyValueArchiver();
- ((EOKeyValueArchiving)q).encodeWithKeyValueArchiver(ar2);
+ ((EOKeyValueArchiving) q).encodeWithKeyValueArchiver(ar2);
arr.addObject(ar2.dictionary());
} else
throw new WotonomyException("Cannot archive instance of " + q.getClass().getName());
@@ -136,34 +122,31 @@ public class EOOrQualifier extends EOQualifier
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/12 01:43:04 chochos
- * formally implement EOQualifierEvaluation
+ * Revision 1.6 2003/08/12 01:43:04 chochos formally implement
+ * EOQualifierEvaluation
*
- * Revision 1.5 2003/08/09 01:22:51 chochos
- * qualifiers implement EOKeyValueArchiving
+ * Revision 1.5 2003/08/09 01:22:51 chochos qualifiers implement
+ * EOKeyValueArchiving
*
- * Revision 1.4 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.4 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.3 2001/10/31 15:25:14 mpowers
- * Cleanup of qualifiers.
+ * Revision 1.3 2001/10/31 15:25:14 mpowers Cleanup of qualifiers.
*
- * Revision 1.2 2001/10/30 22:57:28 mpowers
- * EOQualifier framework is now working.
+ * Revision 1.2 2001/10/30 22:57:28 mpowers EOQualifier framework is now
+ * working.
*
- * Revision 1.1 2001/09/13 15:25:56 mpowers
- * Started implementation of the EOQualifier framework.
+ * Revision 1.1 2001/09/13 15:25:56 mpowers Started implementation of the
+ * EOQualifier framework.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java
index 6fffea4..32443fa 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java
@@ -38,643 +38,504 @@ import net.wotonomy.foundation.internal.ValueConverter;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EOQualifiers are used to perform property-based
-* qualifications on objects: for a set of criteria,
-* a qualifier either qualifies or disqualifies an
-* given object. EOKeyValueQualifiers can be joined
-* by EOAndQualifier and EOOrQualifier, and so can
-* form a tree of qualifications. <br><br>
-*
-* Certain qualifiers
-* can accept a variable in place of a value; variable
-* names are marked by a "$", as in "$name". Variables
-* are resolved with the qualifierWithBindings() method.
-*
-* @author michael@mpowers.net
-* @author yjcheung@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public abstract class EOQualifier
-{
- public static final NSSelector
- QualifierOperatorCaseInsensitiveLike = new OperatorCaseInsensitiveLike();
- public static final NSSelector
- QualifierOperatorContains = new OperatorContains();
- public static final NSSelector
- QualifierOperatorEqual = new OperatorEqual();
- public static final NSSelector
- QualifierOperatorGreaterThan = new OperatorGreaterThan();
- public static final NSSelector
- QualifierOperatorGreaterThanOrEqualTo = new OperatorGreaterThanOrEqualTo();
- public static final NSSelector
- QualifierOperatorLessThan = new OperatorLessThan();
- public static final NSSelector
- QualifierOperatorLessThanOrEqualTo = new OperatorLessThanOrEqualTo();
- public static final NSSelector
- QualifierOperatorLike = new OperatorLike();
- public static final NSSelector
- QualifierOperatorNotEqual = new OperatorNotEqual();
-
- /**
- * Default constructor.
- */
- public EOQualifier ()
- {
- }
-
- /**
- * Adds all qualifier keys in this qualifier to
- * the specified Set, which is expected to be
- * mutable. The tree of qualifiers is traversed
- * and the left-hand-side of each expression is
- * added to the set.
- */
- public void addQualifierKeysToSet ( Set aSet )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Set of all property names used for
- * comparisons by this qualifier. The tree of
- * qualifiers is traversed and the left-hand-side
- * of each expression is added to the set.
- */
- public NSSet allQualifierKeys ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a List containing the variables used
- * at compare-time by this qualifier. Each variable
- * will appear only once in the list.
- */
- public NSArray bindingKeys ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether the specified object meets the
- * criteria defined by this qualifier.
- */
- public boolean evaluateWithObject ( Object anObject )
- {
- return true;
- }
-
- /**
- * Returns the key (which can be a key path) that
- * is tested against the specified binding variable.
- * The tree is traversed looking for the first instance
- * of the specified variable, and the corresponding
- * left-hand-side of the expression is returned.
- */
- public String keyPathForBindingKey ( String aVariable )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a qualifier that is like this qualifier,
- * except all variables will be replaced with values
- * from the specified Map whose keys match the variable
- * names. If requireAll is true, an exception will be
- * thrown if there is no key that matches on of the
- * variables in the tree; otherwise, the qualifier
- * containing the unmatched variable is removed.
- */
- public EOQualifier qualifierWithBindings (
- Map aMap,
- boolean requireAll )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
-
- /**
- * Tests whether all the keys in this qualifier can
- * be applied to an object of the specified class.
- * @return A Throwable if the validation fails,
- * otherwise returns null if the class can be used
- * with this qualifier.
- */
- public Throwable validateKeysWithRootClassDescription (
- Class aClass )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
-
- // statics
-
- /**
- * Convenience to retain only those objects from the specified
- * List that meet the specified qualifier's requirements.
- */
- public static void filterArrayWithQualifier (
- List anObjectList, EOQualifier aQualifier )
- {
- ListIterator iterator = anObjectList.listIterator();
- while ( iterator.hasNext() )
- {
- if ( ! aQualifier.evaluateWithObject( iterator.next() ) )
- {
- iterator.remove();
- }
- }
- }
-
- /**
- * Convenience to return a List consisting only
- * of those objects in the specified List that meet
- * the specified qualifier's requirements.
- */
- public static NSArray filteredArrayWithQualifier (
- List anObjectList, EOQualifier aQualifier )
- {
- Object o;
- List result = new LinkedList();
- Iterator iterator = anObjectList.iterator();
- while ( iterator.hasNext() )
- {
- o = iterator.next();
- if ( aQualifier.evaluateWithObject( o ) )
- {
- result.add( o );
- }
- }
- return new NSArray( (Collection) result );
- }
-
- /**
- * Convenience to create a set of EOKeyValueQualifiers
- * joined by an EOAndQualifier. Each pair of keys and
- * values are used to create EOKeyValueQualifiers.
- */
- public static EOQualifier
- qualifierToMatchAllValues ( Map aMap )
- {
- Object key, value;
- List qualifierList = new LinkedList();
- Iterator iterator = aMap.keySet().iterator();
- while ( iterator.hasNext() )
- {
- key = iterator.next();
- value = aMap.get( key );
- qualifierList.add( new EOKeyValueQualifier(
- key.toString(), QualifierOperatorEqual, value ) );
- }
- return new EOAndQualifier( qualifierList );
- }
-
- /**
- * Convenience to create a set of EOKeyValueQualifiers
- * joined by an EOOrQualifier. Each pair of keys and
- * values are used to create EOKeyValueQualifiers.
- */
- public static EOQualifier
- qualifierToMatchAnyValue ( Map aMap )
- {
- Object key, value;
- List qualifierList = new LinkedList();
- Iterator iterator = aMap.keySet().iterator();
- while ( iterator.hasNext() )
- {
- key = iterator.next();
- value = aMap.get( key );
- qualifierList.add( new EOKeyValueQualifier(
- key.toString(), QualifierOperatorEqual, value ) );
- }
- return new EOOrQualifier( qualifierList );
- }
-
- /**
- * Returns an EOQualifier that meets the criteria
- * represented by the specified string and variable
- * length argument list. This method parses the string
- * and returns a tree of qualifiers. Each token beginning
- * with "%" is replaced with the corresponding object
- * from the argument list. The parser recognizes the
- * operation tokens returned from the allQualifierOperators()
- * method.
- */
- public static EOQualifier qualifierWithQualifierFormat (
- String aString, List anArgumentList )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a List of operators that are supported for
- * relational operations. This excludes string comparison
- * operators.
- */
- public static NSArray relationalQualifierOperators ()
- {
- NSMutableArray result = new NSMutableArray();
- BaseSelector selector;
- Iterator iterator = allQualifierOperators().iterator();
- while ( iterator.hasNext() )
- {
- selector = (BaseSelector) iterator.next();
- if ( selector.isRelationalOperator() )
- {
- result.addObject( selector );
- }
- }
- return result;
- }
-
- /**
- * Returns a List of valid operators.
- */
- public static NSArray allQualifierOperators ()
- {
- return operators.allKeys();
- }
-
- /**
- * Returns a selector the corresponds to the operation
- * represented by the specified string. For example,
- * ">" represents QualifierOperatorGreaterThan.
- */
- public static NSSelector operatorSelectorForString (
- String anOperatorString )
- {
- return (NSSelector)
- operators.objectForKey( anOperatorString );
- }
-
- /**
- * Returns a string the corresponds to the operation
- * represented by the specified selector. For example,
- * QualifierOperatorGreaterThan is represented with ">".
- */
- public static String stringForOperatorSelector (
- NSSelector aSelector )
- {
- return (String)
- operators.allKeysForObject( aSelector ).lastObject();
- }
-
- /**
- * Returns a string representation of this qualifier.
- */
- public String toString()
- {
- //TODO: implement this
- return super.toString();
- }
-
- // built-in qualifiers
-
- private static NSMutableDictionary operators;
- static
- {
- operators = new NSMutableDictionary();
- operators.setObjectForKey(
- QualifierOperatorCaseInsensitiveLike,
- QualifierOperatorCaseInsensitiveLike.toString() );
- operators.setObjectForKey(
- QualifierOperatorContains,
- QualifierOperatorContains.toString() );
- operators.setObjectForKey(
- QualifierOperatorEqual,
- QualifierOperatorEqual.toString() );
- operators.setObjectForKey(
- QualifierOperatorGreaterThan,
- QualifierOperatorGreaterThan.toString() );
- operators.setObjectForKey(
- QualifierOperatorGreaterThanOrEqualTo,
- QualifierOperatorGreaterThanOrEqualTo.toString() );
- operators.setObjectForKey(
- QualifierOperatorLessThan,
- QualifierOperatorLessThan.toString() );
- operators.setObjectForKey(
- QualifierOperatorLessThanOrEqualTo,
- QualifierOperatorLessThanOrEqualTo.toString() );
- operators.setObjectForKey(
- QualifierOperatorLike,
- QualifierOperatorLike.toString() );
- operators.setObjectForKey(
- QualifierOperatorNotEqual,
- QualifierOperatorNotEqual.toString() );
- }
-
- static private abstract class BaseSelector extends NSSelector
- {
- public String name ()
- {
- return "BaseSelector";
- }
-
- public Class[] parameterTypes ()
- {
- return new Class[] { Object.class, Object.class };
- }
-
- public Method methodOnClass (Class aClass)
- throws NoSuchMethodException
- {
- throw new NoSuchMethodException();
- }
-
- public Method methodOnObject (Object anObject)
- throws NoSuchMethodException
- {
- throw new NoSuchMethodException();
- }
-
- public boolean implementedByClass (Class aClass)
- {
- return true;
- }
-
- public boolean implementedByObject (Object anObject)
- {
- return true;
- }
-
- public boolean isRelationalOperator()
- {
- return true;
- }
-
- public Object invoke (Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return qualify( anObject, parameters[0] );
- }
-
- abstract protected Boolean qualify( Object target, Object parameter );
-
- protected int doCompare(Object o1, Object o2)
- {
- Class firstClass = o1.getClass();
- Class secondClass = o2.getClass();
-
- if ( ! ( secondClass.equals( firstClass ) ) )
- {
- Object converted = null;
- if ( o2 instanceof Comparable )
- {
- converted = ValueConverter.convertObjectToClass( o1, secondClass );
- if (converted != null)
- {
- o1 = converted;
- }
- }
-
- if (converted == null && (o1 instanceof Comparable))
- {
- converted = ValueConverter.convertObjectToClass( o2, firstClass );
- if ( converted != null )
- {
- o2 = converted;
- }
- }
-
- if (converted == null)
- {
- throw new WotonomyException("Qualifier: Not Comparable Objects");
- // no way to compare
- }
- }
-
- return ((Comparable)o2).compareTo( o1 );
- }
-
- }
-
-
- static class OperatorCaseInsensitiveLike extends BaseSelector {
-
- public boolean isRelationalOperator()
- {
- return false;
- }
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- String myString1 = o1.toString();
- String myString2 = o2.toString();
- myString1 = myString1.toLowerCase();
- myString2 = myString2.toLowerCase();
- StringTokenizer st = new StringTokenizer(myString1, "%");
-
- while (st.hasMoreTokens()) {
- String part = st.nextToken();
- int index = myString2.indexOf(part);
- if (index > -1)
- {
- myString2 = myString2.substring(index + part.length());
- }
- else
- {
- return Boolean.FALSE;
- }
- }
- return Boolean.TRUE;
-
- }
-
- public String toString()
- {
- return "caseInsensitiveLike";
- }
- }
-
- static class OperatorContains extends BaseSelector {
-
- public boolean isRelationalOperator()
- {
- return false;
- }
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- String myString1 = o1.toString();
- String myString2 = o2.toString();
- return new Boolean(
- myString2.indexOf(myString1) > -1 );
- }
-
- public String toString()
- {
- return "contains";
- }
- }
-
- static class OperatorEqual extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean( doCompare(o1, o2) == 0 );
- }
-
- public String toString()
- {
- return "=";
- }
- }
-
- static class OperatorGreaterThan extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean( doCompare(o1, o2) > 0 );
- }
-
- public String toString()
- {
- return ">";
- }
- }
-
- static class OperatorGreaterThanOrEqualTo extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean( doCompare(o1, o2) >= 0 );
- }
-
- public String toString()
- {
- return new String(" >= ");
- }
- }
-
- static class OperatorLessThan extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean( doCompare(o1, o2) < 0 );
- }
-
- public String toString()
- {
- return ">";
- }
- }
-
- static class OperatorLessThanOrEqualTo extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean (doCompare(o1, o2) <= 0);
- }
-
- public String toString()
- {
- return "<=";
- }
- }
-
- static class OperatorLike extends BaseSelector {
-
- public boolean isRelationalOperator()
- {
- return false;
- }
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- String myString1 = o1.toString();
- String myString2 = o2.toString();
- StringTokenizer st = new StringTokenizer(myString1, "%");
- while (st.hasMoreTokens()) {
- String part = st.nextToken();
- int index = myString2.indexOf(part);
- if (index > -1)
- {
- myString2 = myString2.substring(index + part.length());
- }
- else
- {
- return Boolean.FALSE;
- }
- }
- return Boolean.TRUE;
- }
-
- public String toString()
- {
- return "like";
- }
- }
-
- static class OperatorNotEqual extends BaseSelector {
-
- protected Boolean qualify( Object o1, Object o2 )
- {
- return new Boolean(!(o1.equals(o2)));
- }
-
- public String toString()
- {
- return "!=";
- }
- }
-
+ * EOQualifiers are used to perform property-based qualifications on objects:
+ * for a set of criteria, a qualifier either qualifies or disqualifies an given
+ * object. EOKeyValueQualifiers can be joined by EOAndQualifier and
+ * EOOrQualifier, and so can form a tree of qualifications. <br>
+ * <br>
+ *
+ * Certain qualifiers can accept a variable in place of a value; variable names
+ * are marked by a "$", as in "$name". Variables are resolved with the
+ * qualifierWithBindings() method.
+ *
+ * @author michael@mpowers.net
+ * @author yjcheung@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public abstract class EOQualifier {
+ public static final NSSelector QualifierOperatorCaseInsensitiveLike = new OperatorCaseInsensitiveLike();
+ public static final NSSelector QualifierOperatorContains = new OperatorContains();
+ public static final NSSelector QualifierOperatorEqual = new OperatorEqual();
+ public static final NSSelector QualifierOperatorGreaterThan = new OperatorGreaterThan();
+ public static final NSSelector QualifierOperatorGreaterThanOrEqualTo = new OperatorGreaterThanOrEqualTo();
+ public static final NSSelector QualifierOperatorLessThan = new OperatorLessThan();
+ public static final NSSelector QualifierOperatorLessThanOrEqualTo = new OperatorLessThanOrEqualTo();
+ public static final NSSelector QualifierOperatorLike = new OperatorLike();
+ public static final NSSelector QualifierOperatorNotEqual = new OperatorNotEqual();
+
+ /**
+ * Default constructor.
+ */
+ public EOQualifier() {
+ }
+
+ /**
+ * Adds all qualifier keys in this qualifier to the specified Set, which is
+ * expected to be mutable. The tree of qualifiers is traversed and the
+ * left-hand-side of each expression is added to the set.
+ */
+ public void addQualifierKeysToSet(Set aSet) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Set of all property names used for comparisons by this qualifier.
+ * The tree of qualifiers is traversed and the left-hand-side of each expression
+ * is added to the set.
+ */
+ public NSSet allQualifierKeys() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a List containing the variables used at compare-time by this
+ * qualifier. Each variable will appear only once in the list.
+ */
+ public NSArray bindingKeys() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether the specified object meets the criteria defined by this
+ * qualifier.
+ */
+ public boolean evaluateWithObject(Object anObject) {
+ return true;
+ }
+
+ /**
+ * Returns the key (which can be a key path) that is tested against the
+ * specified binding variable. The tree is traversed looking for the first
+ * instance of the specified variable, and the corresponding left-hand-side of
+ * the expression is returned.
+ */
+ public String keyPathForBindingKey(String aVariable) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a qualifier that is like this qualifier, except all variables will be
+ * replaced with values from the specified Map whose keys match the variable
+ * names. If requireAll is true, an exception will be thrown if there is no key
+ * that matches on of the variables in the tree; otherwise, the qualifier
+ * containing the unmatched variable is removed.
+ */
+ public EOQualifier qualifierWithBindings(Map aMap, boolean requireAll) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ /**
+ * Tests whether all the keys in this qualifier can be applied to an object of
+ * the specified class.
+ *
+ * @return A Throwable if the validation fails, otherwise returns null if the
+ * class can be used with this qualifier.
+ */
+ public Throwable validateKeysWithRootClassDescription(Class aClass) {
+ throw new WotonomyException("Not implemented yet.");
+ }
+
+ // statics
+
+ /**
+ * Convenience to retain only those objects from the specified List that meet
+ * the specified qualifier's requirements.
+ */
+ public static void filterArrayWithQualifier(List anObjectList, EOQualifier aQualifier) {
+ ListIterator iterator = anObjectList.listIterator();
+ while (iterator.hasNext()) {
+ if (!aQualifier.evaluateWithObject(iterator.next())) {
+ iterator.remove();
+ }
+ }
+ }
+
+ /**
+ * Convenience to return a List consisting only of those objects in the
+ * specified List that meet the specified qualifier's requirements.
+ */
+ public static NSArray filteredArrayWithQualifier(List anObjectList, EOQualifier aQualifier) {
+ Object o;
+ List result = new LinkedList();
+ Iterator iterator = anObjectList.iterator();
+ while (iterator.hasNext()) {
+ o = iterator.next();
+ if (aQualifier.evaluateWithObject(o)) {
+ result.add(o);
+ }
+ }
+ return new NSArray((Collection) result);
+ }
+
+ /**
+ * Convenience to create a set of EOKeyValueQualifiers joined by an
+ * EOAndQualifier. Each pair of keys and values are used to create
+ * EOKeyValueQualifiers.
+ */
+ public static EOQualifier qualifierToMatchAllValues(Map aMap) {
+ Object key, value;
+ List qualifierList = new LinkedList();
+ Iterator iterator = aMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ key = iterator.next();
+ value = aMap.get(key);
+ qualifierList.add(new EOKeyValueQualifier(key.toString(), QualifierOperatorEqual, value));
+ }
+ return new EOAndQualifier(qualifierList);
+ }
+
+ /**
+ * Convenience to create a set of EOKeyValueQualifiers joined by an
+ * EOOrQualifier. Each pair of keys and values are used to create
+ * EOKeyValueQualifiers.
+ */
+ public static EOQualifier qualifierToMatchAnyValue(Map aMap) {
+ Object key, value;
+ List qualifierList = new LinkedList();
+ Iterator iterator = aMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ key = iterator.next();
+ value = aMap.get(key);
+ qualifierList.add(new EOKeyValueQualifier(key.toString(), QualifierOperatorEqual, value));
+ }
+ return new EOOrQualifier(qualifierList);
+ }
+
+ /**
+ * Returns an EOQualifier that meets the criteria represented by the specified
+ * string and variable length argument list. This method parses the string and
+ * returns a tree of qualifiers. Each token beginning with "%" is replaced with
+ * the corresponding object from the argument list. The parser recognizes the
+ * operation tokens returned from the allQualifierOperators() method.
+ */
+ public static EOQualifier qualifierWithQualifierFormat(String aString, List anArgumentList) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a List of operators that are supported for relational operations.
+ * This excludes string comparison operators.
+ */
+ public static NSArray relationalQualifierOperators() {
+ NSMutableArray result = new NSMutableArray();
+ BaseSelector selector;
+ Iterator iterator = allQualifierOperators().iterator();
+ while (iterator.hasNext()) {
+ selector = (BaseSelector) iterator.next();
+ if (selector.isRelationalOperator()) {
+ result.addObject(selector);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns a List of valid operators.
+ */
+ public static NSArray allQualifierOperators() {
+ return operators.allKeys();
+ }
+
+ /**
+ * Returns a selector the corresponds to the operation represented by the
+ * specified string. For example, ">" represents QualifierOperatorGreaterThan.
+ */
+ public static NSSelector operatorSelectorForString(String anOperatorString) {
+ return (NSSelector) operators.objectForKey(anOperatorString);
+ }
+
+ /**
+ * Returns a string the corresponds to the operation represented by the
+ * specified selector. For example, QualifierOperatorGreaterThan is represented
+ * with ">".
+ */
+ public static String stringForOperatorSelector(NSSelector aSelector) {
+ return (String) operators.allKeysForObject(aSelector).lastObject();
+ }
+
+ /**
+ * Returns a string representation of this qualifier.
+ */
+ public String toString() {
+ // TODO: implement this
+ return super.toString();
+ }
+
+ // built-in qualifiers
+
+ private static NSMutableDictionary operators;
+ static {
+ operators = new NSMutableDictionary();
+ operators.setObjectForKey(QualifierOperatorCaseInsensitiveLike,
+ QualifierOperatorCaseInsensitiveLike.toString());
+ operators.setObjectForKey(QualifierOperatorContains, QualifierOperatorContains.toString());
+ operators.setObjectForKey(QualifierOperatorEqual, QualifierOperatorEqual.toString());
+ operators.setObjectForKey(QualifierOperatorGreaterThan, QualifierOperatorGreaterThan.toString());
+ operators.setObjectForKey(QualifierOperatorGreaterThanOrEqualTo,
+ QualifierOperatorGreaterThanOrEqualTo.toString());
+ operators.setObjectForKey(QualifierOperatorLessThan, QualifierOperatorLessThan.toString());
+ operators.setObjectForKey(QualifierOperatorLessThanOrEqualTo, QualifierOperatorLessThanOrEqualTo.toString());
+ operators.setObjectForKey(QualifierOperatorLike, QualifierOperatorLike.toString());
+ operators.setObjectForKey(QualifierOperatorNotEqual, QualifierOperatorNotEqual.toString());
+ }
+
+ static private abstract class BaseSelector extends NSSelector {
+ public String name() {
+ return "BaseSelector";
+ }
+
+ public Class[] parameterTypes() {
+ return new Class[] { Object.class, Object.class };
+ }
+
+ public Method methodOnClass(Class aClass) throws NoSuchMethodException {
+ throw new NoSuchMethodException();
+ }
+
+ public Method methodOnObject(Object anObject) throws NoSuchMethodException {
+ throw new NoSuchMethodException();
+ }
+
+ public boolean implementedByClass(Class aClass) {
+ return true;
+ }
+
+ public boolean implementedByObject(Object anObject) {
+ return true;
+ }
+
+ public boolean isRelationalOperator() {
+ return true;
+ }
+
+ public Object invoke(Object anObject, Object[] parameters) throws IllegalAccessException,
+ IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return qualify(anObject, parameters[0]);
+ }
+
+ abstract protected Boolean qualify(Object target, Object parameter);
+
+ protected int doCompare(Object o1, Object o2) {
+ Class firstClass = o1.getClass();
+ Class secondClass = o2.getClass();
+
+ if (!(secondClass.equals(firstClass))) {
+ Object converted = null;
+ if (o2 instanceof Comparable) {
+ converted = ValueConverter.convertObjectToClass(o1, secondClass);
+ if (converted != null) {
+ o1 = converted;
+ }
+ }
+
+ if (converted == null && (o1 instanceof Comparable)) {
+ converted = ValueConverter.convertObjectToClass(o2, firstClass);
+ if (converted != null) {
+ o2 = converted;
+ }
+ }
+
+ if (converted == null) {
+ throw new WotonomyException("Qualifier: Not Comparable Objects");
+ // no way to compare
+ }
+ }
+
+ return ((Comparable) o2).compareTo(o1);
+ }
+
+ }
+
+ static class OperatorCaseInsensitiveLike extends BaseSelector {
+
+ public boolean isRelationalOperator() {
+ return false;
+ }
+
+ protected Boolean qualify(Object o1, Object o2) {
+ String myString1 = o1.toString();
+ String myString2 = o2.toString();
+ myString1 = myString1.toLowerCase();
+ myString2 = myString2.toLowerCase();
+ StringTokenizer st = new StringTokenizer(myString1, "%");
+
+ while (st.hasMoreTokens()) {
+ String part = st.nextToken();
+ int index = myString2.indexOf(part);
+ if (index > -1) {
+ myString2 = myString2.substring(index + part.length());
+ } else {
+ return Boolean.FALSE;
+ }
+ }
+ return Boolean.TRUE;
+
+ }
+
+ public String toString() {
+ return "caseInsensitiveLike";
+ }
+ }
+
+ static class OperatorContains extends BaseSelector {
+
+ public boolean isRelationalOperator() {
+ return false;
+ }
+
+ protected Boolean qualify(Object o1, Object o2) {
+ String myString1 = o1.toString();
+ String myString2 = o2.toString();
+ return new Boolean(myString2.indexOf(myString1) > -1);
+ }
+
+ public String toString() {
+ return "contains";
+ }
+ }
+
+ static class OperatorEqual extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(doCompare(o1, o2) == 0);
+ }
+
+ public String toString() {
+ return "=";
+ }
+ }
+
+ static class OperatorGreaterThan extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(doCompare(o1, o2) > 0);
+ }
+
+ public String toString() {
+ return ">";
+ }
+ }
+
+ static class OperatorGreaterThanOrEqualTo extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(doCompare(o1, o2) >= 0);
+ }
+
+ public String toString() {
+ return new String(" >= ");
+ }
+ }
+
+ static class OperatorLessThan extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(doCompare(o1, o2) < 0);
+ }
+
+ public String toString() {
+ return ">";
+ }
+ }
+
+ static class OperatorLessThanOrEqualTo extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(doCompare(o1, o2) <= 0);
+ }
+
+ public String toString() {
+ return "<=";
+ }
+ }
+
+ static class OperatorLike extends BaseSelector {
+
+ public boolean isRelationalOperator() {
+ return false;
+ }
+
+ protected Boolean qualify(Object o1, Object o2) {
+ String myString1 = o1.toString();
+ String myString2 = o2.toString();
+ StringTokenizer st = new StringTokenizer(myString1, "%");
+ while (st.hasMoreTokens()) {
+ String part = st.nextToken();
+ int index = myString2.indexOf(part);
+ if (index > -1) {
+ myString2 = myString2.substring(index + part.length());
+ } else {
+ return Boolean.FALSE;
+ }
+ }
+ return Boolean.TRUE;
+ }
+
+ public String toString() {
+ return "like";
+ }
+ }
+
+ static class OperatorNotEqual extends BaseSelector {
+
+ protected Boolean qualify(Object o1, Object o2) {
+ return new Boolean(!(o1.equals(o2)));
+ }
+
+ public String toString() {
+ return "!=";
+ }
+ }
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver ua) {
- String cname = (String)ua.decodeObjectForKey("class");
+ String cname = (String) ua.decodeObjectForKey("class");
if (cname.equals("EOKeyValueQualifier"))
- return (EOQualifier)EOKeyValueQualifier.decodeWithKeyValueUnarchiver(ua);
+ return (EOQualifier) EOKeyValueQualifier.decodeWithKeyValueUnarchiver(ua);
if (cname.equals("EOAndQualifier"))
- return (EOQualifier)EOAndQualifier.decodeWithKeyValueUnarchiver(ua);
+ return (EOQualifier) EOAndQualifier.decodeWithKeyValueUnarchiver(ua);
if (cname.equals("EOOrQualifier"))
- return (EOQualifier)EOOrQualifier.decodeWithKeyValueUnarchiver(ua);
+ return (EOQualifier) EOOrQualifier.decodeWithKeyValueUnarchiver(ua);
if (cname.equals("EONotQualifier"))
- return (EOQualifier)EONotQualifier.decodeWithKeyValueUnarchiver(ua);
+ return (EOQualifier) EONotQualifier.decodeWithKeyValueUnarchiver(ua);
return null;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.10 2003/08/09 01:22:51 chochos
- * qualifiers implement EOKeyValueArchiving
+ * Revision 1.10 2003/08/09 01:22:51 chochos qualifiers implement
+ * EOKeyValueArchiving
*
- * Revision 1.9 2001/11/04 18:29:11 mpowers
- * Better handling for non-string types used with non-relational operators.
+ * Revision 1.9 2001/11/04 18:29:11 mpowers Better handling for non-string types
+ * used with non-relational operators.
*
- * Revision 1.8 2001/10/31 15:25:14 mpowers
- * Cleanup of qualifiers.
+ * Revision 1.8 2001/10/31 15:25:14 mpowers Cleanup of qualifiers.
*
- * Revision 1.7 2001/10/30 22:57:28 mpowers
- * EOQualifier framework is now working.
+ * Revision 1.7 2001/10/30 22:57:28 mpowers EOQualifier framework is now
+ * working.
*
- * Revision 1.6 2001/10/30 22:16:37 mpowers
- * Implemented operators as selectors.
+ * Revision 1.6 2001/10/30 22:16:37 mpowers Implemented operators as selectors.
*
- * Revision 1.5 2001/09/14 14:21:28 mpowers
- * Updated javadoc.
+ * Revision 1.5 2001/09/14 14:21:28 mpowers Updated javadoc.
*
- * Revision 1.3 2001/09/13 15:25:56 mpowers
- * Started implementation of the EOQualifier framework.
+ * Revision 1.3 2001/09/13 15:25:56 mpowers Started implementation of the
+ * EOQualifier framework.
*
- * Revision 1.2 2001/02/27 03:33:04 mpowers
- * Initial draft of the key-value qualifier.
+ * Revision 1.2 2001/02/27 03:33:04 mpowers Initial draft of the key-value
+ * qualifier.
*
- * Revision 1.1.1.1 2000/12/21 15:46:47 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:47 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifierEvaluation.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifierEvaluation.java
index 87769b8..bbdc190 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifierEvaluation.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifierEvaluation.java
@@ -18,25 +18,23 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EOQualifiers that want to perform in-memory
-* evaluation should implement this interface. <br><br>
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ * EOQualifiers that want to perform in-memory evaluation should implement this
+ * interface. <br>
+ * <br>
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public interface EOQualifierEvaluation {
public boolean evaluateWithObject(Object eo);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/08/12 01:42:17 chochos
- * formally declare this interface
+ * Revision 1.1 2003/08/12 01:42:17 chochos formally declare this interface
*
*/
- \ No newline at end of file
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EORelationshipManipulation.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EORelationshipManipulation.java
index 568b555..4b8845b 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EORelationshipManipulation.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EORelationshipManipulation.java
@@ -19,58 +19,48 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EORelationshipManipulation provides methods for generically
-* adding and removing relationships between objects, handling
-* both one-way and reciprocal relationships.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EORelationshipManipulation
-{
- /**
- * Adds the specified object to the relationship on this
- * object specified by the key. For to-one relationships,
- * this operation is the same as valueForKey.
- */
- void addObjectToPropertyWithKey(
- Object anObject, String aKey );
+ * EORelationshipManipulation provides methods for generically adding and
+ * removing relationships between objects, handling both one-way and reciprocal
+ * relationships.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EORelationshipManipulation {
+ /**
+ * Adds the specified object to the relationship on this object specified by the
+ * key. For to-one relationships, this operation is the same as valueForKey.
+ */
+ void addObjectToPropertyWithKey(Object anObject, String aKey);
- /**
- * Removes the specified object from the relationship on
- * this object specified by the key. For to-one relationships,
- * this operation is the same as takeValueForKey with a null
- * value.
- */
- void removeObjectFromPropertyWithKey(
- Object anObject, String aKey );
+ /**
+ * Removes the specified object from the relationship on this object specified
+ * by the key. For to-one relationships, this operation is the same as
+ * takeValueForKey with a null value.
+ */
+ void removeObjectFromPropertyWithKey(Object anObject, String aKey);
- /**
- * As addObjectToProperty with key, but also performs the
- * reciprocal operation on the other side of the relationship.
- */
- void addObjectToBothSidesOfRelationshipWithKey(
- EORelationshipManipulation anObject, String aKey );
-
- /**
- * As removeObjectFromPropertyWithKey with key, but also performs the
- * reciprocal operation on the other side of the relationship.
- */
- void removeObjectFromBothSidesOfRelationshipWithKey(
- EORelationshipManipulation anObject, String aKey );
+ /**
+ * As addObjectToProperty with key, but also performs the reciprocal operation
+ * on the other side of the relationship.
+ */
+ void addObjectToBothSidesOfRelationshipWithKey(EORelationshipManipulation anObject, String aKey);
+
+ /**
+ * As removeObjectFromPropertyWithKey with key, but also performs the reciprocal
+ * operation on the other side of the relationship.
+ */
+ void removeObjectFromBothSidesOfRelationshipWithKey(EORelationshipManipulation anObject, String aKey);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOSortOrdering.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOSortOrdering.java
index 789b6da..e2ce595 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOSortOrdering.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOSortOrdering.java
@@ -30,154 +30,128 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSSelector;
/**
-* EOSortOrdering defines a sort key and operation.
-* DisplayGroups use lists of EOSortOrdering to determine
-* how to order their items.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EOSortOrdering implements Serializable, EOKeyValueArchiving
-{
- /**
- * Sorts items in ascending order.
- */
- public static final
- NSSelector CompareAscending = new CompareAscendingComparator();
-
- /**
- * Sorts items in descending order.
- */
- public static final
- NSSelector CompareDescending = new CompareDescendingComparator();
-
- /**
- * Sorts items' string representations in ascending order
- * in a case insensitive manner.
- */
- public static final
- NSSelector CompareCaseInsensitiveAscending =
- new CompareCaseInsensitiveAscendingComparator();
-
- /**
- * Sorts items' string representations in descending order
- * in a case insensitive manner.
- */
- public static final
- NSSelector CompareCaseInsensitiveDescending =
- new CompareCaseInsensitiveDescendingComparator();
-
- protected String key;
- protected NSSelector selector;
-
- /**
- * Factory-style constructor returns a new EOSortOrdering instance
- * with the specified key and selector. Neither may be null.
- */
- public static EOSortOrdering sortOrderingWithKey(String key, NSSelector selector)
- {
- return new EOSortOrdering( key, selector );
- }
-
- /**
- * Constructor creates an EOSortOrdering that uses the
- * specified key and selector. Neither may be null.
- */
- public EOSortOrdering( String aKey, NSSelector aSelector )
- {
- key = aKey;
- selector = aSelector;
- }
-
- /**
- * Constructor creates an EOSortOrdering that uses the
- * specified key and comparator. Neither may be null.
- * Not in the spec.
- */
- public EOSortOrdering( String aKey, Comparator aComparator )
- {
- key = aKey;
- selector = new NSSelector( aKey, aComparator );
- }
-
- /**
- * Returns the property key.
- */
- public String key()
- {
- return key;
- }
-
- /**
- * Returns the selector.
- */
- public NSSelector selector()
- {
- return selector;
- }
-
- public String toString()
- {
- return "[EOSortOrdering: key='"+key+"' selector='"+selector+"']";
- }
-
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof EOSortOrdering )
- {
- EOSortOrdering x = (EOSortOrdering) anObject;
- if ( selector().equals( x.selector() ) )
- {
- if ( key().equals( x.key() ) )
- {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Sorts the specified list in place according to the specified
- * list of EOSortOrderings. The items will be sorted first by the
- * first ordering, and items with equal values for that property
- * will be sorted by the next ordering, and so on.
- */
- public static void sortArrayUsingKeyOrderArray(
- List anObjectList, List aSortOrderingList )
- {
- List keys = new ArrayList( aSortOrderingList );
- Collections.reverse( keys );
- Iterator it = keys.iterator();
- EOSortOrdering sortOrdering;
- while ( it.hasNext() )
- {
- sortOrdering = (EOSortOrdering) it.next();
- Collections.sort( anObjectList,
- new DelegatingComparator(
- sortOrdering.key(), sortOrdering.selector() ) );
- }
- }
-
- /**
- * Sorts the specified list in place according to the specified
- * list of EOSortOrderings. The items will be sorted first by the
- * first ordering, and items with equal values for that property
- * will be sorted by the next ordering, and so on.
- */
- public static NSArray sortedArrayUsingKeyOrderArray(
- List anObjectList, List aSortOrderingList )
- {
- NSArray result = new NSMutableArray();
- result.addAll( anObjectList );
- sortArrayUsingKeyOrderArray( result, aSortOrderingList );
- return result;
- }
+ * EOSortOrdering defines a sort key and operation. DisplayGroups use lists of
+ * EOSortOrdering to determine how to order their items.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EOSortOrdering implements Serializable, EOKeyValueArchiving {
+ /**
+ * Sorts items in ascending order.
+ */
+ public static final NSSelector CompareAscending = new CompareAscendingComparator();
+
+ /**
+ * Sorts items in descending order.
+ */
+ public static final NSSelector CompareDescending = new CompareDescendingComparator();
+
+ /**
+ * Sorts items' string representations in ascending order in a case insensitive
+ * manner.
+ */
+ public static final NSSelector CompareCaseInsensitiveAscending = new CompareCaseInsensitiveAscendingComparator();
+
+ /**
+ * Sorts items' string representations in descending order in a case insensitive
+ * manner.
+ */
+ public static final NSSelector CompareCaseInsensitiveDescending = new CompareCaseInsensitiveDescendingComparator();
+
+ protected String key;
+ protected NSSelector selector;
+
+ /**
+ * Factory-style constructor returns a new EOSortOrdering instance with the
+ * specified key and selector. Neither may be null.
+ */
+ public static EOSortOrdering sortOrderingWithKey(String key, NSSelector selector) {
+ return new EOSortOrdering(key, selector);
+ }
+
+ /**
+ * Constructor creates an EOSortOrdering that uses the specified key and
+ * selector. Neither may be null.
+ */
+ public EOSortOrdering(String aKey, NSSelector aSelector) {
+ key = aKey;
+ selector = aSelector;
+ }
+
+ /**
+ * Constructor creates an EOSortOrdering that uses the specified key and
+ * comparator. Neither may be null. Not in the spec.
+ */
+ public EOSortOrdering(String aKey, Comparator aComparator) {
+ key = aKey;
+ selector = new NSSelector(aKey, aComparator);
+ }
+
+ /**
+ * Returns the property key.
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Returns the selector.
+ */
+ public NSSelector selector() {
+ return selector;
+ }
+
+ public String toString() {
+ return "[EOSortOrdering: key='" + key + "' selector='" + selector + "']";
+ }
+
+ public boolean equals(Object anObject) {
+ if (anObject instanceof EOSortOrdering) {
+ EOSortOrdering x = (EOSortOrdering) anObject;
+ if (selector().equals(x.selector())) {
+ if (key().equals(x.key())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sorts the specified list in place according to the specified list of
+ * EOSortOrderings. The items will be sorted first by the first ordering, and
+ * items with equal values for that property will be sorted by the next
+ * ordering, and so on.
+ */
+ public static void sortArrayUsingKeyOrderArray(List anObjectList, List aSortOrderingList) {
+ List keys = new ArrayList(aSortOrderingList);
+ Collections.reverse(keys);
+ Iterator it = keys.iterator();
+ EOSortOrdering sortOrdering;
+ while (it.hasNext()) {
+ sortOrdering = (EOSortOrdering) it.next();
+ Collections.sort(anObjectList, new DelegatingComparator(sortOrdering.key(), sortOrdering.selector()));
+ }
+ }
+
+ /**
+ * Sorts the specified list in place according to the specified list of
+ * EOSortOrderings. The items will be sorted first by the first ordering, and
+ * items with equal values for that property will be sorted by the next
+ * ordering, and so on.
+ */
+ public static NSArray sortedArrayUsingKeyOrderArray(List anObjectList, List aSortOrderingList) {
+ NSArray result = new NSMutableArray();
+ result.addAll(anObjectList);
+ sortArrayUsingKeyOrderArray(result, aSortOrderingList);
+ return result;
+ }
public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
- String k = (String)arch.decodeObjectForKey("key");
- String sname = (String)arch.decodeObjectForKey("selectorName");
+ String k = (String) arch.decodeObjectForKey("key");
+ String sname = (String) arch.decodeObjectForKey("selectorName");
NSSelector sel = null;
if (sname.equals("compareAscending:"))
sel = CompareAscending;
@@ -189,8 +163,8 @@ public class EOSortOrdering implements Serializable, EOKeyValueArchiving
sel = CompareCaseInsensitiveAscending;
else {
if (sname.endsWith(":"))
- sname = sname.substring(0, sname.length()-1);
- sel = new NSSelector(sname, new Class[]{ Object.class });
+ sname = sname.substring(0, sname.length() - 1);
+ sel = new NSSelector(sname, new Class[] { Object.class });
}
return new EOSortOrdering(k, sel);
}
@@ -210,197 +184,147 @@ public class EOSortOrdering implements Serializable, EOKeyValueArchiving
arch.encodeObject(selector.name() + ":", "selectorName");
}
- private static class CompareAscendingComparator
- extends NSSelector
- {
- public int compare(Object o1, Object o2)
- {
- if ( o1 instanceof Comparable )
- {
- if ( o2 instanceof Comparable )
- {
- return ((Comparable)o1).compareTo( o2 );
- }
- }
-
- // null handling: null is less than any object
-
- if ( o1 == null )
- {
- if ( o2 == null )
- {
- return 0;
- }
- else
- {
- return -1;
- }
- }
- else // o1 != null
- if ( o2 == null )
- {
- return 1;
- }
-
- // fall back on string representation comparison
-
- return o1.toString().compareTo( o2.toString() );
- }
-
- public boolean equals(Object obj)
- {
- return ( this == obj );
- }
- }
-
- private static class CompareDescendingComparator
- extends CompareAscendingComparator
- {
- public int compare(Object o1, Object o2)
- {
- return -1 * super.compare( o1, o2 );
- }
- }
-
- private static class CompareCaseInsensitiveAscendingComparator
- extends NSSelector
- {
- public int compare(Object o1, Object o2)
- {
- // null handling: null is less than any object
-
- if ( o1 == null )
- {
- if ( o2 == null )
- {
- return 0;
- }
- else
- {
- return -1;
- }
- }
- else // o1 != null
- if ( o2 == null )
- {
- return 1;
- }
-
- return o1.toString().toLowerCase().compareTo(
- o2.toString().toLowerCase() );
- }
-
- public boolean equals(Object obj)
- {
- return ( this == obj );
- }
- }
-
- private static class CompareCaseInsensitiveDescendingComparator
- extends CompareCaseInsensitiveAscendingComparator
- {
- public int compare(Object o1, Object o2)
- {
- return -1 * super.compare( o1, o2 );
- }
- }
-
- private static class DelegatingComparator implements Comparator
- {
- private String key;
- private Comparator comparator;
-
- public DelegatingComparator( String aKey, Comparator aComparator )
- {
- key = aKey;
- comparator = aComparator;
- }
-
- public int compare(Object o1, Object o2)
- {
- Object v1, v2;
- if ( o1 instanceof EOKeyValueCoding )
- {
- v1 = ((EOKeyValueCoding)o1).valueForKey( key );
- }
- else
- {
- v1 = EOKeyValueCodingSupport.valueForKey( o1, key );
- }
- if ( o2 instanceof EOKeyValueCoding )
- {
- v2 = ((EOKeyValueCoding)o2).valueForKey( key );
- }
- else
- {
- v2 = EOKeyValueCodingSupport.valueForKey( o2, key );
- }
- return comparator.compare( v1, v2 );
- }
-
- public boolean equals(Object obj)
- {
- return ( this == obj );
- }
- }
+ private static class CompareAscendingComparator extends NSSelector {
+ public int compare(Object o1, Object o2) {
+ if (o1 instanceof Comparable) {
+ if (o2 instanceof Comparable) {
+ return ((Comparable) o1).compareTo(o2);
+ }
+ }
+
+ // null handling: null is less than any object
+
+ if (o1 == null) {
+ if (o2 == null) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else // o1 != null
+ if (o2 == null) {
+ return 1;
+ }
+
+ // fall back on string representation comparison
+
+ return o1.toString().compareTo(o2.toString());
+ }
+
+ public boolean equals(Object obj) {
+ return (this == obj);
+ }
+ }
+
+ private static class CompareDescendingComparator extends CompareAscendingComparator {
+ public int compare(Object o1, Object o2) {
+ return -1 * super.compare(o1, o2);
+ }
+ }
+
+ private static class CompareCaseInsensitiveAscendingComparator extends NSSelector {
+ public int compare(Object o1, Object o2) {
+ // null handling: null is less than any object
+
+ if (o1 == null) {
+ if (o2 == null) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else // o1 != null
+ if (o2 == null) {
+ return 1;
+ }
+
+ return o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
+ }
+
+ public boolean equals(Object obj) {
+ return (this == obj);
+ }
+ }
+
+ private static class CompareCaseInsensitiveDescendingComparator extends CompareCaseInsensitiveAscendingComparator {
+ public int compare(Object o1, Object o2) {
+ return -1 * super.compare(o1, o2);
+ }
+ }
+
+ private static class DelegatingComparator implements Comparator {
+ private String key;
+ private Comparator comparator;
+
+ public DelegatingComparator(String aKey, Comparator aComparator) {
+ key = aKey;
+ comparator = aComparator;
+ }
+
+ public int compare(Object o1, Object o2) {
+ Object v1, v2;
+ if (o1 instanceof EOKeyValueCoding) {
+ v1 = ((EOKeyValueCoding) o1).valueForKey(key);
+ } else {
+ v1 = EOKeyValueCodingSupport.valueForKey(o1, key);
+ }
+ if (o2 instanceof EOKeyValueCoding) {
+ v2 = ((EOKeyValueCoding) o2).valueForKey(key);
+ } else {
+ v2 = EOKeyValueCodingSupport.valueForKey(o2, key);
+ }
+ return comparator.compare(v1, v2);
+ }
+
+ public boolean equals(Object obj) {
+ return (this == obj);
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.14 2003/08/11 19:39:52 chochos
- * now encodes/decodes correctly.
+ * Revision 1.14 2003/08/11 19:39:52 chochos now encodes/decodes correctly.
*
- * Revision 1.13 2003/08/09 01:29:56 chochos
- * implements EOKeyValueArchiving
+ * Revision 1.13 2003/08/09 01:29:56 chochos implements EOKeyValueArchiving
*
- * Revision 1.12 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.12 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.11 2003/02/07 20:23:23 mpowers
- * Provided backwards compatibility for comparators.
+ * Revision 1.11 2003/02/07 20:23:23 mpowers Provided backwards compatibility
+ * for comparators.
*
- * Revision 1.10 2003/01/18 23:46:58 mpowers
- * EOSortOrdering is now correctly using NSSelectors.
+ * Revision 1.10 2003/01/18 23:46:58 mpowers EOSortOrdering is now correctly
+ * using NSSelectors.
*
- * Revision 1.9 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.9 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.8 2002/03/01 20:23:27 mpowers
- * Implemented equals.
+ * Revision 1.8 2002/03/01 20:23:27 mpowers Implemented equals.
*
- * Revision 1.7 2002/02/06 21:15:04 mpowers
- * Added null handling to CompareCaseInsensitiveAscendingComparator.
+ * Revision 1.7 2002/02/06 21:15:04 mpowers Added null handling to
+ * CompareCaseInsensitiveAscendingComparator.
*
- * Revision 1.6 2001/12/01 23:51:24 mpowers
- * Made serializable.
+ * Revision 1.6 2001/12/01 23:51:24 mpowers Made serializable.
*
- * Revision 1.5 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.5 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
- * Revision 1.4 2001/01/24 22:15:52 mpowers
- * Fixed npe when comparing nulls.
+ * Revision 1.4 2001/01/24 22:15:52 mpowers Fixed npe when comparing nulls.
*
- * Revision 1.3 2001/01/12 19:11:56 mpowers
- * Fixed table column click sorting.
+ * Revision 1.3 2001/01/12 19:11:56 mpowers Fixed table column click sorting.
*
- * Revision 1.2 2001/01/12 17:23:46 mpowers
- * Inner classes are now private.
+ * Revision 1.2 2001/01/12 17:23:46 mpowers Inner classes are now private.
*
- * Revision 1.1 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.1 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOTemporaryGlobalID.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOTemporaryGlobalID.java
index 44ba855..31351a9 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOTemporaryGlobalID.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOTemporaryGlobalID.java
@@ -21,199 +21,181 @@ package net.wotonomy.control;
import java.net.InetAddress;
/**
-* EOTemporaryGlobalID is a network-wide unique key.
-* This is used by EOEditingContext to construct temporary
-* ids when new objects are created. <br><br>
-*
-* The specified format of the key is a byte array:
-* &lt; Sequence [2], ProcessID [2], Time [4], IP Addr [4] &gt;,
-* but because java does not allow access to the process id,
-* the timestamp of when this class is first loaded is used
-* to simulate a process id.
-*
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class EOTemporaryGlobalID
- extends EOGlobalID
-{
- /**
- * Holds the length in bytes of the key that is generated.
- */
- public static final int UniqueBinaryKeyLength = 12;
-
- private static int sequence;
- private static byte[] processid; // 2 bytes
- private static byte[] ipaddr; // 4 bytes
-
- static // static initializer
- {
- // init sequence
- sequence = 0;
-
- // init processid
- processid = new byte[2];
- long time = System.currentTimeMillis();
- processid[1] = (byte) time;
- time = time >> 8;
- processid[0] = (byte) time;
-
- // init ipaddr
- ipaddr = new byte[4];
- try
- {
- ipaddr = InetAddress.getLocalHost().getAddress();
- }
- catch ( Exception exc )
- {
- // could not obtain ip address - use pid twice
- ipaddr[0] = processid[0];
- ipaddr[1] = processid[1];
- ipaddr[2] = processid[0];
- ipaddr[3] = processid[1];
- }
- }
-
- private byte[] key;
- private int hashCode;
-
- /**
- * Generates a new id with a unique key.
- */
- public EOTemporaryGlobalID()
- {
- key = new byte[UniqueBinaryKeyLength];
-
- // init sequence (important byte first)
- key[0] = (byte) ( sequence );
- key[1] = (byte) ( sequence >> 8 );
- sequence++;
-
- // populate pid (important byte first)
- key[2] = processid[1];
- key[3] = processid[0];
-
- // init time (important byte first)
- long time = System.currentTimeMillis();
- key[4] = (byte) time;
- time = time >> 8;
- key[5] = (byte) time;
- time = time >> 8;
- key[6] = (byte) time;
- time = time >> 8;
- key[7] = (byte) time;
-
- // populate ipaddr
- key[8] = ipaddr[0];
- key[9] = ipaddr[1];
- key[10] = ipaddr[2];
- key[11] = ipaddr[3];
-
- // use string's hash code
- hashCode = new String( key ).hashCode();
- }
-
- /**
- * Private constructor for cloning.
- */
- private EOTemporaryGlobalID( byte[] aKey )
- {
+ * EOTemporaryGlobalID is a network-wide unique key. This is used by
+ * EOEditingContext to construct temporary ids when new objects are created.
+ * <br>
+ * <br>
+ *
+ * The specified format of the key is a byte array: &lt; Sequence [2], ProcessID
+ * [2], Time [4], IP Addr [4] &gt;, but because java does not allow access to
+ * the process id, the timestamp of when this class is first loaded is used to
+ * simulate a process id.
+ *
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class EOTemporaryGlobalID extends EOGlobalID {
+ /**
+ * Holds the length in bytes of the key that is generated.
+ */
+ public static final int UniqueBinaryKeyLength = 12;
+
+ private static int sequence;
+ private static byte[] processid; // 2 bytes
+ private static byte[] ipaddr; // 4 bytes
+
+ static // static initializer
+ {
+ // init sequence
+ sequence = 0;
+
+ // init processid
+ processid = new byte[2];
+ long time = System.currentTimeMillis();
+ processid[1] = (byte) time;
+ time = time >> 8;
+ processid[0] = (byte) time;
+
+ // init ipaddr
+ ipaddr = new byte[4];
+ try {
+ ipaddr = InetAddress.getLocalHost().getAddress();
+ } catch (Exception exc) {
+ // could not obtain ip address - use pid twice
+ ipaddr[0] = processid[0];
+ ipaddr[1] = processid[1];
+ ipaddr[2] = processid[0];
+ ipaddr[3] = processid[1];
+ }
+ }
+
+ private byte[] key;
+ private int hashCode;
+
+ /**
+ * Generates a new id with a unique key.
+ */
+ public EOTemporaryGlobalID() {
+ key = new byte[UniqueBinaryKeyLength];
+
+ // init sequence (important byte first)
+ key[0] = (byte) (sequence);
+ key[1] = (byte) (sequence >> 8);
+ sequence++;
+
+ // populate pid (important byte first)
+ key[2] = processid[1];
+ key[3] = processid[0];
+
+ // init time (important byte first)
+ long time = System.currentTimeMillis();
+ key[4] = (byte) time;
+ time = time >> 8;
+ key[5] = (byte) time;
+ time = time >> 8;
+ key[6] = (byte) time;
+ time = time >> 8;
+ key[7] = (byte) time;
+
+ // populate ipaddr
+ key[8] = ipaddr[0];
+ key[9] = ipaddr[1];
+ key[10] = ipaddr[2];
+ key[11] = ipaddr[3];
+
+ // use string's hash code
+ hashCode = new String(key).hashCode();
+ }
+
+ /**
+ * Private constructor for cloning.
+ */
+ private EOTemporaryGlobalID(byte[] aKey) {
// key = aKey; // this might be faster
- // make copy of key - might be safer
- key = new byte[ UniqueBinaryKeyLength ];
- for ( int i = 0; i < UniqueBinaryKeyLength; i++ )
- {
- key[i] = aKey[i];
- }
-
- // use string's hash code
- hashCode = new String( aKey ).hashCode();
- }
-
- /**
- * Returns true.
- */
- public boolean isTemporary()
- {
- return true;
- }
-
- /**
- * Returns whether the keys are equal.
- */
- public boolean equals( Object anObject )
- {
- if ( ! ( anObject instanceof EOTemporaryGlobalID ) )
- return false;
-
- byte[] otherKey = ((EOTemporaryGlobalID)anObject).key;
-
- for ( int i = 0; i < UniqueBinaryKeyLength; i++ )
- {
- if ( key[i] != otherKey[i] ) return false;
- }
- return true;
- }
-
- /**
- * Returns a copy of this object.
- */
- public Object clone()
- {
- // faster than super.clone()
- return new EOTemporaryGlobalID( key );
- }
-
- public int hashCode()
- {
- return hashCode;
- }
-
- /**
- * Returns a string representation of this key.
- * This is a 24-character string with each pair
- * of characters holding a hexadecimal value that
- * is 128 more than the value of the corresponding
- * byte (to account for two's complement).
- */
- public String toString()
- {
- String hex;
- StringBuffer buffer = new StringBuffer();
- for ( int i = 0; i < key.length; i++ )
- {
- // get string: adjust for two's complement
- hex = Integer.toHexString( key[i]+128 );
- // pad with zero so we take two characters
- if ( hex.length() == 1 ) hex = "0" + hex;
- // append hex code
- buffer.append( hex );
- }
- return buffer.toString();
- }
+ // make copy of key - might be safer
+ key = new byte[UniqueBinaryKeyLength];
+ for (int i = 0; i < UniqueBinaryKeyLength; i++) {
+ key[i] = aKey[i];
+ }
+
+ // use string's hash code
+ hashCode = new String(aKey).hashCode();
+ }
+
+ /**
+ * Returns true.
+ */
+ public boolean isTemporary() {
+ return true;
+ }
+
+ /**
+ * Returns whether the keys are equal.
+ */
+ public boolean equals(Object anObject) {
+ if (!(anObject instanceof EOTemporaryGlobalID))
+ return false;
+
+ byte[] otherKey = ((EOTemporaryGlobalID) anObject).key;
+
+ for (int i = 0; i < UniqueBinaryKeyLength; i++) {
+ if (key[i] != otherKey[i])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a copy of this object.
+ */
+ public Object clone() {
+ // faster than super.clone()
+ return new EOTemporaryGlobalID(key);
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Returns a string representation of this key. This is a 24-character string
+ * with each pair of characters holding a hexadecimal value that is 128 more
+ * than the value of the corresponding byte (to account for two's complement).
+ */
+ public String toString() {
+ String hex;
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < key.length; i++) {
+ // get string: adjust for two's complement
+ hex = Integer.toHexString(key[i] + 128);
+ // pad with zero so we take two characters
+ if (hex.length() == 1)
+ hex = "0" + hex;
+ // append hex code
+ buffer.append(hex);
+ }
+ return buffer.toString();
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.4 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.3 2001/02/15 21:13:30 mpowers
- * First draft implementation is complete. Now on to debugging.
+ * Revision 1.3 2001/02/15 21:13:30 mpowers First draft implementation is
+ * complete. Now on to debugging.
*
- * Revision 1.2 2001/02/14 23:03:02 mpowers
- * A near-complete first draft of EOEditingContext.
+ * Revision 1.2 2001/02/14 23:03:02 mpowers A near-complete first draft of
+ * EOEditingContext.
*
- * Revision 1.1 2001/02/13 23:24:29 mpowers
- * Implementing more of editing context.
+ * Revision 1.1 2001/02/13 23:24:29 mpowers Implementing more of editing
+ * context.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOValidation.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOValidation.java
index a0aa4db..3054d4c 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOValidation.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOValidation.java
@@ -19,54 +19,48 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* EOValidation provides methods for validating a operation
-* on an object as a whole, rather than on an individual property.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface EOValidation
-{
- /**
- * Validates this object for delete.
- * Throws an exception if this object cannot be deleted.
- */
- void validateForDelete();
-
- /**
- * Validates this object for insertion into the external store.
- * Throws an exception if this object cannot be inserted.
- * Validations here should be specific to insertion.
- * Implementations may call validateForSave().
- */
- void validateForInsert();
-
- /**
- * Validates this object for a commit to the external store.
- * Throws an exception if this object cannot be committed.
- * Validations here are not specific to either inserts or updates.
- */
- void validateForSave();
-
- /**
- * Validates this object for update to the external store.
- * Throws an exception if this object cannot be updated.
- * Validations here should be specific to updates.
- * Implementations may call validateForSave().
- */
- void validateForUpdate();
+ * EOValidation provides methods for validating a operation on an object as a
+ * whole, rather than on an individual property.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface EOValidation {
+ /**
+ * Validates this object for delete. Throws an exception if this object cannot
+ * be deleted.
+ */
+ void validateForDelete();
+
+ /**
+ * Validates this object for insertion into the external store. Throws an
+ * exception if this object cannot be inserted. Validations here should be
+ * specific to insertion. Implementations may call validateForSave().
+ */
+ void validateForInsert();
+
+ /**
+ * Validates this object for a commit to the external store. Throws an exception
+ * if this object cannot be committed. Validations here are not specific to
+ * either inserts or updates.
+ */
+ void validateForSave();
+
+ /**
+ * Validates this object for update to the external store. Throws an exception
+ * if this object cannot be updated. Validations here should be specific to
+ * updates. Implementations may call validateForSave().
+ */
+ void validateForUpdate();
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/11/13 04:13:59 mpowers
- * Added interfaces needed to begin work on EOCustomObject.
+ * Revision 1.1 2001/11/13 04:13:59 mpowers Added interfaces needed to begin
+ * work on EOCustomObject.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOVectorKeyGlobalID.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOVectorKeyGlobalID.java
index cc91fd7..5fc500d 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOVectorKeyGlobalID.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOVectorKeyGlobalID.java
@@ -18,11 +18,11 @@
package net.wotonomy.control;
/**
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
public class EOVectorKeyGlobalID extends EOKeyGlobalID {
protected Object[] _keyValues;
@@ -35,14 +35,18 @@ public class EOVectorKeyGlobalID extends EOKeyGlobalID {
}
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#keyValuesNoCopy()
*/
public Object[] _keyValuesNoCopy() {
return _keyValues;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#_keyValues()
*/
public Object[] keyValues() {
@@ -53,14 +57,18 @@ public class EOVectorKeyGlobalID extends EOKeyGlobalID {
return v;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOKeyGlobalID#keyCount()
*/
public int keyCount() {
return _keyValues.length;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see net.wotonomy.control.EOGlobalID#isTemporary()
*/
public boolean isTemporary() {
@@ -69,11 +77,9 @@ public class EOVectorKeyGlobalID extends EOKeyGlobalID {
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/19 01:59:01 chochos
- * Added the wotonomy headers
+ * Revision 1.2 2003/08/19 01:59:01 chochos Added the wotonomy headers
*
*/
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EditingContext.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EditingContext.java
index ee40f23..1a120a5 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EditingContext.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EditingContext.java
@@ -25,259 +25,210 @@ import java.util.Map;
//import javax.swing.undo.UndoManager;
/**
-* EditingContext provides transactional support for
-* fetching, editing, and committing changes made on a
-* collection of objects to a parent object store.
-* This subclasses EOEditingContext to provide
-* java-friendly conveniences.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class EditingContext extends EOEditingContext
-{
- /**
- * Default constructor creates a new editing context
- * that uses the default object store. If the default
- * object store has not been set, an exception is thrown.
- */
- public EditingContext()
- {
- this( defaultParentObjectStore() );
- }
-
- /**
- * Creates a new editing context that uses the specified
- * object store as its parent object store.
- */
- public EditingContext( EOObjectStore anObjectStore )
- {
- super( anObjectStore );
- }
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship, or may return a placeholder array that
- * will defer the fetch until needed (aka an array fault).
- * All objects must be registered in the specified editing context.
- * This implementation calls to its parent object store's
- * implementation if the requested source object is not
- * registered in this editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public List getArrayFaultWithSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationshipKey,
- EOEditingContext aContext )
- {
- return arrayFaultWithSourceGlobalID(
- aGlobalID, aRelationshipKey, aContext );
- }
-
- /**
- * Returns a snapshot of the specified object as it
- * existed when it was last read or committed to the
- * parent object store.
- */
- public Map getCommittedSnapshotForObject (
- Object anObject )
- {
- return committedSnapshotForObject( anObject );
- }
-
- /**
- * Returns a snapshot of the specified object as it
- * existed before the edits triggered by the current
- * event loop were processed.
- */
- public Map getCurrentEventSnapshotForObject (
- Object anObject )
- {
- return currentEventSnapshotForObject( anObject );
- }
-
- /**
- * Returns the delegate for this editing context,
- * or null if no delegate has been set.
- */
- public Object getDelegate ()
- {
- return delegate();
- }
-
- /**
- * Returns a List of all objects marked as deleted
- * in this editing context.
- */
- public List getDeletedObjects ()
- {
- return deletedObjects();
- }
-
- /**
- * Returns a List of registered editors of this
- * editing context.
- */
- public List getEditors()
- {
- return editors();
- }
-
- /**
- * Returns the object for the specified id.
- * If the object's data has not been fetched,
- * it will be fetched when needed.
- */
- public Object getFaultForGlobalID (
- EOGlobalID aGlobalID )
- {
- return faultForGlobalID( aGlobalID, this );
- }
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary.
- */
- public Object getFaultForRawRow (
- Map aDictionary,
- String anEntityName )
- {
- return faultForRawRow( aDictionary, anEntityName );
- }
-
- /**
- * Returns the fetch timestamp for this editing context.
- */
- public double getFetchTimestamp()
- {
- return fetchTimestamp();
- }
-
- /**
- * Returns the id for the specified object, or null
- * if the object is not registered in this context.
- */
- public EOGlobalID getGlobalIDForObject (
- Object anObject )
- {
- return globalIDForObject( anObject );
- }
-
- /**
- * Returns a List of the objects that have been
- * inserted into this editing context.
- */
- public List getInsertedObjects ()
- {
- return insertedObjects();
- }
-
- /**
- * Returns the message handler for this editing context,
- * or null if no message handler has been set.
- */
- public Object getMessageHandler ()
- {
- return messageHandler();
- }
-
- /**
- * Returns the object registered in this editing context
- * for the specified id, or null if that id is not
- * registered.
- */
- public Object getObjectForGlobalID (
- EOGlobalID aGlobalID )
- {
- return objectForGlobalID( aGlobalID );
- }
-
- /**
- * Returns a List of objects the meet the criteria of
- * the supplied specification.
- */
- public List getObjectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec )
- {
- return objectsWithFetchSpecification( aFetchSpec );
- }
-
- /**
- * Returns the parent object store for this editing context.
- * The result will not be null.
- */
- public EOObjectStore getParentObjectStore ()
- {
- return parentObjectStore();
- }
-
- /**
- * Returns a List of all objects registered in this
- * editing context.
- */
- public List geRegisteredObjects ()
- {
- return registeredObjects();
- }
-
- /**
- * Returns the root object store, which is the parent
- * of all parent object stores of this editing context.
- */
- public EOObjectStore getRootObjectStore ()
- {
- return rootObjectStore();
- }
-
- /**
- * Returns a list of all objects marked as modified,
- * but not inserted or deleted, in this editing context.
- */
- public List getUpdatedObjects ()
- {
- return updatedObjects();
- }
-
- // static methods
-
- public static double getDefaultFetchTimestampLag()
- {
- return defaultFetchTimestampLag();
- }
-
- /**
- * Returns the default parent object store for all
- * object stores created with the parameterless
- * constructor.
- */
- public static EOObjectStore getDefaultParentObjectStore()
- {
- return defaultParentObjectStore();
- }
+ * EditingContext provides transactional support for fetching, editing, and
+ * committing changes made on a collection of objects to a parent object store.
+ * This subclasses EOEditingContext to provide java-friendly conveniences.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class EditingContext extends EOEditingContext {
+ /**
+ * Default constructor creates a new editing context that uses the default
+ * object store. If the default object store has not been set, an exception is
+ * thrown.
+ */
+ public EditingContext() {
+ this(defaultParentObjectStore());
+ }
+
+ /**
+ * Creates a new editing context that uses the specified object store as its
+ * parent object store.
+ */
+ public EditingContext(EOObjectStore anObjectStore) {
+ super(anObjectStore);
+ }
+
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship, or may return a placeholder array
+ * that will defer the fetch until needed (aka an array fault). All objects must
+ * be registered in the specified editing context. This implementation calls to
+ * its parent object store's implementation if the requested source object is
+ * not registered in this editing context. The specified relationship key must
+ * produce a result of type Collection for the source object or an exception is
+ * thrown.
+ */
+ public List getArrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationshipKey,
+ EOEditingContext aContext) {
+ return arrayFaultWithSourceGlobalID(aGlobalID, aRelationshipKey, aContext);
+ }
+
+ /**
+ * Returns a snapshot of the specified object as it existed when it was last
+ * read or committed to the parent object store.
+ */
+ public Map getCommittedSnapshotForObject(Object anObject) {
+ return committedSnapshotForObject(anObject);
+ }
+
+ /**
+ * Returns a snapshot of the specified object as it existed before the edits
+ * triggered by the current event loop were processed.
+ */
+ public Map getCurrentEventSnapshotForObject(Object anObject) {
+ return currentEventSnapshotForObject(anObject);
+ }
+
+ /**
+ * Returns the delegate for this editing context, or null if no delegate has
+ * been set.
+ */
+ public Object getDelegate() {
+ return delegate();
+ }
+
+ /**
+ * Returns a List of all objects marked as deleted in this editing context.
+ */
+ public List getDeletedObjects() {
+ return deletedObjects();
+ }
+
+ /**
+ * Returns a List of registered editors of this editing context.
+ */
+ public List getEditors() {
+ return editors();
+ }
+
+ /**
+ * Returns the object for the specified id. If the object's data has not been
+ * fetched, it will be fetched when needed.
+ */
+ public Object getFaultForGlobalID(EOGlobalID aGlobalID) {
+ return faultForGlobalID(aGlobalID, this);
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary.
+ */
+ public Object getFaultForRawRow(Map aDictionary, String anEntityName) {
+ return faultForRawRow(aDictionary, anEntityName);
+ }
+
+ /**
+ * Returns the fetch timestamp for this editing context.
+ */
+ public double getFetchTimestamp() {
+ return fetchTimestamp();
+ }
+
+ /**
+ * Returns the id for the specified object, or null if the object is not
+ * registered in this context.
+ */
+ public EOGlobalID getGlobalIDForObject(Object anObject) {
+ return globalIDForObject(anObject);
+ }
+
+ /**
+ * Returns a List of the objects that have been inserted into this editing
+ * context.
+ */
+ public List getInsertedObjects() {
+ return insertedObjects();
+ }
+
+ /**
+ * Returns the message handler for this editing context, or null if no message
+ * handler has been set.
+ */
+ public Object getMessageHandler() {
+ return messageHandler();
+ }
+
+ /**
+ * Returns the object registered in this editing context for the specified id,
+ * or null if that id is not registered.
+ */
+ public Object getObjectForGlobalID(EOGlobalID aGlobalID) {
+ return objectForGlobalID(aGlobalID);
+ }
+
+ /**
+ * Returns a List of objects the meet the criteria of the supplied
+ * specification.
+ */
+ public List getObjectsWithFetchSpecification(EOFetchSpecification aFetchSpec) {
+ return objectsWithFetchSpecification(aFetchSpec);
+ }
+
+ /**
+ * Returns the parent object store for this editing context. The result will not
+ * be null.
+ */
+ public EOObjectStore getParentObjectStore() {
+ return parentObjectStore();
+ }
+
+ /**
+ * Returns a List of all objects registered in this editing context.
+ */
+ public List geRegisteredObjects() {
+ return registeredObjects();
+ }
+
+ /**
+ * Returns the root object store, which is the parent of all parent object
+ * stores of this editing context.
+ */
+ public EOObjectStore getRootObjectStore() {
+ return rootObjectStore();
+ }
+
+ /**
+ * Returns a list of all objects marked as modified, but not inserted or
+ * deleted, in this editing context.
+ */
+ public List getUpdatedObjects() {
+ return updatedObjects();
+ }
+
+ // static methods
+
+ public static double getDefaultFetchTimestampLag() {
+ return defaultFetchTimestampLag();
+ }
+
+ /**
+ * Returns the default parent object store for all object stores created with
+ * the parameterless constructor.
+ */
+ public static EOObjectStore getDefaultParentObjectStore() {
+ return defaultParentObjectStore();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2002/03/26 21:46:36 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.1 2002/03/26 21:46:36 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/KeyValueCodingUtilities.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/KeyValueCodingUtilities.java
index 1aa2147..d052fcf 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/KeyValueCodingUtilities.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/KeyValueCodingUtilities.java
@@ -38,227 +38,169 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* KeyValueCodingUtilities implements what
-* EOKeyValueCodingSupport leaves out. Importantly,
-* this class implements the deep clone and deep copy
-* operations that are essential to the functioning of
-* nested editing contexts.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 900 $
-*/
-public class KeyValueCodingUtilities
-{
- /**
- * Returns a Map of the specified keys to their values,
- * each of which is obtained by calling valueForKey
- * on the specified object if it implements EOKeyValueCoding,
- * and otherwise falling back on EOKeyValueCodingSupport.
- * Null values must be represented by NSNull.nullValue().
- */
- static public NSDictionary valuesForKeys(
- Object anObject, List aKeyList )
- {
- return valuesForKeys( anObject, aKeyList, false );
- }
-
- /**
- * Returns a Map of the specified keys to their values,
- * each of which is obtained by calling storedValueForKey
- * on the specified object if it implements EOKeyValueCoding,
- * and otherwise falling back on EOKeyValueCodingSupport.
- * Null values must be represented by NSNull.nullValue().
- */
- static public NSDictionary storedValuesForKeys(
- Object anObject, List aKeyList )
- {
- return valuesForKeys( anObject, aKeyList, true );
- }
-
- /**
- * Called by valuesForKeys and storedValuesForKeys.
- * This uses storedValueForKey if isStored is true,
- * otherwise uses valueForKey.
- */
- static private NSDictionary valuesForKeys(
- Object anObject, List aKeyList, boolean isStored )
- {
- EOKeyValueCoding coding;
- if ( anObject instanceof EOKeyValueCoding )
- {
- coding = (EOKeyValueCoding) anObject;
- }
- else
- {
- coding = null;
- }
-
- String key;
- Object value;
- NSMutableDictionary result = new NSMutableDictionary();
- Iterator it = aKeyList.iterator();
- while ( it.hasNext() )
- {
- //TODO: get rid of this try/catch - exceptions should be fatal (?)
- try
- {
- key = it.next().toString();
- if ( coding != null )
- {
- if ( isStored )
- value = coding.storedValueForKey( key );
- else
- value = coding.valueForKey( key );
- }
- else
- {
- if ( isStored )
- value = EOKeyValueCodingSupport.storedValueForKey( anObject, key );
- else
- value = EOKeyValueCodingSupport.valueForKey( anObject, key );
- }
- if ( value == null )
- {
- value = EONullValue.nullValue();
- }
- result.setObjectForKey( value, key );
- }
- catch ( RuntimeException exc )
- {
- System.out.println(
- "KeyValueCodingUtilities.valuesForKeys: "
- + isStored + " : " + exc );
- }
- }
- return result;
- }
-
- /**
- * Takes the keys from the specified Map as properties
- * and applies the corresponding values, each of which
- * might be set by calling takeValueForKey on the
- * specified object if it implements EOKeyValueCoding,
- * and otherwise falling back on EOKeyValueCodingSupport.
- * Null values must be represented by NSNull.nullValue().
- */
- static public void takeValuesFromDictionary(
- Object anObject, Map aMap )
- {
- takeStoredValuesFromDictionary( anObject, aMap, false );
- }
-
- /**
- * Takes the keys from the specified Map as properties
- * and applies the corresponding values, each of which
- * might be set by calling takeStoredValueForKey on the
- * specified object if it implements EOKeyValueCoding,
- * and otherwise falling back on EOKeyValueCodingSupport.
- * Null values must be represented by NSNull.nullValue().
- */
- static public void takeStoredValuesFromDictionary(
- Object anObject, Map aMap )
- {
- takeStoredValuesFromDictionary( anObject, aMap, true );
- }
-
- /**
- * Called by takeValuesFromDictionary and takeStoredValuesFromDictionary.
- * This uses takeStoredValueForKey if isStored is true,
- * otherwise uses takeValueForKey.
- */
- static private void takeStoredValuesFromDictionary(
- Object anObject, Map aMap, boolean isStored )
- {
- EOKeyValueCoding coding;
- if ( anObject instanceof EOKeyValueCoding )
- {
- coding = (EOKeyValueCoding) anObject;
- }
- else
- {
- coding = null;
- }
-
- String key;
- Object value;
- NSMutableDictionary result = new NSMutableDictionary();
- Iterator it = aMap.keySet().iterator();
- while ( it.hasNext() )
- {
- //TODO: get rid of this try/catch - exceptions should be fatal (?)
- try
- {
- key = it.next().toString();
- value = aMap.get( key );
- if ( value instanceof EONullValue )
- // can't use == nullValue() because of cloning/serialization
- {
- value = null;
- }
- if ( coding != null )
- {
- if ( isStored )
- coding.takeStoredValueForKey( value, key );
- else
- coding.takeValueForKey( value, key );
- }
- else
- {
- if ( isStored )
- EOKeyValueCodingSupport.takeStoredValueForKey(
- anObject, value, key );
- else
- EOKeyValueCodingSupport.takeValueForKey(
- anObject, value, key );
- }
- }
- catch ( WotonomyException exc )
- {
- System.out.println(
- "KeyValueCodingUtilities.takeStoredValuesFromDictionary: "
- + isStored + " : " + exc );
- }
- }
- }
-
- /**
- * Creates a deep clone of the specified object.
- * (Object.clone() only creates a shallow clone.)
- * Returns null if operation fails.
- */
- static public Object clone( Object aSource )
- {
- return Duplicator.deepClone( aSource );
- }
-
- /**
- * Creates a deep clone of the specified object,
- * registered in the specified source editing context,
- * transposing it into the specified destination
- * editing context.
- * Returns null if operation fails.
- */
- static public Object clone(
- EOEditingContext aSourceContext, Object aSource,
- EOEditingContext aDestinationContext )
- {
- return clone( aSourceContext, aSource, aDestinationContext, aSource );
- }
-
- /**
- * Called by clone and copy.
- * The specified root object will not be replaced
- * by an object in the destination editing context:
- * this should be the same as the source object for
- * cloning, but should be null for copying.
- * Returns null if operation fails.
- */
- static private Object clone(
- EOEditingContext aSourceContext, Object aSource,
- EOEditingContext aDestinationContext,
- Object aRootObject )
- {
+ * KeyValueCodingUtilities implements what EOKeyValueCodingSupport leaves out.
+ * Importantly, this class implements the deep clone and deep copy operations
+ * that are essential to the functioning of nested editing contexts.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 900 $
+ */
+public class KeyValueCodingUtilities {
+ /**
+ * Returns a Map of the specified keys to their values, each of which is
+ * obtained by calling valueForKey on the specified object if it implements
+ * EOKeyValueCoding, and otherwise falling back on EOKeyValueCodingSupport. Null
+ * values must be represented by NSNull.nullValue().
+ */
+ static public NSDictionary valuesForKeys(Object anObject, List aKeyList) {
+ return valuesForKeys(anObject, aKeyList, false);
+ }
+
+ /**
+ * Returns a Map of the specified keys to their values, each of which is
+ * obtained by calling storedValueForKey on the specified object if it
+ * implements EOKeyValueCoding, and otherwise falling back on
+ * EOKeyValueCodingSupport. Null values must be represented by
+ * NSNull.nullValue().
+ */
+ static public NSDictionary storedValuesForKeys(Object anObject, List aKeyList) {
+ return valuesForKeys(anObject, aKeyList, true);
+ }
+
+ /**
+ * Called by valuesForKeys and storedValuesForKeys. This uses storedValueForKey
+ * if isStored is true, otherwise uses valueForKey.
+ */
+ static private NSDictionary valuesForKeys(Object anObject, List aKeyList, boolean isStored) {
+ EOKeyValueCoding coding;
+ if (anObject instanceof EOKeyValueCoding) {
+ coding = (EOKeyValueCoding) anObject;
+ } else {
+ coding = null;
+ }
+
+ String key;
+ Object value;
+ NSMutableDictionary result = new NSMutableDictionary();
+ Iterator it = aKeyList.iterator();
+ while (it.hasNext()) {
+ // TODO: get rid of this try/catch - exceptions should be fatal (?)
+ try {
+ key = it.next().toString();
+ if (coding != null) {
+ if (isStored)
+ value = coding.storedValueForKey(key);
+ else
+ value = coding.valueForKey(key);
+ } else {
+ if (isStored)
+ value = EOKeyValueCodingSupport.storedValueForKey(anObject, key);
+ else
+ value = EOKeyValueCodingSupport.valueForKey(anObject, key);
+ }
+ if (value == null) {
+ value = EONullValue.nullValue();
+ }
+ result.setObjectForKey(value, key);
+ } catch (RuntimeException exc) {
+ System.out.println("KeyValueCodingUtilities.valuesForKeys: " + isStored + " : " + exc);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Takes the keys from the specified Map as properties and applies the
+ * corresponding values, each of which might be set by calling takeValueForKey
+ * on the specified object if it implements EOKeyValueCoding, and otherwise
+ * falling back on EOKeyValueCodingSupport. Null values must be represented by
+ * NSNull.nullValue().
+ */
+ static public void takeValuesFromDictionary(Object anObject, Map aMap) {
+ takeStoredValuesFromDictionary(anObject, aMap, false);
+ }
+
+ /**
+ * Takes the keys from the specified Map as properties and applies the
+ * corresponding values, each of which might be set by calling
+ * takeStoredValueForKey on the specified object if it implements
+ * EOKeyValueCoding, and otherwise falling back on EOKeyValueCodingSupport. Null
+ * values must be represented by NSNull.nullValue().
+ */
+ static public void takeStoredValuesFromDictionary(Object anObject, Map aMap) {
+ takeStoredValuesFromDictionary(anObject, aMap, true);
+ }
+
+ /**
+ * Called by takeValuesFromDictionary and takeStoredValuesFromDictionary. This
+ * uses takeStoredValueForKey if isStored is true, otherwise uses
+ * takeValueForKey.
+ */
+ static private void takeStoredValuesFromDictionary(Object anObject, Map aMap, boolean isStored) {
+ EOKeyValueCoding coding;
+ if (anObject instanceof EOKeyValueCoding) {
+ coding = (EOKeyValueCoding) anObject;
+ } else {
+ coding = null;
+ }
+
+ String key;
+ Object value;
+ NSMutableDictionary result = new NSMutableDictionary();
+ Iterator it = aMap.keySet().iterator();
+ while (it.hasNext()) {
+ // TODO: get rid of this try/catch - exceptions should be fatal (?)
+ try {
+ key = it.next().toString();
+ value = aMap.get(key);
+ if (value instanceof EONullValue)
+ // can't use == nullValue() because of cloning/serialization
+ {
+ value = null;
+ }
+ if (coding != null) {
+ if (isStored)
+ coding.takeStoredValueForKey(value, key);
+ else
+ coding.takeValueForKey(value, key);
+ } else {
+ if (isStored)
+ EOKeyValueCodingSupport.takeStoredValueForKey(anObject, value, key);
+ else
+ EOKeyValueCodingSupport.takeValueForKey(anObject, value, key);
+ }
+ } catch (WotonomyException exc) {
+ System.out.println("KeyValueCodingUtilities.takeStoredValuesFromDictionary: " + isStored + " : " + exc);
+ }
+ }
+ }
+
+ /**
+ * Creates a deep clone of the specified object. (Object.clone() only creates a
+ * shallow clone.) Returns null if operation fails.
+ */
+ static public Object clone(Object aSource) {
+ return Duplicator.deepClone(aSource);
+ }
+
+ /**
+ * Creates a deep clone of the specified object, registered in the specified
+ * source editing context, transposing it into the specified destination editing
+ * context. Returns null if operation fails.
+ */
+ static public Object clone(EOEditingContext aSourceContext, Object aSource, EOEditingContext aDestinationContext) {
+ return clone(aSourceContext, aSource, aDestinationContext, aSource);
+ }
+
+ /**
+ * Called by clone and copy. The specified root object will not be replaced by
+ * an object in the destination editing context: this should be the same as the
+ * source object for cloning, but should be null for copying. Returns null if
+ * operation fails.
+ */
+ static private Object clone(EOEditingContext aSourceContext, Object aSource, EOEditingContext aDestinationContext,
+ Object aRootObject) {
//System.out.println();
//System.out.println( "clone: " + aSourceContext );
@@ -266,475 +208,361 @@ public class KeyValueCodingUtilities
//System.out.println( " : " + aDestinationContext );
//System.out.println();
- // the only known way to deep copy in
- // java without native code is serialization
-
- return thaw(
- freeze( aSource, aSourceContext, aRootObject, true ),
- aDestinationContext, true );
- }
-
- /**
- * Serializes an object to a byte array containing
- * GlobalIDMarkers in place of references to other objects
- * registered in the specified context.
- * The specified root object will be serialized,
- * even if it is registered in the specified context:
- * this is typically the root object you're trying to
- * serialize.
- * Package access, as this method is used by editing
- * context for snapshots.
- */
- static public byte[] freeze(
- Object anObject, EOEditingContext aContext, Object aRootObject, boolean transpose )
- {
- try
- {
+ // the only known way to deep copy in
+ // java without native code is serialization
+
+ return thaw(freeze(aSource, aSourceContext, aRootObject, true), aDestinationContext, true);
+ }
+
+ /**
+ * Serializes an object to a byte array containing GlobalIDMarkers in place of
+ * references to other objects registered in the specified context. The
+ * specified root object will be serialized, even if it is registered in the
+ * specified context: this is typically the root object you're trying to
+ * serialize. Package access, as this method is used by editing context for
+ * snapshots.
+ */
+ static public byte[] freeze(Object anObject, EOEditingContext aContext, Object aRootObject, boolean transpose) {
+ try {
//long t = System.currentTimeMillis();
- ByteArrayOutputStream byteOutput =
- new ByteArrayOutputStream();// CloneBufferSize );
- ObjectOutputStream objectOutput;
- if ( transpose )
- {
- objectOutput =
- new TransposingContextObjectOutputStream(
- byteOutput, aContext, aRootObject );
- }
- else
- {
- objectOutput =
- new ContextObjectOutputStream(
- byteOutput, aContext );
- }
-
- objectOutput.writeObject( anObject );
- objectOutput.flush();
- objectOutput.close();
-
- return byteOutput.toByteArray();
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();// CloneBufferSize );
+ ObjectOutputStream objectOutput;
+ if (transpose) {
+ objectOutput = new TransposingContextObjectOutputStream(byteOutput, aContext, aRootObject);
+ } else {
+ objectOutput = new ContextObjectOutputStream(byteOutput, aContext);
+ }
+
+ objectOutput.writeObject(anObject);
+ objectOutput.flush();
+ objectOutput.close();
+
+ return byteOutput.toByteArray();
// profiling
-/*
-byte[] result = byteOutput.toByteArray();
-long size = result.length;
-long time = ( System.currentTimeMillis() - t );
-maxSize = Math.max( size, maxSize );
-minSize = Math.min( size, minSize );
-totSize += size;
-maxTime = Math.max( time, maxTime );
-minTime = Math.min( time, minTime );
-totTime += time;
-nTime++;
-System.out.println( "freeze: size = [ " + size + " : " + minSize + " : " + ( (float)totSize / (float)nTime ) + " : " + maxSize
-+ " ] time = [ " + time + " : " + minTime + " : " + ( (float)totTime / (float)nTime ) + " : " + maxTime + " ]" );
-return result;
-*/
+ /*
+ * byte[] result = byteOutput.toByteArray(); long size = result.length; long
+ * time = ( System.currentTimeMillis() - t ); maxSize = Math.max( size, maxSize
+ * ); minSize = Math.min( size, minSize ); totSize += size; maxTime = Math.max(
+ * time, maxTime ); minTime = Math.min( time, minTime ); totTime += time;
+ * nTime++; System.out.println( "freeze: size = [ " + size + " : " + minSize +
+ * " : " + ( (float)totSize / (float)nTime ) + " : " + maxSize + " ] time = [ "
+ * + time + " : " + minTime + " : " + ( (float)totTime / (float)nTime ) + " : "
+ * + maxTime + " ]" ); return result;
+ */
// end profiling
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
//static long maxTime, minTime, totTime, nTime, maxSize, minSize, totSize;
//static long maxTimeThaw, minTimeThaw, totTimeThaw, nTimeThaw;
- /**
- * De-serializes an object from the specified byte
- * array, replacing GlobalIDMarkers with reference
- * to objects registered in the specified editing
- * context.
- * Package access, as this method is used by editing
- * context for snapshots.
- */
- static public Object thaw(
- byte[] aByteArray, EOEditingContext aContext, boolean transpose )
- {
- return thaw( aByteArray, aContext, null, transpose );
- }
-
- /**
- * De-serializes an object from the specified byte
- * array, replacing GlobalIDMarkers with reference
- * to objects registered in the specified editing
- * context.
- * Package access, as this method is used by editing
- * context for snapshots.
- */
- static public Object thaw(
- byte[] aByteArray, EOEditingContext aContext, ClassLoader aLoader, boolean transpose )
- {
- try
- {
+ /**
+ * De-serializes an object from the specified byte array, replacing
+ * GlobalIDMarkers with reference to objects registered in the specified editing
+ * context. Package access, as this method is used by editing context for
+ * snapshots.
+ */
+ static public Object thaw(byte[] aByteArray, EOEditingContext aContext, boolean transpose) {
+ return thaw(aByteArray, aContext, null, transpose);
+ }
+
+ /**
+ * De-serializes an object from the specified byte array, replacing
+ * GlobalIDMarkers with reference to objects registered in the specified editing
+ * context. Package access, as this method is used by editing context for
+ * snapshots.
+ */
+ static public Object thaw(byte[] aByteArray, EOEditingContext aContext, ClassLoader aLoader, boolean transpose) {
+ try {
//long t = System.currentTimeMillis();
- ByteArrayInputStream byteInput =
- new ByteArrayInputStream( aByteArray );
- ObjectInputStream objectInput;
- if ( transpose )
- {
- objectInput =
- new TransposingContextObjectInputStream(
- byteInput, aContext, aLoader );
- }
- else
- {
- objectInput =
- new ContextObjectInputStream(
- byteInput, aContext, aLoader );
- }
-
- return objectInput.readObject();
+ ByteArrayInputStream byteInput = new ByteArrayInputStream(aByteArray);
+ ObjectInputStream objectInput;
+ if (transpose) {
+ objectInput = new TransposingContextObjectInputStream(byteInput, aContext, aLoader);
+ } else {
+ objectInput = new ContextObjectInputStream(byteInput, aContext, aLoader);
+ }
+
+ return objectInput.readObject();
// profiling
-/*
-Object result = objectInput.readObject();
-long timeThaw = ( System.currentTimeMillis() - t );
-maxTimeThaw = Math.max( timeThaw, maxTimeThaw );
-minTimeThaw = Math.min( timeThaw, minTimeThaw );
-totTimeThaw += timeThaw;
-nTimeThaw++;
-System.out.println( "thaw: size = " + aByteArray.length + ", time = [ " + timeThaw + " : " + minTimeThaw + " : " + ( (float)totTimeThaw / (float)nTimeThaw ) + " : " + maxTimeThaw + " ]" );
-return result;
-*/
+ /*
+ * Object result = objectInput.readObject(); long timeThaw = (
+ * System.currentTimeMillis() - t ); maxTimeThaw = Math.max( timeThaw,
+ * maxTimeThaw ); minTimeThaw = Math.min( timeThaw, minTimeThaw ); totTimeThaw
+ * += timeThaw; nTimeThaw++; System.out.println( "thaw: size = " +
+ * aByteArray.length + ", time = [ " + timeThaw + " : " + minTimeThaw + " : " +
+ * ( (float)totTimeThaw / (float)nTimeThaw ) + " : " + maxTimeThaw + " ]" );
+ * return result;
+ */
// end profiling
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
- /**
- * Copies values from one object registered in the
- * specified origin context to the specified destination
- * object
- * The values themselves are cloned, so this is a deep copy.
- * Returns the destination object, or throws exception
- * if operation fails.
- */
- static public Object copy( Object aSource, Object aDestination )
- {
- NSDictionary values = (NSDictionary)
- clone( valuesForKeys( aSource,
- EOClassDescription.classDescriptionForClass(
- aSource.getClass() ).attributeKeys() ) );
-
- takeStoredValuesFromDictionary( aDestination, values );
- return aDestination;
- }
-
- /**
- * Copies values from one object registered in the
- * specified origin context to the specified destination
- * object
- * The values themselves are cloned, so this is a deep copy.
- * Returns the destination object, or throws exception
- * if operation fails.
- */
- static public Object copy(
- EOEditingContext aSourceContext, Object aSource,
- EOEditingContext aDestinationContext, Object aDestination )
- {
- // get all keys for this object
- EOClassDescription classDesc =
- EOClassDescription.classDescriptionForClass( aSource.getClass() );
- List keys = new LinkedList();
- keys.addAll( classDesc.attributeKeys() );
- keys.addAll( classDesc.toOneRelationshipKeys() );
- keys.addAll( classDesc.toManyRelationshipKeys() );
-
- // transpose all objects registered in source context
- NSDictionary values = storedValuesForKeys( aSource, keys );
- values = (NSDictionary)
- clone( aSourceContext, values, aDestinationContext, null );
-
- // apply to destination object
- takeStoredValuesFromDictionary( aDestination, values );
- return aDestination;
- }
-
- // inner classes
-
- /**
- * An ObjectOutputStream that serializes objects with references
- * to an editing context. The specified context will not be
- * serialized but referenced, so that a ContextObjectInputStream
- * can replace the reference with another editing context.
- */
- static private class ContextObjectOutputStream extends ObjectOutputStream
- {
- private EditingContextMarker marker = new EditingContextMarker();
- protected EOEditingContext editingContext;
-
- /**
- * Specifies the output stream to wrap,
- * and the source context that should be
- * referenced but not serialized.
- */
- public ContextObjectOutputStream(
- OutputStream anOutputStream,
- EOEditingContext aContext )
- throws IOException
- {
- super( anOutputStream );
- editingContext = aContext;
- try
- {
- enableReplaceObject(true);
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
- }
-
- protected Object replaceObject(Object anObject) throws IOException
- {
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
+ /**
+ * Copies values from one object registered in the specified origin context to
+ * the specified destination object The values themselves are cloned, so this is
+ * a deep copy. Returns the destination object, or throws exception if operation
+ * fails.
+ */
+ static public Object copy(Object aSource, Object aDestination) {
+ NSDictionary values = (NSDictionary) clone(valuesForKeys(aSource,
+ EOClassDescription.classDescriptionForClass(aSource.getClass()).attributeKeys()));
+
+ takeStoredValuesFromDictionary(aDestination, values);
+ return aDestination;
+ }
+
+ /**
+ * Copies values from one object registered in the specified origin context to
+ * the specified destination object The values themselves are cloned, so this is
+ * a deep copy. Returns the destination object, or throws exception if operation
+ * fails.
+ */
+ static public Object copy(EOEditingContext aSourceContext, Object aSource, EOEditingContext aDestinationContext,
+ Object aDestination) {
+ // get all keys for this object
+ EOClassDescription classDesc = EOClassDescription.classDescriptionForClass(aSource.getClass());
+ List keys = new LinkedList();
+ keys.addAll(classDesc.attributeKeys());
+ keys.addAll(classDesc.toOneRelationshipKeys());
+ keys.addAll(classDesc.toManyRelationshipKeys());
+
+ // transpose all objects registered in source context
+ NSDictionary values = storedValuesForKeys(aSource, keys);
+ values = (NSDictionary) clone(aSourceContext, values, aDestinationContext, null);
+
+ // apply to destination object
+ takeStoredValuesFromDictionary(aDestination, values);
+ return aDestination;
+ }
+
+ // inner classes
+
+ /**
+ * An ObjectOutputStream that serializes objects with references to an editing
+ * context. The specified context will not be serialized but referenced, so that
+ * a ContextObjectInputStream can replace the reference with another editing
+ * context.
+ */
+ static private class ContextObjectOutputStream extends ObjectOutputStream {
+ private EditingContextMarker marker = new EditingContextMarker();
+ protected EOEditingContext editingContext;
+
+ /**
+ * Specifies the output stream to wrap, and the source context that should be
+ * referenced but not serialized.
+ */
+ public ContextObjectOutputStream(OutputStream anOutputStream, EOEditingContext aContext) throws IOException {
+ super(anOutputStream);
+ editingContext = aContext;
+ try {
+ enableReplaceObject(true);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ }
+
+ protected Object replaceObject(Object anObject) throws IOException {
// if ( anObject == editingContext ) return marker;
//FIXME: this should be more strict as above
- if ( anObject instanceof EOEditingContext ) return marker;
- return anObject;
- }
-
- }
-
- /**
- * A ContextObjectOutputStream that replaces any objects registered
- * in the source editing context with markers to be used in
- * ContextObjectInputStream.
- */
- static private class TransposingContextObjectOutputStream
- extends ContextObjectOutputStream
- {
- protected Object rootObject;
-
- /**
- * Specifies the output stream to wrap,
- * the source context containing objects that
- * should be replaced if found,
- * and the object which should not be re-registered,
- * which is typically the object being cloned, but
- * may be null.
- */
- public TransposingContextObjectOutputStream(
- OutputStream anOutputStream,
- EOEditingContext aContext,
- Object anObject )
- throws IOException
- {
- super( anOutputStream, aContext );
- rootObject = anObject;
- }
-
- protected Object replaceObject(Object anObject) throws IOException
- {
- if ( anObject == rootObject ) return anObject;
- if ( editingContext != null )
- {
- EOGlobalID id = editingContext.globalIDForObject( anObject );
- if ( id != null )
- {
- Object result = new GlobalIDMarker( id );
- //System.out.println( "KeyValueCodingUtilities.replaceObject: returning: " + result );
- return result;
- }
- }
- return super.replaceObject( anObject );
- }
-
- }
-
- /**
- * A marker class so references to objects registered in editing
- * contexts get transposed rather than cloned.
- */
- static private class GlobalIDMarker implements Serializable
- {
- private EOGlobalID id;
-
- public GlobalIDMarker( EOGlobalID anID )
- {
- id = anID;
- }
-
- public EOGlobalID getID()
- {
- return id;
- }
-
- public String toString()
- {
- return "[GlobalIDMarker:"+id+"]";
- }
- }
-
- /**
- * A marker class so references an object's editing context
- * gets transposed rather than cloned.
- */
- static private class EditingContextMarker implements Serializable
- {
- // just a marker class - no implementation necessary
- }
-
- /**
- * An ObjectInputStream that replaces any markers from
- * ContextObjectOutputStream with objects registered
- * in the destination editing context.
- */
- static private class ContextObjectInputStream extends ObjectInputStream
- {
- protected EOEditingContext editingContext;
- protected ClassLoader classLoader;
-
- /**
- * Specifies the output stream to wrap,
- * the source context containing objects that
- * should be to replace any markers.
- * The class loader may be null.
- */
- public ContextObjectInputStream(
- InputStream anInputStream,
- EOEditingContext aContext,
- ClassLoader aClassLoader )
- throws IOException
- {
- super( anInputStream );
- editingContext = aContext;
- classLoader = aClassLoader;
- if ( classLoader == null )
- {
- classLoader =
- KeyValueCodingUtilities.class.getClassLoader();
- }
- try
- {
- enableResolveObject(true);
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
- }
-
- protected Object resolveObject(Object anObject) throws IOException
- {
- if ( anObject instanceof EditingContextMarker )
- {
- return editingContext;
- }
- return anObject;
- }
-
- protected Class resolveClass(ObjectStreamClass v)
- throws IOException, ClassNotFoundException
- {
- return classLoader.loadClass( v.getName() );
- }
- }
-
- /**
- * A ContextObjectInputStream that replaces any markers from
- * TransposingContextObjectOutputStream with objects registered
- * in the destination editing context.
- */
- static private class TransposingContextObjectInputStream
- extends ContextObjectInputStream
- {
- /**
- * Specifies the output stream to wrap,
- * the source context containing objects that
- * should be to replace any markers.
- */
- public TransposingContextObjectInputStream(
- InputStream anInputStream,
- EOEditingContext aContext,
- ClassLoader aClassLoader )
- throws IOException
- {
- super( anInputStream, aContext, aClassLoader );
- }
-
- protected Object resolveObject(Object anObject) throws IOException
- {
- if ( anObject instanceof GlobalIDMarker )
- {
- return editingContext.faultForGlobalID(
- ((GlobalIDMarker)anObject).getID(), editingContext );
- }
- return super.resolveObject( anObject );
- }
- }
-
+ if (anObject instanceof EOEditingContext)
+ return marker;
+ return anObject;
+ }
+
+ }
+
+ /**
+ * A ContextObjectOutputStream that replaces any objects registered in the
+ * source editing context with markers to be used in ContextObjectInputStream.
+ */
+ static private class TransposingContextObjectOutputStream extends ContextObjectOutputStream {
+ protected Object rootObject;
+
+ /**
+ * Specifies the output stream to wrap, the source context containing objects
+ * that should be replaced if found, and the object which should not be
+ * re-registered, which is typically the object being cloned, but may be null.
+ */
+ public TransposingContextObjectOutputStream(OutputStream anOutputStream, EOEditingContext aContext,
+ Object anObject) throws IOException {
+ super(anOutputStream, aContext);
+ rootObject = anObject;
+ }
+
+ protected Object replaceObject(Object anObject) throws IOException {
+ if (anObject == rootObject)
+ return anObject;
+ if (editingContext != null) {
+ EOGlobalID id = editingContext.globalIDForObject(anObject);
+ if (id != null) {
+ Object result = new GlobalIDMarker(id);
+ // System.out.println( "KeyValueCodingUtilities.replaceObject: returning: " +
+ // result );
+ return result;
+ }
+ }
+ return super.replaceObject(anObject);
+ }
+
+ }
+
+ /**
+ * A marker class so references to objects registered in editing contexts get
+ * transposed rather than cloned.
+ */
+ static private class GlobalIDMarker implements Serializable {
+ private EOGlobalID id;
+
+ public GlobalIDMarker(EOGlobalID anID) {
+ id = anID;
+ }
+
+ public EOGlobalID getID() {
+ return id;
+ }
+
+ public String toString() {
+ return "[GlobalIDMarker:" + id + "]";
+ }
+ }
+
+ /**
+ * A marker class so references an object's editing context gets transposed
+ * rather than cloned.
+ */
+ static private class EditingContextMarker implements Serializable {
+ // just a marker class - no implementation necessary
+ }
+
+ /**
+ * An ObjectInputStream that replaces any markers from ContextObjectOutputStream
+ * with objects registered in the destination editing context.
+ */
+ static private class ContextObjectInputStream extends ObjectInputStream {
+ protected EOEditingContext editingContext;
+ protected ClassLoader classLoader;
+
+ /**
+ * Specifies the output stream to wrap, the source context containing objects
+ * that should be to replace any markers. The class loader may be null.
+ */
+ public ContextObjectInputStream(InputStream anInputStream, EOEditingContext aContext, ClassLoader aClassLoader)
+ throws IOException {
+ super(anInputStream);
+ editingContext = aContext;
+ classLoader = aClassLoader;
+ if (classLoader == null) {
+ classLoader = KeyValueCodingUtilities.class.getClassLoader();
+ }
+ try {
+ enableResolveObject(true);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ }
+
+ protected Object resolveObject(Object anObject) throws IOException {
+ if (anObject instanceof EditingContextMarker) {
+ return editingContext;
+ }
+ return anObject;
+ }
+
+ protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException {
+ return classLoader.loadClass(v.getName());
+ }
+ }
+
+ /**
+ * A ContextObjectInputStream that replaces any markers from
+ * TransposingContextObjectOutputStream with objects registered in the
+ * destination editing context.
+ */
+ static private class TransposingContextObjectInputStream extends ContextObjectInputStream {
+ /**
+ * Specifies the output stream to wrap, the source context containing objects
+ * that should be to replace any markers.
+ */
+ public TransposingContextObjectInputStream(InputStream anInputStream, EOEditingContext aContext,
+ ClassLoader aClassLoader) throws IOException {
+ super(anInputStream, aContext, aClassLoader);
+ }
+
+ protected Object resolveObject(Object anObject) throws IOException {
+ if (anObject instanceof GlobalIDMarker) {
+ return editingContext.faultForGlobalID(((GlobalIDMarker) anObject).getID(), editingContext);
+ }
+ return super.resolveObject(anObject);
+ }
+ }
+
}
/*
- * $Log$
- * Revision 1.3 2006/02/18 22:46:44 cgruber
- * Add Surrogate map from .util into control's internal package, and fix imports.
+ * $Log$ Revision 1.3 2006/02/18 22:46:44 cgruber Add Surrogate map from .util
+ * into control's internal package, and fix imports.
*
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to "internal"
+ * packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.15 2003/01/21 22:30:10 mpowers
- * thaw() now allows you to pass in a class loader.
+ * Revision 1.15 2003/01/21 22:30:10 mpowers thaw() now allows you to pass in a
+ * class loader.
*
- * Revision 1.14 2002/05/15 13:46:35 mpowers
- * Exposed freeze and thaw as public.
+ * Revision 1.14 2002/05/15 13:46:35 mpowers Exposed freeze and thaw as public.
*
- * Revision 1.13 2001/08/22 19:25:13 mpowers
- * Added (and commented out) profiling code for freeze.
+ * Revision 1.13 2001/08/22 19:25:13 mpowers Added (and commented out) profiling
+ * code for freeze.
*
- * Revision 1.12 2001/05/06 18:27:10 mpowers
- * More broadly catching editing contexts for now.
+ * Revision 1.12 2001/05/06 18:27:10 mpowers More broadly catching editing
+ * contexts for now.
*
- * Revision 1.11 2001/05/05 13:18:49 mpowers
- * Fixed: transposing output stream was not returning the object to replace.
+ * Revision 1.11 2001/05/05 13:18:49 mpowers Fixed: transposing output stream
+ * was not returning the object to replace.
*
- * Revision 1.10 2001/05/04 16:57:56 mpowers
- * Now correctly transposing references to editing contexts when
- * cloning/copying between editing contexts.
+ * Revision 1.10 2001/05/04 16:57:56 mpowers Now correctly transposing
+ * references to editing contexts when cloning/copying between editing contexts.
*
- * Revision 1.9 2001/05/04 14:42:58 mpowers
- * Now getting stored values in KeyValueCoding.
- * MasterDetail now marks dirty based on whether it's an attribute
- * or relation.
- * Implemented editing context marker.
+ * Revision 1.9 2001/05/04 14:42:58 mpowers Now getting stored values in
+ * KeyValueCoding. MasterDetail now marks dirty based on whether it's an
+ * attribute or relation. Implemented editing context marker.
*
- * Revision 1.8 2001/05/02 15:47:40 mpowers
- * Fixed the pernicious problem with reverts: recordObject was recording
- * a snapshot of the clone before the transposition-copy happened,
- * so the revert object would lose all of its transposed relationships.
+ * Revision 1.8 2001/05/02 15:47:40 mpowers Fixed the pernicious problem with
+ * reverts: recordObject was recording a snapshot of the clone before the
+ * transposition-copy happened, so the revert object would lose all of its
+ * transposed relationships.
*
- * Revision 1.7 2001/04/30 12:33:17 mpowers
- * Fixed problem with use of EONullValue.nullValue(), which can't be used
- * when we're serializably duplicating objects.
+ * Revision 1.7 2001/04/30 12:33:17 mpowers Fixed problem with use of
+ * EONullValue.nullValue(), which can't be used when we're serializably
+ * duplicating objects.
*
- * Revision 1.6 2001/04/30 02:14:25 mpowers
- * Copying should call takeStoredValueForKeys.
+ * Revision 1.6 2001/04/30 02:14:25 mpowers Copying should call
+ * takeStoredValueForKeys.
*
- * Revision 1.5 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.5 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.4 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
+ * Revision 1.4 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
*
- * Revision 1.3 2001/04/28 16:18:44 mpowers
- * Implementing relationships.
+ * Revision 1.3 2001/04/28 16:18:44 mpowers Implementing relationships.
*
- * Revision 1.2 2001/04/28 14:12:23 mpowers
- * Refactored cloning/copying into KeyValueCodingUtilities.
+ * Revision 1.2 2001/04/28 14:12:23 mpowers Refactored cloning/copying into
+ * KeyValueCodingUtilities.
*
- * Revision 1.1 2001/04/27 23:41:12 mpowers
- * Contributing file for KeyValueCodingUtilities.
+ * Revision 1.1 2001/04/27 23:41:12 mpowers Contributing file for
+ * KeyValueCodingUtilities.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ObservableArray.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ObservableArray.java
index 19d39ff..ff66578 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ObservableArray.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/ObservableArray.java
@@ -26,321 +26,272 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSRange;
/**
-* A package class that extends NSMutableArray but makes use
-* of the fact that wotonomy's implementation extends ArrayList
-* to intercept insertions and deletion and register and
-* unregister objects for change notifications as appropriate.
-* Since we can't be sure of ArrayList's implementation, we're
-* forced to override each and every add and remove method,
-* some of which probably call each other. However,
-* EOObserverCenter will only register us once per object.
-*/
-class ObservableArray extends NSMutableArray
-{
- EOObserving observer;
-
- ObservableArray( EOObserving anObserver )
- {
- observer = anObserver;
- }
-
+ * A package class that extends NSMutableArray but makes use of the fact that
+ * wotonomy's implementation extends ArrayList to intercept insertions and
+ * deletion and register and unregister objects for change notifications as
+ * appropriate. Since we can't be sure of ArrayList's implementation, we're
+ * forced to override each and every add and remove method, some of which
+ * probably call each other. However, EOObserverCenter will only register us
+ * once per object.
+ */
+class ObservableArray extends NSMutableArray {
+ EOObserving observer;
+
+ ObservableArray(EOObserving anObserver) {
+ observer = anObserver;
+ }
+
/**
- * Removes the last object from the array.
- */
- public void removeLastObject ()
- {
- remove( count() - 1 );
- }
+ * Removes the last object from the array.
+ */
+ public void removeLastObject() {
+ remove(count() - 1);
+ }
/**
- * Removes the object at the specified index.
- */
- public void removeObjectAtIndex (int index)
- {
- remove( index );
- }
+ * Removes the object at the specified index.
+ */
+ public void removeObjectAtIndex(int index) {
+ remove(index);
+ }
/**
- * Adds all objects in the specified collection.
- */
- public void addObjectsFromArray (Collection aCollection)
- {
- addAll( aCollection );
- }
+ * Adds all objects in the specified collection.
+ */
+ public void addObjectsFromArray(Collection aCollection) {
+ addAll(aCollection);
+ }
/**
- * Removes all objects from the array.
- */
- public void removeAllObjects ()
- {
- clear();
- }
+ * Removes all objects from the array.
+ */
+ public void removeAllObjects() {
+ clear();
+ }
/**
- * Removes all objects equivalent to the specified object
- * within the range of specified indices.
- */
- public void removeObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( get( i ) ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all objects equivalent to the specified object within the range of
+ * specified indices.
+ */
+ public void removeObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(get(i))) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all instances of the specified object within the
- * range of specified indices, comparing by reference.
- */
- public void removeIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == get( i ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all instances of the specified object within the range of specified
+ * indices, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == get(i)) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all objects in the specified collection from the array.
- */
- public void removeObjectsInArray (Collection aCollection)
- {
- removeAll( aCollection );
- }
+ * Removes all objects in the specified collection from the array.
+ */
+ public void removeObjectsInArray(Collection aCollection) {
+ removeAll(aCollection);
+ }
/**
- * Removes all objects in the indices within the specified range
- * from the array.
- */
- public void removeObjectsInRange (NSRange aRange)
- {
- if ( aRange == null ) return;
-
- for ( int i = 0; i < aRange.length(); i++ )
- {
- remove( aRange.location() );
- }
- }
+ * Removes all objects in the indices within the specified range from the array.
+ */
+ public void removeObjectsInRange(NSRange aRange) {
+ if (aRange == null)
+ return;
+
+ for (int i = 0; i < aRange.length(); i++) {
+ remove(aRange.location());
+ }
+ }
/**
- * Replaces objects in the current range with objects from
- * the specified range of the specified array. If currentRange
- * is larger than otherRange, the extra objects are removed.
- * If otherRange is larger than currentRange, the extra objects
- * are added.
- */
- public void replaceObjectsInRange (NSRange currentRange,
- List otherArray, NSRange otherRange)
- {
- if ( ( currentRange == null ) || ( otherArray == null ) ||
- ( otherRange == null ) ) return;
-
+ * Replaces objects in the current range with objects from the specified range
+ * of the specified array. If currentRange is larger than otherRange, the extra
+ * objects are removed. If otherRange is larger than currentRange, the extra
+ * objects are added.
+ */
+ public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ if ((currentRange == null) || (otherArray == null) || (otherRange == null))
+ return;
+
// transform otherRange if out of bounds for array
- if ( otherRange.maxRange() > otherArray.size() )
- {
+ if (otherRange.maxRange() > otherArray.size()) {
// TODO: Test this logic.
- int loc = Math.min( otherRange.location(), otherArray.size() - 1 );
- otherRange = new NSRange( loc, otherArray.size() - loc );
+ int loc = Math.min(otherRange.location(), otherArray.size() - 1);
+ otherRange = new NSRange(loc, otherArray.size() - loc);
}
-
+
Object o;
- List subList = subList(
- currentRange.location(), currentRange.maxRange() );
+ List subList = subList(currentRange.location(), currentRange.maxRange());
int otherIndex = otherRange.location();
// TODO: Test this logic.
- for ( int i = 0; i < subList.size(); i++ )
- {
- if ( otherIndex < otherRange.maxRange() )
- { // set object
- subList.set( i, otherArray.get( otherIndex ) );
- }
- else
- { // remove extra elements from currentRange
- subList.remove( i );
- i--;
+ for (int i = 0; i < subList.size(); i++) {
+ if (otherIndex < otherRange.maxRange()) { // set object
+ subList.set(i, otherArray.get(otherIndex));
+ } else { // remove extra elements from currentRange
+ subList.remove(i);
+ i--;
}
otherIndex++;
}
// TODO: Test this logic.
- for ( int i = otherIndex; i < otherRange.maxRange(); i++ )
- {
- add( otherArray.get( i ) );
+ for (int i = otherIndex; i < otherRange.maxRange(); i++) {
+ add(otherArray.get(i));
}
}
/**
- * Clears the current array and then populates it with the
- * contents of the specified collection.
- */
- public void setArray (Collection aCollection)
- {
- clear();
- addAll( aCollection );
- }
+ * Clears the current array and then populates it with the contents of the
+ * specified collection.
+ */
+ public void setArray(Collection aCollection) {
+ clear();
+ addAll(aCollection);
+ }
/**
- * Removes all objects equivalent to the specified object.
- */
- public void removeObject (Object anObject)
- {
- remove( anObject );
- }
+ * Removes all objects equivalent to the specified object.
+ */
+ public void removeObject(Object anObject) {
+ remove(anObject);
+ }
/**
- * Removes all occurences of the specified object,
- * comparing by reference.
- */
- public void removeIdenticalObject (Object anObject)
- {
- EOObserverCenter.removeObserver( observer, anObject );
- super.removeIdenticalObject( anObject );
- }
+ * Removes all occurences of the specified object, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject) {
+ EOObserverCenter.removeObserver(observer, anObject);
+ super.removeIdenticalObject(anObject);
+ }
/**
- * Inserts the specified object into this array at the
- * specified index.
- */
- public void insertObjectAtIndex (Object anObject, int anIndex)
- {
- add( anIndex, anObject );
- }
-
+ * Inserts the specified object into this array at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ add(anIndex, anObject);
+ }
+
/**
- * Replaces the object at the specified index with the
- * specified object.
- */
- public void replaceObjectAtIndex (int anIndex, Object anObject)
- {
- set( anIndex, anObject );
- }
+ * Replaces the object at the specified index with the specified object.
+ */
+ public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ set(anIndex, anObject);
+ }
/**
- * Adds the specified object to the end of this array.
- */
- public void addObject (Object anObject)
- {
- add( anObject );
- }
-
- // interface List: mutators
-
- public void add(int index, Object element)
- {
- EOObserverCenter.addObserver( observer, element );
- super.add( index, element );
- }
-
- public boolean add(Object o)
- {
- EOObserverCenter.addObserver( observer, o );
- return super.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll( index, c );
- }
-
- public void clear()
- {
- Iterator it = iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- super.clear();
- }
-
- public Object remove(int index)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- return super.remove( index );
- }
-
- public boolean remove(Object o)
- {
- EOObserverCenter.removeObserver( observer, o );
- return super.remove(o);
- }
-
- public boolean removeAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- return super.removeAll(coll);
- }
-
- public boolean retainAll(Collection coll)
- {
- throw new UnsupportedOperationException();
- }
-
- public Object set(int index, Object element)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- EOObserverCenter.addObserver( observer, element );
- return super.set( index, element );
- }
+ * Adds the specified object to the end of this array.
+ */
+ public void addObject(Object anObject) {
+ add(anObject);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ EOObserverCenter.addObserver(observer, element);
+ super.add(index, element);
+ }
+
+ public boolean add(Object o) {
+ EOObserverCenter.addObserver(observer, o);
+ return super.add(o);
+ }
+
+ public boolean addAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(index, c);
+ }
+
+ public void clear() {
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ super.clear();
+ }
+
+ public Object remove(int index) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ return super.remove(index);
+ }
+
+ public boolean remove(Object o) {
+ EOObserverCenter.removeObserver(observer, o);
+ return super.remove(o);
+ }
+
+ public boolean removeAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ return super.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object set(int index, Object element) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ EOObserverCenter.addObserver(observer, element);
+ return super.set(index, element);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2002/10/24 21:15:35 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.1 2002/10/24 21:15:35 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.1 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.1 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.1 2001/01/24 14:37:24 mpowers
- * Contributing a delegate useful for debugging.
+ * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for
+ * debugging.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/OrderedDataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/OrderedDataSource.java
index 8b88615..f91e76d 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/OrderedDataSource.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/OrderedDataSource.java
@@ -19,39 +19,31 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.control;
/**
-* A simple extension of EODataSource that
-* allows for indexed insertion. The wotonomy
-* implementation of EODisplayGroup supports
-* this and will use it if possible. This is
-* useful for classes like the PropertyDataSource,
-* where the ordering of items in an indexed
-* property may be important.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public abstract class OrderedDataSource extends EODataSource
-{
- /**
- * Inserts the specified object into this data source,
- * at the specified index.
- */
- public abstract void insertObjectAtIndex (
- Object anObject, int anIndex );
+ * A simple extension of EODataSource that allows for indexed insertion. The
+ * wotonomy implementation of EODisplayGroup supports this and will use it if
+ * possible. This is useful for classes like the PropertyDataSource, where the
+ * ordering of items in an indexed property may be important.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public abstract class OrderedDataSource extends EODataSource {
+ /**
+ * Inserts the specified object into this data source, at the specified index.
+ */
+ public abstract void insertObjectAtIndex(Object anObject, int anIndex);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2001/01/24 14:10:53 mpowers
- * Contributing OrderedDataSource, and PropertyDataSource extends it.
+ * Revision 1.1 2001/01/24 14:10:53 mpowers Contributing OrderedDataSource, and
+ * PropertyDataSource extends it.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java
index 76f7219..c02c3e2 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java
@@ -34,516 +34,413 @@ import net.wotonomy.foundation.internal.Introspector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* A data source that reads and writes to an indexed
-* property of a java object. This class is used by
-* MasterDetailAssociation to retreive objects from
-* the master display group.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 894 $
-*/
-public class PropertyDataSource extends OrderedDataSource
-{
- protected Object source;
- protected String key;
- protected Class lastKnownType; // for best-guessing
- protected EOClassDescription classDesc;
- protected EOEditingContext context;
-
- /**
- * Creates a new PropertyDataSource with no editing context
- * and will try to guess the appropriate class description
- * when trying to create objects.
- */
- public PropertyDataSource()
- {
- this( null, (EOClassDescription) null );
- }
-
- /**
- * Creates a new PropertyDataSource that uses the specified
- * editing context, but will try to guess the appropriate
- * class description when trying to create objects.
- */
- public PropertyDataSource( EOEditingContext aContext )
- {
- this( aContext, (EOClassDescription) null );
- }
-
- /**
- * Creates a new PropertyDataSource that uses the specified
- * editing context and vends objects of the specified class.
- */
- public PropertyDataSource(
- EOEditingContext aContext, Class aClass )
- {
- this( aContext, EOClassDescription.classDescriptionForClass( aClass ) );
- }
-
- /**
- * Creates a new PropertyDataSource that uses the specified
- * editing context and vends objects of the specified
- * class description.
- */
- public PropertyDataSource(
- EOEditingContext aContext, EOClassDescription aClassDesc )
- {
- source = null;
- key = null;
- lastKnownType = null;
- classDesc = aClassDesc;
- context = aContext;
- }
-
- /**
- * Provides the master object for detail display groups.
- */
- public Object source()
- {
- return source;
- }
-
- /**
- * Allows a detail display group to set the master object.
- */
- public void setSource( Object anObject )
- {
- source = anObject;
- }
-
- /**
- * Provides the detail key for detail display groups.
- */
- public String key()
- {
- return key;
- }
-
- /**
- * Allows a detail display group to set the detail key.
- */
- public void setKey( String aKey )
- {
- key = aKey;
- }
-
- /**
- * Inserts the specified object into this data source.
- * Calls insertObjectAtIndex and appends to the end
- * of the list.
- */
- public void insertObject ( Object anObject )
- {
- insertObjectAtIndex( anObject, -1 ); // trick to force to end
- }
-
- /**
- * Inserts the specified object into this data source,
- * at the specified index.
- */
- public void insertObjectAtIndex (
- Object anObject, int anIndex )
- {
- if ( source == null ) return;
- List list = readAsList();
- if ( anIndex == -1 ) anIndex = list.size(); // force to end
- if ( anIndex > list.size() ) anIndex = list.size(); // force to end
- list.add( anIndex, anObject );
- writeAsList( list );
- }
-
- /**
- * Deletes the specified object from this data source.
- */
- public void deleteObject ( Object anObject )
- {
- if ( source == null ) return;
- List list = readAsList();
- list.remove( anObject );
- writeAsList( list );
- }
-
- public EOEditingContext editingContext ()
- {
- return context;
- }
-
- /**
- * Returns a List containing the objects in this
- * data source.
- */
- public NSArray fetchObjects ()
- {
- if ( source == null ) return NSArray.EmptyArray;
- return readAsList();
- }
-
- /**
- * Returns a new instance of this class.
- */
- public EODataSource
- dataSourceQualifiedByKey ( String aKey )
- {
- // determine the target class desc if possible
- EOClassDescription keyClassDesc = null;
- if ( classDesc != null )
- {
- keyClassDesc = classDesc.classDescriptionForDestinationKey( aKey );
- }
- return new PropertyDataSource( editingContext(), keyClassDesc );
- }
-
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- */
- public void
- qualifyWithRelationshipKey (
- String aKey, Object anObject )
- {
- source = anObject;
- key = aKey;
- }
-
- /**
- * Returns the class description passed to the
- * constructor, if any. If no class description and
- * if the bound property is an indexed property,
- * the type of the array is returned, otherwise
- * this method returns null. This method is called
- * by createObject().
- */
- public EOClassDescription
- classDescriptionForObjects ()
- {
- // just return the class description if we have one
- if ( classDesc != null ) return classDesc;
-
- // otherwise, try to do some guesswork
- EOClassDescription result = null;
-
- // lastKnownType is not updated here
- Class type = lastKnownType;
-
- // if no last known type
- if ( type == null )
- {
- // if source and key were specified
- if ( ( source != null ) && ( key != null ) )
- {
- // try to get an array type
- Method m = Introspector.getPropertyReadMethod(
- source.getClass(), key, new Class[0] );
- if ( m != null )
- {
- Class returnType = m.getReturnType();
- if ( returnType.isArray() )
- {
- type = returnType.getComponentType();
- }
- }
- else
- {
- throw new WotonomyException( "Key does not exist for object: " + key + " : " + source );
- }
- }
-
- // does not update lastKnownType because
- // we prefer to get that info from a fetch.
- }
-
- // if type has been determined
- if ( type != null )
- {
- result =
- EOClassDescription.classDescriptionForClass( type );
- }
-
- return result;
- }
-
- /**
- * Calls getValue() and returns the result as a List.
- * Sets lastKnownType to the retrieved type.
- */
- protected NSMutableArray readAsList()
- {
- Object value = getValue();
- if ( value == null )
- {
- return new NSMutableArray();
- }
-
- Object o;
- NSMutableArray result = new NSMutableArray();
- boolean hasReadType = false;
- lastKnownType = null;
-
- // if instance of array, convert to list
- if ( value.getClass().isArray() )
- {
- int count = Array.getLength( value );
- for ( int i = 0; i < count; i++ )
- {
- o = Array.get( value, i );
- if ( o != null )
- {
- // we've already found a type
- if ( hasReadType )
- {
- // check that this matches the last known type
- if ( o.getClass() != lastKnownType )
- {
- // not all of the same type: set to null
- lastKnownType = null;
- }
- }
- else // this is the first type we've found
- {
- // remember it
- hasReadType = true;
- lastKnownType = o.getClass();
- }
- }
- result.add( o );
+ * A data source that reads and writes to an indexed property of a java object.
+ * This class is used by MasterDetailAssociation to retreive objects from the
+ * master display group.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 894 $
+ */
+public class PropertyDataSource extends OrderedDataSource {
+ protected Object source;
+ protected String key;
+ protected Class lastKnownType; // for best-guessing
+ protected EOClassDescription classDesc;
+ protected EOEditingContext context;
+
+ /**
+ * Creates a new PropertyDataSource with no editing context and will try to
+ * guess the appropriate class description when trying to create objects.
+ */
+ public PropertyDataSource() {
+ this(null, (EOClassDescription) null);
+ }
+
+ /**
+ * Creates a new PropertyDataSource that uses the specified editing context, but
+ * will try to guess the appropriate class description when trying to create
+ * objects.
+ */
+ public PropertyDataSource(EOEditingContext aContext) {
+ this(aContext, (EOClassDescription) null);
+ }
+
+ /**
+ * Creates a new PropertyDataSource that uses the specified editing context and
+ * vends objects of the specified class.
+ */
+ public PropertyDataSource(EOEditingContext aContext, Class aClass) {
+ this(aContext, EOClassDescription.classDescriptionForClass(aClass));
+ }
+
+ /**
+ * Creates a new PropertyDataSource that uses the specified editing context and
+ * vends objects of the specified class description.
+ */
+ public PropertyDataSource(EOEditingContext aContext, EOClassDescription aClassDesc) {
+ source = null;
+ key = null;
+ lastKnownType = null;
+ classDesc = aClassDesc;
+ context = aContext;
+ }
+
+ /**
+ * Provides the master object for detail display groups.
+ */
+ public Object source() {
+ return source;
+ }
+
+ /**
+ * Allows a detail display group to set the master object.
+ */
+ public void setSource(Object anObject) {
+ source = anObject;
+ }
+
+ /**
+ * Provides the detail key for detail display groups.
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Allows a detail display group to set the detail key.
+ */
+ public void setKey(String aKey) {
+ key = aKey;
+ }
+
+ /**
+ * Inserts the specified object into this data source. Calls insertObjectAtIndex
+ * and appends to the end of the list.
+ */
+ public void insertObject(Object anObject) {
+ insertObjectAtIndex(anObject, -1); // trick to force to end
+ }
+
+ /**
+ * Inserts the specified object into this data source, at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ if (source == null)
+ return;
+ List list = readAsList();
+ if (anIndex == -1)
+ anIndex = list.size(); // force to end
+ if (anIndex > list.size())
+ anIndex = list.size(); // force to end
+ list.add(anIndex, anObject);
+ writeAsList(list);
+ }
+
+ /**
+ * Deletes the specified object from this data source.
+ */
+ public void deleteObject(Object anObject) {
+ if (source == null)
+ return;
+ List list = readAsList();
+ list.remove(anObject);
+ writeAsList(list);
+ }
+
+ public EOEditingContext editingContext() {
+ return context;
+ }
+
+ /**
+ * Returns a List containing the objects in this data source.
+ */
+ public NSArray fetchObjects() {
+ if (source == null)
+ return NSArray.EmptyArray;
+ return readAsList();
+ }
+
+ /**
+ * Returns a new instance of this class.
+ */
+ public EODataSource dataSourceQualifiedByKey(String aKey) {
+ // determine the target class desc if possible
+ EOClassDescription keyClassDesc = null;
+ if (classDesc != null) {
+ keyClassDesc = classDesc.classDescriptionForDestinationKey(aKey);
+ }
+ return new PropertyDataSource(editingContext(), keyClassDesc);
+ }
+
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object.
+ */
+ public void qualifyWithRelationshipKey(String aKey, Object anObject) {
+ source = anObject;
+ key = aKey;
+ }
+
+ /**
+ * Returns the class description passed to the constructor, if any. If no class
+ * description and if the bound property is an indexed property, the type of the
+ * array is returned, otherwise this method returns null. This method is called
+ * by createObject().
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ // just return the class description if we have one
+ if (classDesc != null)
+ return classDesc;
+
+ // otherwise, try to do some guesswork
+ EOClassDescription result = null;
+
+ // lastKnownType is not updated here
+ Class type = lastKnownType;
+
+ // if no last known type
+ if (type == null) {
+ // if source and key were specified
+ if ((source != null) && (key != null)) {
+ // try to get an array type
+ Method m = Introspector.getPropertyReadMethod(source.getClass(), key, new Class[0]);
+ if (m != null) {
+ Class returnType = m.getReturnType();
+ if (returnType.isArray()) {
+ type = returnType.getComponentType();
+ }
+ } else {
+ throw new WotonomyException("Key does not exist for object: " + key + " : " + source);
+ }
}
+
+ // does not update lastKnownType because
+ // we prefer to get that info from a fetch.
}
- else
- if ( value instanceof Collection )
- {
+
+ // if type has been determined
+ if (type != null) {
+ result = EOClassDescription.classDescriptionForClass(type);
+ }
+
+ return result;
+ }
+
+ /**
+ * Calls getValue() and returns the result as a List. Sets lastKnownType to the
+ * retrieved type.
+ */
+ protected NSMutableArray readAsList() {
+ Object value = getValue();
+ if (value == null) {
+ return new NSMutableArray();
+ }
+
+ Object o;
+ NSMutableArray result = new NSMutableArray();
+ boolean hasReadType = false;
+ lastKnownType = null;
+
+ // if instance of array, convert to list
+ if (value.getClass().isArray()) {
+ int count = Array.getLength(value);
+ for (int i = 0; i < count; i++) {
+ o = Array.get(value, i);
+ if (o != null) {
+ // we've already found a type
+ if (hasReadType) {
+ // check that this matches the last known type
+ if (o.getClass() != lastKnownType) {
+ // not all of the same type: set to null
+ lastKnownType = null;
+ }
+ } else // this is the first type we've found
+ {
+ // remember it
+ hasReadType = true;
+ lastKnownType = o.getClass();
+ }
+ }
+ result.add(o);
+ }
+ } else if (value instanceof Collection) {
// convert to list so we handle sets, etc.
- Iterator i = ((Collection)value).iterator();
- while ( i.hasNext() )
- {
- o = i.next();
- if ( o != null )
- {
- // we've already found a type
- if ( hasReadType )
- {
- // check that this matches the last known type
- if ( o.getClass() != lastKnownType )
- {
- // not all of the same type: set to null
- lastKnownType = null;
- }
- }
- else // this is the first type we've found
- {
- // remember it
- hasReadType = true;
- lastKnownType = o.getClass();
- }
- }
- result.add( o );
- }
+ Iterator i = ((Collection) value).iterator();
+ while (i.hasNext()) {
+ o = i.next();
+ if (o != null) {
+ // we've already found a type
+ if (hasReadType) {
+ // check that this matches the last known type
+ if (o.getClass() != lastKnownType) {
+ // not all of the same type: set to null
+ lastKnownType = null;
+ }
+ } else // this is the first type we've found
+ {
+ // remember it
+ hasReadType = true;
+ lastKnownType = o.getClass();
+ }
+ }
+ result.add(o);
+ }
+ } else {
+ lastKnownType = null;
+ throw new WotonomyException("PropertyDataSource: " + "bound property was not an indexed property: " + key);
}
- else
- {
- lastKnownType = null;
- throw new WotonomyException( "PropertyDataSource: " +
- "bound property was not an indexed property: " + key );
+
+ return result;
+ }
+
+ /**
+ * Converts the specified List to lastKnownType and calls setValue().
+ */
+ protected void writeAsList(List anObjectList) {
+ if (source == null) {
+ throw new WotonomyException("PropertyDataSource: " + "no source object: " + key);
+ }
+
+ Class c = source.getClass();
+ Method m = Introspector.getPropertyReadMethod(c, key, new Class[0]);
+ if (m == null) {
+ throw new WotonomyException("Could not read property for object: " + key + " : " + source + " (" + c + ")");
}
- return result;
- }
-
- /**
- * Converts the specified List to lastKnownType
- * and calls setValue().
- */
- protected void writeAsList( List anObjectList )
- {
- if ( source == null )
- {
- throw new WotonomyException( "PropertyDataSource: " +
- "no source object: " + key );
- }
-
- Class c = source.getClass();
- Method m = Introspector.getPropertyReadMethod( c, key, new Class[0] );
- if ( m == null )
- {
- throw new WotonomyException( "Could not read property for object: "
- + key + " : " + source + " (" + c + ")" );
- }
-
- Class returnType = m.getReturnType();
-
- int count = anObjectList.size();
- Object result = null;
-
- if ( returnType.isArray() )
- {
- Class type = returnType.getComponentType();
- result = Array.newInstance( type, count );
- for ( int i = 0; i < count; i++ )
- {
- Array.set( result, i, anObjectList.get( i ) );
- }
- }
- else
- {
- Collection collection = null;
-
- if ( ! returnType.isInterface() )
- {
- try
- {
- collection = (Collection) returnType.newInstance();
- }
- catch ( Exception exc )
- {
- // no default constructor, leave null
- }
- }
-
- // try to find an acceptable collections type
- if ( collection == null )
- {
- if ( returnType.isAssignableFrom( NSMutableArray.class ) )
- {
- collection = new NSMutableArray();
- }
- else
- if ( returnType.isAssignableFrom( LinkedList.class ) )
- {
- collection = new LinkedList();
- }
- else
- if ( returnType.isAssignableFrom( ArrayList.class ) )
- {
- collection = new ArrayList();
- }
- else
- if ( returnType.isAssignableFrom( HashSet.class ) )
- {
- collection = new HashSet();
- }
- else
- if ( returnType.isAssignableFrom( TreeSet.class ) )
- {
- collection = new TreeSet();
- }
- }
-
- if ( collection == null )
- {
- throw new WotonomyException( "Could not create a collection of type: " + returnType );
- }
-
- collection.addAll( anObjectList );
- result = collection;
- }
-
- setValue( result );
- }
-
- /**
- * Returns the value of the indexed property
- * specified by qualifyWithRelationshipKey.
- */
- protected Object getValue()
- {
- if ( source instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)source).valueForKey( key );
- }
- return EOKeyValueCodingSupport.valueForKey( source, key );
- }
-
- /**
- * Sets the value of the indexed property
- * specified by qualifyWithRelationshipKey.
- * The argument is assumed to be of appropriate
- * type for the property. EOObserverCenter is
- * notified that the object will change.
- */
- protected void setValue( Object aValue )
- {
- EOClassDescription sourceDesc =
- EOClassDescription.classDescriptionForClass( source.getClass() );
-
-
- // if we're not editing a relationship (?)
+ Class returnType = m.getReturnType();
+
+ int count = anObjectList.size();
+ Object result = null;
+
+ if (returnType.isArray()) {
+ Class type = returnType.getComponentType();
+ result = Array.newInstance(type, count);
+ for (int i = 0; i < count; i++) {
+ Array.set(result, i, anObjectList.get(i));
+ }
+ } else {
+ Collection collection = null;
+
+ if (!returnType.isInterface()) {
+ try {
+ collection = (Collection) returnType.newInstance();
+ } catch (Exception exc) {
+ // no default constructor, leave null
+ }
+ }
+
+ // try to find an acceptable collections type
+ if (collection == null) {
+ if (returnType.isAssignableFrom(NSMutableArray.class)) {
+ collection = new NSMutableArray();
+ } else if (returnType.isAssignableFrom(LinkedList.class)) {
+ collection = new LinkedList();
+ } else if (returnType.isAssignableFrom(ArrayList.class)) {
+ collection = new ArrayList();
+ } else if (returnType.isAssignableFrom(HashSet.class)) {
+ collection = new HashSet();
+ } else if (returnType.isAssignableFrom(TreeSet.class)) {
+ collection = new TreeSet();
+ }
+ }
+
+ if (collection == null) {
+ throw new WotonomyException("Could not create a collection of type: " + returnType);
+ }
+
+ collection.addAll(anObjectList);
+ result = collection;
+ }
+
+ setValue(result);
+ }
+
+ /**
+ * Returns the value of the indexed property specified by
+ * qualifyWithRelationshipKey.
+ */
+ protected Object getValue() {
+ if (source instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) source).valueForKey(key);
+ }
+ return EOKeyValueCodingSupport.valueForKey(source, key);
+ }
+
+ /**
+ * Sets the value of the indexed property specified by
+ * qualifyWithRelationshipKey. The argument is assumed to be of appropriate type
+ * for the property. EOObserverCenter is notified that the object will change.
+ */
+ protected void setValue(Object aValue) {
+ EOClassDescription sourceDesc = EOClassDescription.classDescriptionForClass(source.getClass());
+
+ // if we're not editing a relationship (?)
// if ( ! sourceDesc.toManyRelationshipKeys().containsObject( key ) )
- {
- // mark the parent as changed
- EOObserverCenter.notifyObserversObjectWillChange( source );
- }
-
-
- if ( source instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)source).takeValueForKey( aValue, key );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( source, aValue, key );
- }
- }
-
+ {
+ // mark the parent as changed
+ EOObserverCenter.notifyObserversObjectWillChange(source);
+ }
+
+ if (source instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) source).takeValueForKey(aValue, key);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(source, aValue, key);
+ }
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/16 16:47:14 cgruber
- * Move some classes in to "internal" packages and re-work imports, etc.
+ * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to
+ * "internal" packages and re-work imports, etc.
*
- * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ * Also use UnsupportedOperationExceptions where appropriate, instead of
+ * WotonomyExceptions.
*
- * Revision 1.1 2006/02/16 13:19:57 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.14 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.14 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.13 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.13 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.12 2002/10/24 18:18:12 mpowers
- * NSArray's are now considered read-only, so we can return our internal
- * representation to reduce unnecessary object allocation.
+ * Revision 1.12 2002/10/24 18:18:12 mpowers NSArray's are now considered
+ * read-only, so we can return our internal representation to reduce unnecessary
+ * object allocation.
*
- * Revision 1.11 2002/04/15 21:55:33 mpowers
- * Catching a condition where the get may not return the value passed to set.
+ * Revision 1.11 2002/04/15 21:55:33 mpowers Catching a condition where the get
+ * may not return the value passed to set.
*
- * Revision 1.10 2002/03/08 23:20:37 mpowers
- * insertObject now calls insertObjectAtIndex.
+ * Revision 1.10 2002/03/08 23:20:37 mpowers insertObject now calls
+ * insertObjectAtIndex.
*
- * Revision 1.9 2001/06/05 19:10:41 mpowers
- * Better handling of null properties.
+ * Revision 1.9 2001/06/05 19:10:41 mpowers Better handling of null properties.
*
- * Revision 1.8 2001/05/21 14:03:35 mpowers
- * Added a convenience constructor for java classes.
+ * Revision 1.8 2001/05/21 14:03:35 mpowers Added a convenience constructor for
+ * java classes.
*
- * Revision 1.7 2001/04/30 13:15:24 mpowers
- * Child contexts re-initializing objects invalidated in parent now
- * propery transpose relationships.
+ * Revision 1.7 2001/04/30 13:15:24 mpowers Child contexts re-initializing
+ * objects invalidated in parent now propery transpose relationships.
*
- * Revision 1.6 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
+ * Revision 1.6 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
*
- * Revision 1.5 2001/04/28 22:17:51 mpowers
- * Revised PropertyDataSource to be EOClassDescription-aware.
+ * Revision 1.5 2001/04/28 22:17:51 mpowers Revised PropertyDataSource to be
+ * EOClassDescription-aware.
*
- * Revision 1.4 2001/04/27 23:37:20 mpowers
- * Now using EOClassDescription in the EODataSource class, as we should.
+ * Revision 1.4 2001/04/27 23:37:20 mpowers Now using EOClassDescription in the
+ * EODataSource class, as we should.
*
- * Revision 1.3 2001/03/29 03:29:49 mpowers
- * Now using KeyValueCoding and Support instead of Introspector.
+ * Revision 1.3 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support
+ * instead of Introspector.
*
- * Revision 1.2 2001/01/24 14:10:53 mpowers
- * Contributing OrderedDataSource, and PropertyDataSource extends it.
+ * Revision 1.2 2001/01/24 14:10:53 mpowers Contributing OrderedDataSource, and
+ * PropertyDataSource extends it.
*
- * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:35 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:35 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/internal/Surrogate.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/internal/Surrogate.java
index e12fda0..e0fe1eb 100644
--- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/internal/Surrogate.java
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/internal/Surrogate.java
@@ -23,237 +23,202 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.internal.Introspector;
/**
-* A Surrogate is a special object that can be used in a display
-* group when you wish to emulate other objects or modify their
-* behaviors. Because it is a Map, it makes use of Introspector's
-* ability to treat keys in a map as if they were properties to
-* implement the following features.
-* <ul>
-* <li>By default, Surrogate works like a Map, and reading and
-* writing properties to a Surrogate gets and puts values in the
-* Map.</li>
-* <li>If one or more delegate objects are specified, property keys
-* that do not exist in the map are read from and written to the
-* delegate object.</li>
-* <li>If a default value is specified, that value will be returned
-* for all property reads that do not exist in the map or in the
-* delegate object. (Subsequent writes to those properties will
-* create a key in the map and then subsequent reads will read not
-* read the default object.)</li>
-* <li>Subclasses can override the get(Object) method to further
-* customize the behavior of a Surrogate.
-* </ul>
-*
-* @author michael@mpowers.net
-* @date $Date: 2006-02-18 17:46:44 -0500 (Sat, 18 Feb 2006) $
-* @revision $Revision: 900 $
-*/
-public class Surrogate extends NSMutableDictionary
-{
+ * A Surrogate is a special object that can be used in a display group when you
+ * wish to emulate other objects or modify their behaviors. Because it is a Map,
+ * it makes use of Introspector's ability to treat keys in a map as if they were
+ * properties to implement the following features.
+ * <ul>
+ * <li>By default, Surrogate works like a Map, and reading and writing
+ * properties to a Surrogate gets and puts values in the Map.</li>
+ * <li>If one or more delegate objects are specified, property keys that do not
+ * exist in the map are read from and written to the delegate object.</li>
+ * <li>If a default value is specified, that value will be returned for all
+ * property reads that do not exist in the map or in the delegate object.
+ * (Subsequent writes to those properties will create a key in the map and then
+ * subsequent reads will read not read the default object.)</li>
+ * <li>Subclasses can override the get(Object) method to further customize the
+ * behavior of a Surrogate.
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @date $Date: 2006-02-18 17:46:44 -0500 (Sat, 18 Feb 2006) $
+ * @revision $Revision: 900 $
+ */
+public class Surrogate extends NSMutableDictionary {
protected Object[] delegates;
protected Object defaultValue;
-
+
/**
- * Default constructor with no delegate object and no default value.
- */
- public Surrogate()
- {
+ * Default constructor with no delegate object and no default value.
+ */
+ public Surrogate() {
delegates = null;
defaultValue = null;
}
-
+
/**
- * Constructor specifying a delegate object.
- */
- public Surrogate( Object[] aDelegateArray )
- {
- setDelegates( aDelegateArray );
+ * Constructor specifying a delegate object.
+ */
+ public Surrogate(Object[] aDelegateArray) {
+ setDelegates(aDelegateArray);
}
/**
- * Constructor specifying a default value.
- */
- public Surrogate( Object aDefault )
- {
- setDefaultValue( aDefault );
+ * Constructor specifying a default value.
+ */
+ public Surrogate(Object aDefault) {
+ setDefaultValue(aDefault);
}
/**
- * Constructor specifying a delegate object and a default value.
- */
- public Surrogate( Object[] aDelegateArray, Object aDefault )
- {
- setDelegates( aDelegateArray );
- setDefaultValue( aDefault );
+ * Constructor specifying a delegate object and a default value.
+ */
+ public Surrogate(Object[] aDelegateArray, Object aDefault) {
+ setDelegates(aDelegateArray);
+ setDefaultValue(aDefault);
}
/**
- * Returns the first delegate object, or null if no delegates exist.
- */
- public Object getDelegate()
- {
- if ( delegates == null ) return null;
- if ( delegates.length == 0 ) return null;
+ * Returns the first delegate object, or null if no delegates exist.
+ */
+ public Object getDelegate() {
+ if (delegates == null)
+ return null;
+ if (delegates.length == 0)
+ return null;
return delegates[0];
}
-
+
/**
- * Sets the delegate object list to contain only the
- * specified object.
- */
- public void setDelegate( Object aDelegate )
- {
- setDelegates( new Object[] { aDelegate } );
+ * Sets the delegate object list to contain only the specified object.
+ */
+ public void setDelegate(Object aDelegate) {
+ setDelegates(new Object[] { aDelegate });
}
-
+
/**
- * Returns the list of delegates in the order in which
- * they are consulted.
- */
- public Object[] getDelegates()
- {
- if ( delegates == null ) delegates = new Object[0];
- return delegates;
+ * Returns the list of delegates in the order in which they are consulted.
+ */
+ public Object[] getDelegates() {
+ if (delegates == null)
+ delegates = new Object[0];
+ return delegates;
}
-
+
/**
- * Sets the list of delegates in the order in which they
- * will be consulted.
- */
- public void setDelegates( Object[] aDelegateArray )
- {
+ * Sets the list of delegates in the order in which they will be consulted.
+ */
+ public void setDelegates(Object[] aDelegateArray) {
delegates = aDelegateArray;
}
/**
- * Returns the current default value, or null if no default exists.
- */
- public Object getDefaultValue()
- {
+ * Returns the current default value, or null if no default exists.
+ */
+ public Object getDefaultValue() {
return defaultValue;
}
-
+
/**
- * Sets the default value.
- */
- public void setDefaultValue( Object aDefault )
- {
+ * Sets the default value.
+ */
+ public void setDefaultValue(Object aDefault) {
defaultValue = aDefault;
}
-
+
/**
- * Called by get to retrieve a value from the internal map.
- * This implementation simply calls super.get().
- */
- public Object directGet( Object aKey )
- {
- return super.get( aKey );
+ * Called by get to retrieve a value from the internal map. This implementation
+ * simply calls super.get().
+ */
+ public Object directGet(Object aKey) {
+ return super.get(aKey);
}
-
+
/**
- * Called by put to retrieve a value from the internal map.
- * This implementation simply calls super.put().
- */
- public Object directPut( Object aKey, Object aValue )
- {
- return super.put( aKey, aValue );
+ * Called by put to retrieve a value from the internal map. This implementation
+ * simply calls super.put().
+ */
+ public Object directPut(Object aKey, Object aValue) {
+ return super.put(aKey, aValue);
}
-
+
/**
- * Overridden to consult each delegate before
- * checking the internal list of keys. No matching
- * key is found, returns the default object, or
- * null if no default object exists.
- */
- public Object get( Object aKey )
- {
+ * Overridden to consult each delegate before checking the internal list of
+ * keys. No matching key is found, returns the default object, or null if no
+ * default object exists.
+ */
+ public Object get(Object aKey) {
// check all delegates in order
int i, j;
Object[] list = getDelegates();
String[] properties;
- for ( i = 0; i < list.length; i++ )
- {
+ for (i = 0; i < list.length; i++) {
// for each delegate
- properties =
- Introspector.getReadPropertiesForObject( list[i] );
- for ( j = 0; j < properties.length; j++ )
- {
+ properties = Introspector.getReadPropertiesForObject(list[i]);
+ for (j = 0; j < properties.length; j++) {
// if delegate has property
- if ( properties[j].equals( aKey ) )
- {
+ if (properties[j].equals(aKey)) {
// use this delegate
- return Introspector.get( list[i], aKey.toString() );
+ return Introspector.get(list[i], aKey.toString());
}
}
}
-
+
// return from internal map
- Object result = directGet( aKey );
- if ( result == null )
- {
+ Object result = directGet(aKey);
+ if (result == null) {
// if not in map, return default object
result = getDefaultValue();
}
- return result;
+ return result;
}
-
- /**
- * Overridden to attempt to write each delegate, writing to
- * only the first successful delegate, before storing the
- * value in the internal map.
- */
- public Object put( Object aKey, Object aValue )
- {
+
+ /**
+ * Overridden to attempt to write each delegate, writing to only the first
+ * successful delegate, before storing the value in the internal map.
+ */
+ public Object put(Object aKey, Object aValue) {
// check all delegates in order
int i, j;
Object[] list = getDelegates();
String[] properties;
- for ( i = 0; i < list.length; i++ )
- {
+ for (i = 0; i < list.length; i++) {
// for each delegate
- properties =
- Introspector.getWritePropertiesForObject( list[i] );
- for ( j = 0; j < properties.length; j++ )
- {
+ properties = Introspector.getWritePropertiesForObject(list[i]);
+ for (j = 0; j < properties.length; j++) {
// if delegate has property
- if ( properties[j].equals( aKey ) )
- {
+ if (properties[j].equals(aKey)) {
// use this delegate
- EOObserverCenter.notifyObserversObjectWillChange( list[i] );
- return Introspector.set( list[i], aKey.toString(), aValue );
+ EOObserverCenter.notifyObserversObjectWillChange(list[i]);
+ return Introspector.set(list[i], aKey.toString(), aValue);
}
}
}
-
+
// set on internal map
- EOObserverCenter.notifyObserversObjectWillChange( this );
- return directPut( aKey, aValue );
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ return directPut(aKey, aValue);
}
/**
- * Overridden to compare by reference.
- */
- public boolean equals( Object anObject )
- {
- return ( this == anObject );
+ * Overridden to compare by reference.
+ */
+ public boolean equals(Object anObject) {
+ return (this == anObject);
}
}
/*
- * $Log$
- * Revision 1.1 2006/02/18 22:46:44 cgruber
- * Add Surrogate map from .util into control's internal package, and fix imports.
+ * $Log$ Revision 1.1 2006/02/18 22:46:44 cgruber Add Surrogate map from .util
+ * into control's internal package, and fix imports.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:52:21 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:21 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingController.java
index be83eb4..c7f9c9b 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingController.java
@@ -9,27 +9,25 @@ import net.wotonomy.ui.swing.TreeAssociation;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* A simple editor panel with a few textfields.
-*/
-public class BindingController
-{
- public BindingController( EODisplayGroup titlesGroup, EODisplayGroup childGroup )
- {
+ * A simple editor panel with a few textfields.
+ */
+public class BindingController {
+ public BindingController(EODisplayGroup titlesGroup, EODisplayGroup childGroup) {
BindingPanel bindingPanel = new BindingPanel();
-
+
EOAssociation ta;
- ta = new TreeAssociation( bindingPanel.treeChooser, "People" );
- ta.bindAspect( EOAssociation.TitlesAspect, titlesGroup, "lastName" );
- ta.bindAspect( EOAssociation.ChildrenAspect, childGroup, "children" );
- ta.bindAspect( EOAssociation.IsLeafAspect, titlesGroup, "childCount" );
+ ta = new TreeAssociation(bindingPanel.treeChooser, "People");
+ ta.bindAspect(EOAssociation.TitlesAspect, titlesGroup, "lastName");
+ ta.bindAspect(EOAssociation.ChildrenAspect, childGroup, "children");
+ ta.bindAspect(EOAssociation.IsLeafAspect, titlesGroup, "childCount");
ta.establishConnection();
-
+
JDialog d = new JDialog();
- d.getContentPane().add( bindingPanel );
- d.setTitle( "Chooser Panel" );
+ d.getContentPane().add(bindingPanel);
+ d.setTitle("Chooser Panel");
d.pack();
- WindowUtilities.cascade( d );
+ WindowUtilities.cascade(d);
d.show();
}
-
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingPanel.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingPanel.java
index 624dc37..68740b4 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingPanel.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/BindingPanel.java
@@ -12,161 +12,122 @@ import net.wotonomy.ui.swing.components.ButtonPanel;
import net.wotonomy.ui.swing.components.TreeChooser;
/**
-* BindingPanel is a FileChooser-like panel that
-* uses a TreeModel as a data source. It basically
-* provides an alternative to JTree for rendering
-* and manipulating tree-like data.
-*/
-public class BindingPanel extends JPanel
-{
+ * BindingPanel is a FileChooser-like panel that uses a TreeModel as a data
+ * source. It basically provides an alternative to JTree for rendering and
+ * manipulating tree-like data.
+ */
+public class BindingPanel extends JPanel {
protected TreeChooser treeChooser;
protected ButtonPanel okPanel;
-
- public BindingPanel()
- {
+
+ public BindingPanel() {
init();
}
-
- protected void init()
- {
- this.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
- this.setLayout( new BorderLayout( 10, 10 ) );
-
- this.add( treeChooser = new TreeChooser(), BorderLayout.CENTER );
-
- okPanel = new ButtonPanel( new String[] { "OK", "Cancel" } );
- this.add( okPanel, BorderLayout.SOUTH );
+
+ protected void init() {
+ this.setBorder(new EmptyBorder(10, 10, 10, 10));
+ this.setLayout(new BorderLayout(10, 10));
+
+ this.add(treeChooser = new TreeChooser(), BorderLayout.CENTER);
+
+ okPanel = new ButtonPanel(new String[] { "OK", "Cancel" });
+ this.add(okPanel, BorderLayout.SOUTH);
}
-
- /**
- * Creates a new folder.
- */
- protected class NewFolderAction extends AbstractAction
- {
- protected NewFolderAction()
- {
- super("New Folder", UIManager.getIcon("FileChooser.newFolderIcon") );
- }
- public void actionPerformed(ActionEvent e)
- {
- }
- }
-
- /**
- * Acts on the "home" key event or equivalent event.
- */
- protected class GoHomeAction extends AbstractAction
- {
- protected GoHomeAction()
- {
- super("Go Home", UIManager.getIcon("FileChooser.homeFolderIcon") );
- }
- public void actionPerformed(ActionEvent e)
- {
- }
- }
- protected class ChangeToParentDirectoryAction extends AbstractAction
- {
- protected ChangeToParentDirectoryAction()
- {
- super("Go Up", UIManager.getIcon("FileChooser.upFolderIcon") );
+ /**
+ * Creates a new folder.
+ */
+ protected class NewFolderAction extends AbstractAction {
+ protected NewFolderAction() {
+ super("New Folder", UIManager.getIcon("FileChooser.newFolderIcon"));
}
- public void actionPerformed(ActionEvent e)
- {
+
+ public void actionPerformed(ActionEvent e) {
}
}
- /**
- * Responds to an Open or Save request
- */
- protected class ApproveSelectionAction extends AbstractAction {
- public void actionPerformed(ActionEvent e)
- {
+ /**
+ * Acts on the "home" key event or equivalent event.
+ */
+ protected class GoHomeAction extends AbstractAction {
+ protected GoHomeAction() {
+ super("Go Home", UIManager.getIcon("FileChooser.homeFolderIcon"));
}
- }
-
- /**
- * Responds to a cancel request.
- */
- protected class CancelSelectionAction extends AbstractAction {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
}
- }
-
- /**
- * Rescans the files in the current directory
- */
- protected class UpdateAction extends AbstractAction {
- public void actionPerformed(ActionEvent e)
- {
+ }
+
+ protected class ChangeToParentDirectoryAction extends AbstractAction {
+ protected ChangeToParentDirectoryAction() {
+ super("Go Up", UIManager.getIcon("FileChooser.upFolderIcon"));
}
- }
-
- //
- // Renderer for DirectoryComboBox
- //
-/*
- class DirectoryComboBoxRenderer extends DefaultListCellRenderer {
- IndentIcon ii = new IndentIcon();
- public Component getListCellRendererComponent(JList list, Object value,
- int index, boolean isSelected,
- boolean cellHasFocus) {
-
- super.getListCellRendererComponent(list, value, index,
- isSelected, cellHasFocus);
- File directory = (File) value;
- if(directory == null) {
- setText("");
- return this;
- }
-
- String fileName = getFileChooser().getName(directory);
- setText(fileName);
-
- // Find the depth of the directory
- int depth = 0;
- if(index != -1) {
- File f = directory;
- while(f.getParent() != null) {
- depth++;
- f = getFileChooser().getFileSystemView().createFileObject(
- f.getParent()
- );
- }
- }
-
- Icon icon = getFileChooser().getIcon(directory);
-
- ii.icon = icon;
- ii.depth = depth;
-
- setIcon(ii);
-
- return this;
+
+ public void actionPerformed(ActionEvent e) {
}
- }
-
- final static int space = 10;
- class IndentIcon implements Icon {
-
- Icon icon = null;
- int depth = 0;
-
- public void paintIcon(Component c, Graphics g, int x, int y) {
- icon.paintIcon(c, g, x+depth*space, y);
+ }
+
+ /**
+ * Responds to an Open or Save request
+ */
+ protected class ApproveSelectionAction extends AbstractAction {
+ public void actionPerformed(ActionEvent e) {
}
-
- public int getIconWidth() {
- return icon.getIconWidth() + depth*space;
+ }
+
+ /**
+ * Responds to a cancel request.
+ */
+ protected class CancelSelectionAction extends AbstractAction {
+ public void actionPerformed(ActionEvent e) {
}
-
- public int getIconHeight() {
- return icon.getIconHeight();
+ }
+
+ /**
+ * Rescans the files in the current directory
+ */
+ protected class UpdateAction extends AbstractAction {
+ public void actionPerformed(ActionEvent e) {
}
-
- }
-*/
+ }
+
+ //
+ // Renderer for DirectoryComboBox
+ //
+ /*
+ * class DirectoryComboBoxRenderer extends DefaultListCellRenderer { IndentIcon
+ * ii = new IndentIcon(); public Component getListCellRendererComponent(JList
+ * list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ *
+ * super.getListCellRendererComponent(list, value, index, isSelected,
+ * cellHasFocus); File directory = (File) value; if(directory == null) {
+ * setText(""); return this; }
+ *
+ * String fileName = getFileChooser().getName(directory); setText(fileName);
+ *
+ * // Find the depth of the directory int depth = 0; if(index != -1) { File f =
+ * directory; while(f.getParent() != null) { depth++; f =
+ * getFileChooser().getFileSystemView().createFileObject( f.getParent() ); } }
+ *
+ * Icon icon = getFileChooser().getIcon(directory);
+ *
+ * ii.icon = icon; ii.depth = depth;
+ *
+ * setIcon(ii);
+ *
+ * return this; } }
+ *
+ * final static int space = 10; class IndentIcon implements Icon {
+ *
+ * Icon icon = null; int depth = 0;
+ *
+ * public void paintIcon(Component c, Graphics g, int x, int y) {
+ * icon.paintIcon(c, g, x+depth*space, y); }
+ *
+ * public int getIconWidth() { return icon.getIconWidth() + depth*space; }
+ *
+ * public int getIconHeight() { return icon.getIconHeight(); }
+ *
+ * }
+ */
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataKeyID.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataKeyID.java
index fca6c98..a98129f 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataKeyID.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataKeyID.java
@@ -4,85 +4,69 @@ import net.wotonomy.control.EOGlobalID;
import net.wotonomy.datastore.DataKey;
/**
-* A test implementation of EOGlobalID that
-* wraps a DataKey.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class DataKeyID extends EOGlobalID
-{
- private DataKey key;
-
- /**
- * Constructor takes a data key.
- */
- public DataKeyID( DataKey aKey )
- {
- key = aKey;
- }
-
- /**
- * Returns the wrapped data key.
- */
- public DataKey getKey()
- {
- return key;
- }
+ * A test implementation of EOGlobalID that wraps a DataKey.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class DataKeyID extends EOGlobalID {
+ private DataKey key;
+
+ /**
+ * Constructor takes a data key.
+ */
+ public DataKeyID(DataKey aKey) {
+ key = aKey;
+ }
+
+ /**
+ * Returns the wrapped data key.
+ */
+ public DataKey getKey() {
+ return key;
+ }
+
+ public boolean isTemporary() {
+ return false;
+ }
+
+ public Object clone() {
+ return new DataKeyID((DataKey) key.clone());
+ }
+
+ public String toString() {
+ return "[DataKeyID:" + key.toString() + "]";
+ }
+
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ public boolean equals(Object anObject) {
+ if (anObject instanceof DataKeyID) {
+ if (((DataKeyID) anObject).key.equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
- public boolean isTemporary()
- {
- return false;
- }
-
- public Object clone()
- {
- return new DataKeyID( (DataKey) key.clone() );
- }
-
- public String toString()
- {
- return "[DataKeyID:"+key.toString()+"]";
- }
-
- public int hashCode()
- {
- return key.hashCode();
- }
-
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof DataKeyID )
- {
- if ( ((DataKeyID)anObject).key.equals( key ) )
- {
- return true;
- }
- }
- return false;
- }
-
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2001/02/23 23:44:44 mpowers
- * Fixes for hashcode to ensure proper key comparison.
+ * Revision 1.3 2001/02/23 23:44:44 mpowers Fixes for hashcode to ensure proper
+ * key comparison.
*
- * Revision 1.2 2001/02/22 20:56:07 mpowers
- * Tests of notification handling.
+ * Revision 1.2 2001/02/22 20:56:07 mpowers Tests of notification handling.
*
- * Revision 1.1 2001/02/15 21:14:45 mpowers
- * Test suite now using a persistent object store with editing context.
+ * Revision 1.1 2001/02/15 21:14:45 mpowers Test suite now using a persistent
+ * object store with editing context.
*
- * Revision 1.1 2001/02/05 03:45:37 mpowers
- * Starting work on EOEditingContext.
+ * Revision 1.1 2001/02/05 03:45:37 mpowers Starting work on EOEditingContext.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataObjectStore.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataObjectStore.java
index d175f6e..ac5ee44 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataObjectStore.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/DataObjectStore.java
@@ -24,79 +24,59 @@ import net.wotonomy.foundation.NSNotificationQueue;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* An object store that wraps a datastore for vending test objects.
-*/
-public class DataObjectStore extends EOObjectStore
-{
- DataSoup soup;
-
- /**
- * Constructor specifies path to datastore.
- */
- public DataObjectStore( String aPath )
- {
- soup = new XMLFileSoup( aPath );
- }
-
- /**
- * This implementation returns an appropriately configured array fault.
- */
- public NSArray arrayFaultWithSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext )
- {
- return new ArrayFault(
- aGlobalID, aRelationship, aContext );
- }
-
- /**
- * This implementation returns the actual
- * object for the specified id.
- */
- public Object faultForGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
-System.out.println( "DataObjectStore.faultForGlobalID: * reading object * : " + aGlobalID );
- Object result = soup.getObjectByKey(
- ((DataKeyID)aGlobalID).getKey() );
-
- if ( result == null ) return null;
-
- //! transpose keys to objects
- convertRelationKeysToObjects( aContext, result, aGlobalID );
- //!
-
- aContext.recordObject( result, aGlobalID );
- return result;
- }
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary. The fault should
- * belong to the specified editing context.
- */
- public Object faultForRawRow (
- Map aDictionary,
- String anEntityName,
- EOEditingContext aContext )
- {
- //TODO: faults are not yet supported
- throw new WotonomyException(
- "Faults are not yet supported." );
- }
-
- /**
- * Given a newly instantiated object, this method
- * initializes its properties to values appropriate
- * for the specified id. The object should belong
- * to the specified editing context.
- * This method is called to populate faults.
- */
- public void initializeObject(Object anObject, EOGlobalID aGlobalID,
- EOEditingContext aContext) {
+ * An object store that wraps a datastore for vending test objects.
+ */
+public class DataObjectStore extends EOObjectStore {
+ DataSoup soup;
+
+ /**
+ * Constructor specifies path to datastore.
+ */
+ public DataObjectStore(String aPath) {
+ soup = new XMLFileSoup(aPath);
+ }
+
+ /**
+ * This implementation returns an appropriately configured array fault.
+ */
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) {
+ return new ArrayFault(aGlobalID, aRelationship, aContext);
+ }
+
+ /**
+ * This implementation returns the actual object for the specified id.
+ */
+ public Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ System.out.println("DataObjectStore.faultForGlobalID: * reading object * : " + aGlobalID);
+ Object result = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
+
+ if (result == null)
+ return null;
+
+ // ! transpose keys to objects
+ convertRelationKeysToObjects(aContext, result, aGlobalID);
+ // !
+
+ aContext.recordObject(result, aGlobalID);
+ return result;
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. The fault should belong to the
+ * specified editing context.
+ */
+ public Object faultForRawRow(Map aDictionary, String anEntityName, EOEditingContext aContext) {
+ // TODO: faults are not yet supported
+ throw new WotonomyException("Faults are not yet supported.");
+ }
+
+ /**
+ * Given a newly instantiated object, this method initializes its properties to
+ * values appropriate for the specified id. The object should belong to the
+ * specified editing context. This method is called to populate faults.
+ */
+ public void initializeObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
if (aGlobalID.isTemporary()) {
// TODO: this should never happen, but it does now until we get
// faults.
@@ -105,9 +85,8 @@ System.out.println( "DataObjectStore.faultForGlobalID: * reading object * : " +
return;
}
- System.out.println("DataObjectStore.initializeObject: * reading object * : "
- + aGlobalID);
- //net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
+ System.out.println("DataObjectStore.initializeObject: * reading object * : " + aGlobalID);
+ // net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
Object original = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
// ! transpose keys to objects
@@ -116,368 +95,311 @@ System.out.println( "DataObjectStore.faultForGlobalID: * reading object * : " +
EOObserverCenter.notifyObserversObjectWillChange(anObject);
KeyValueCodingUtilities.copy(aContext, original, aContext, anObject);
}
-
- /**
- * Remove all values from all objects in memory, turning them into faults,
- * and posts a notification that all objects have been invalidated.
+
+ /**
+ * Remove all values from all objects in memory, turning them into faults, and
+ * posts a notification that all objects have been invalidated.
*/
- public void invalidateAllObjects ()
- {
- // does nothing except post notification
-
- NSNotificationQueue.defaultQueue().enqueueNotification(
- new NSNotification(
- InvalidatedAllObjectsInStoreNotification, this ),
- NSNotificationQueue.PostNow );
- }
-
- /**
- * Removes values with the specified ids from memory,
- * turning them into faults, and posts a notification
- * that those objects have been invalidated.
- */
- public void invalidateObjectsWithGlobalIDs (
- List aList )
- {
- // does nothing
- }
-
- /**
- * Returns false because locking is not permitted.
- */
- public boolean isObjectLockedWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- return false;
- }
-
- /**
- * Does nothing because locking is not permitted.
- */
- public void lockObjectWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- // does nothing
- }
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship. This method may not return an array fault
- * because array faults call this method to fetch on demand.
- * All objects must be registered the specified editing context.
- * The specified relationship key must produce a result of
- * type Collection for the source object or an exception is thrown.
- */
- public NSArray objectsForSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext )
- {
- System.out.println( "DataObjectStore.objectsForSourceGlobalID: * reading object * : " + aGlobalID );
- Object object = soup.getObjectByKey(((DataKeyID)aGlobalID).getKey() );
-
- if ( object == null ) return null;
-
- Object fault;
- EOGlobalID id;
- NSMutableArray result = new NSMutableArray();
-
- Iterator it = ((TestObject)object).getChildList().iterator();
- while ( it.hasNext() )
- {
- id = new DataKeyID((DataKey)it.next());
- fault = aContext.faultForGlobalID( id, aContext );
-
- // if key still exists
- if ( fault != null )
- {
+ public void invalidateAllObjects() {
+ // does nothing except post notification
+
+ NSNotificationQueue.defaultQueue().enqueueNotification(
+ new NSNotification(InvalidatedAllObjectsInStoreNotification, this), NSNotificationQueue.PostNow);
+ }
+
+ /**
+ * Removes values with the specified ids from memory, turning them into faults,
+ * and posts a notification that those objects have been invalidated.
+ */
+ public void invalidateObjectsWithGlobalIDs(List aList) {
+ // does nothing
+ }
+
+ /**
+ * Returns false because locking is not permitted.
+ */
+ public boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ return false;
+ }
+
+ /**
+ * Does nothing because locking is not permitted.
+ */
+ public void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ // does nothing
+ }
+
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship. This method may not return an array
+ * fault because array faults call this method to fetch on demand. All objects
+ * must be registered the specified editing context. The specified relationship
+ * key must produce a result of type Collection for the source object or an
+ * exception is thrown.
+ */
+ public NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) {
+ System.out.println("DataObjectStore.objectsForSourceGlobalID: * reading object * : " + aGlobalID);
+ Object object = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
+
+ if (object == null)
+ return null;
+
+ Object fault;
+ EOGlobalID id;
+ NSMutableArray result = new NSMutableArray();
+
+ Iterator it = ((TestObject) object).getChildList().iterator();
+ while (it.hasNext()) {
+ id = new DataKeyID((DataKey) it.next());
+ fault = aContext.faultForGlobalID(id, aContext);
+
+ // if key still exists
+ if (fault != null) {
//System.out.println( "objectsForSourceGlobalID: found: " + id + " : " + fault );
- result.add( fault );
+ result.add(fault);
// for testing purposes
-((TestObject)fault).setParent( (TestObject) object );
- }
- else // key no longer exists
- {
- // do not add
-System.out.println( "objectsForSourceGlobalID: could not find fault for id: " + id );
- }
- }
- return result;
-
- }
-
- /**
- * Returns a List of objects the meet the criteria of
- * the supplied specification.
- * Each object is registered with the specified editing context.
- * If any object is already registered in the specified context,
- * it is not refetched and that object should be used in the array.
- */
- public NSArray objectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec,
- EOEditingContext aContext )
- {
- //TODO: fetch specs are not yet supported
-
- DataView view = soup.queryObjects( null, null );
-System.out.println( "DataObjectStore: ** querying all objects **" );
-
- // we've changed this implementation so that
- // it simply calls faultForGlobalID on the context
- // for each id in the result set.
- // this way, child contexts inherit parent's state.
- // however, it's unclear if the specification allows
- // faults in the resulting array. sounds like it doesn't.
- NSMutableArray result = new NSMutableArray();
- DataKeyID id;
- Iterator it = view.iterator();
- while ( it.hasNext() )
- {
- id = new DataKeyID( view.getKeyForObject( it.next() ) );
- result.addObject( aContext.faultForGlobalID( id, aContext ) );
- }
- return result;
- }
-
- /**
- * Removes all values from the specified object,
- * converting it into a fault for the specified id.
- * New or deleted objects should not be refaulted.
- */
- public void refaultObject (
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- //TODO: faults are not yet supported
- // just re-initialize the object
- initializeObject( anObject, aGlobalID, aContext );
- }
-
- /**
- * Writes all changes in the specified editing context
- * to the respository.
- */
- public void saveChangesInEditingContext (
- EOEditingContext aContext )
- {
- Object o;
- DataKeyID id;
- Iterator it;
-
- // process deletes
- it = aContext.deletedObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- id = (DataKeyID) aContext.globalIDForObject( o );
-System.out.println( "DataObjectStore: * deleting object * : " + id );
- soup.removeObject( id.getKey() );
- // remove object from editing context
- aContext.forgetObject( o );
- }
-
- // process inserts
- NSMutableDictionary userInfo = null;
- it = aContext.insertedObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- EOGlobalID oldId = aContext.globalIDForObject( o );
-
- //! transpose objects to keys
- convertRelationObjectsToKeys( aContext, (TestObject) o );
- id = new DataKeyID( soup.addObject( o ) );
- convertRelationKeysToObjects( aContext, (TestObject) o, oldId );
- //!
-
-System.out.println( "DataObjectStore: * adding object * : " + id );
-
- // save mapping of old id to new id
- if ( userInfo == null )
- {
- userInfo = new NSMutableDictionary();
- }
- userInfo.setObjectForKey( id, oldId );
- }
-
- // broadcast inserted objects' new ids if necessary
- if ( userInfo != null )
- {
- NSNotificationQueue.defaultQueue().enqueueNotification(
- new NSNotification(
- EOGlobalID.GlobalIDChangedNotification, null, userInfo ),
- NSNotificationQueue.PostNow );
- }
-
- System.out.println( aContext.updatedObjects() );
-
- // process updates
- it = aContext.updatedObjects().iterator();
- while ( it.hasNext() )
- {
+ ((TestObject) fault).setParent((TestObject) object);
+ } else // key no longer exists
+ {
+ // do not add
+ System.out.println("objectsForSourceGlobalID: could not find fault for id: " + id);
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Returns a List of objects the meet the criteria of the supplied
+ * specification. Each object is registered with the specified editing context.
+ * If any object is already registered in the specified context, it is not
+ * refetched and that object should be used in the array.
+ */
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext) {
+ // TODO: fetch specs are not yet supported
+
+ DataView view = soup.queryObjects(null, null);
+ System.out.println("DataObjectStore: ** querying all objects **");
+
+ // we've changed this implementation so that
+ // it simply calls faultForGlobalID on the context
+ // for each id in the result set.
+ // this way, child contexts inherit parent's state.
+ // however, it's unclear if the specification allows
+ // faults in the resulting array. sounds like it doesn't.
+ NSMutableArray result = new NSMutableArray();
+ DataKeyID id;
+ Iterator it = view.iterator();
+ while (it.hasNext()) {
+ id = new DataKeyID(view.getKeyForObject(it.next()));
+ result.addObject(aContext.faultForGlobalID(id, aContext));
+ }
+ return result;
+ }
+
+ /**
+ * Removes all values from the specified object, converting it into a fault for
+ * the specified id. New or deleted objects should not be refaulted.
+ */
+ public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ // TODO: faults are not yet supported
+ // just re-initialize the object
+ initializeObject(anObject, aGlobalID, aContext);
+ }
+
+ /**
+ * Writes all changes in the specified editing context to the respository.
+ */
+ public void saveChangesInEditingContext(EOEditingContext aContext) {
+ Object o;
+ DataKeyID id;
+ Iterator it;
+
+ // process deletes
+ it = aContext.deletedObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ id = (DataKeyID) aContext.globalIDForObject(o);
+ System.out.println("DataObjectStore: * deleting object * : " + id);
+ soup.removeObject(id.getKey());
+ // remove object from editing context
+ aContext.forgetObject(o);
+ }
+
+ // process inserts
+ NSMutableDictionary userInfo = null;
+ it = aContext.insertedObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ EOGlobalID oldId = aContext.globalIDForObject(o);
+
+ // ! transpose objects to keys
+ convertRelationObjectsToKeys(aContext, (TestObject) o);
+ id = new DataKeyID(soup.addObject(o));
+ convertRelationKeysToObjects(aContext, (TestObject) o, oldId);
+ // !
+
+ System.out.println("DataObjectStore: * adding object * : " + id);
+
+ // save mapping of old id to new id
+ if (userInfo == null) {
+ userInfo = new NSMutableDictionary();
+ }
+ userInfo.setObjectForKey(id, oldId);
+ }
+
+ // broadcast inserted objects' new ids if necessary
+ if (userInfo != null) {
+ NSNotificationQueue.defaultQueue().enqueueNotification(
+ new NSNotification(EOGlobalID.GlobalIDChangedNotification, null, userInfo),
+ NSNotificationQueue.PostNow);
+ }
+
+ System.out.println(aContext.updatedObjects());
+
+ // process updates
+ it = aContext.updatedObjects().iterator();
+ while (it.hasNext()) {
//if ( true ) // test validation error message handling
//throw new RuntimeException( "Update not allowed." );
- o = it.next();
- id = (DataKeyID) aContext.globalIDForObject( o );
-System.out.println( "DataObjectStore: * updating object * : " + id );
-
- //! transpose objects to keys
- convertRelationObjectsToKeys( aContext, (TestObject) o );
- soup.updateObject( id.getKey(), o );
- convertRelationKeysToObjects( aContext, (TestObject) o, id );
- //!
-
- }
- }
-
- private void convertRelationKeysToObjects(
- EOEditingContext aContext, Object anObject, EOGlobalID aGlobalID )
- { // System.out.println( "convertRelationKeysToObjects: " + anObject );
+ o = it.next();
+ id = (DataKeyID) aContext.globalIDForObject(o);
+ System.out.println("DataObjectStore: * updating object * : " + id);
+
+ // ! transpose objects to keys
+ convertRelationObjectsToKeys(aContext, (TestObject) o);
+ soup.updateObject(id.getKey(), o);
+ convertRelationKeysToObjects(aContext, (TestObject) o, id);
+ // !
+
+ }
+ }
+
+ private void convertRelationKeysToObjects(EOEditingContext aContext, Object anObject, EOGlobalID aGlobalID) { // System.out.println(
+ // "convertRelationKeysToObjects:
+ // "
+ // +
+ // anObject
+ // );
// set editing context for testing
-((TestObject)anObject).editingContext = aContext;
-
- Object fault;
- DataKeyID id;
- List result = new LinkedList();
- Iterator it = ((TestObject)anObject).getChildList().iterator();
- while ( it.hasNext() )
- {
- id = new DataKeyID((DataKey)it.next());
- fault = aContext.faultForGlobalID( id, aContext );
-
- // if key still exists
- if ( fault != null )
- {
+ ((TestObject) anObject).editingContext = aContext;
+
+ Object fault;
+ DataKeyID id;
+ List result = new LinkedList();
+ Iterator it = ((TestObject) anObject).getChildList().iterator();
+ while (it.hasNext()) {
+ id = new DataKeyID((DataKey) it.next());
+ fault = aContext.faultForGlobalID(id, aContext);
+
+ // if key still exists
+ if (fault != null) {
//System.out.println( "convertRelationObjectsToKeys: found: " + id + " : " + fault );
- result.add( fault );
+ result.add(fault);
// for testing purposes
-((TestObject)fault).setParent( (TestObject) anObject );
- }
- else // key no longer exists
- {
- // do not add
-System.out.println( "convertRelationObjectsToKeys: could not find fault for id: " + id );
- }
- }
- // this tests loading manually on-demand
+ ((TestObject) fault).setParent((TestObject) anObject);
+ } else // key no longer exists
+ {
+ // do not add
+ System.out.println("convertRelationObjectsToKeys: could not find fault for id: " + id);
+ }
+ }
+ // this tests loading manually on-demand
// ((TestObject)anObject).setChildList( null );
- // this tests loading immediately
- ((TestObject)anObject).setChildList( result );
- // this tests loading array faults
+ // this tests loading immediately
+ ((TestObject) anObject).setChildList(result);
+ // this tests loading array faults
// ((TestObject)result).setChildList( null );
- ((TestObject)anObject).setChildList(
- aContext.arrayFaultWithSourceGlobalID(
- aGlobalID, "childList", aContext ) );
-
- }
-
- private void convertRelationObjectsToKeys(
- EOEditingContext aContext, Object anObject )
- { // System.out.println( "convertRelationObjectsToKeys: " + anObject );
- Object o;
- DataKeyID id;
- List result = new LinkedList();
- Iterator it = ((TestObject)anObject).getChildList().iterator();
+ ((TestObject) anObject).setChildList(aContext.arrayFaultWithSourceGlobalID(aGlobalID, "childList", aContext));
+
+ }
+
+ private void convertRelationObjectsToKeys(EOEditingContext aContext, Object anObject) { // System.out.println(
+ // "convertRelationObjectsToKeys:
+ // " + anObject );
+ Object o;
+ DataKeyID id;
+ List result = new LinkedList();
+ Iterator it = ((TestObject) anObject).getChildList().iterator();
// for testing purposes
-((TestObject)anObject).setParent( null );
-((TestObject)anObject).editingContext = null;
- while ( it.hasNext() )
- {
- o = it.next();
+ ((TestObject) anObject).setParent(null);
+ ((TestObject) anObject).editingContext = null;
+ while (it.hasNext()) {
+ o = it.next();
//System.out.println( "convertRelationObjectsToKeys: " + o + " : " + aContext.globalIDForObject( o ) );
- id = (DataKeyID)aContext.globalIDForObject( o );
-
- // if object still exists in context
- if ( id != null )
- {
- result.add( id.getKey() );
- }
- else // object was deleted
- {
- // do not add
-System.out.println( "convertRelationObjectsToKeys: could not find id for object: " + o );
-System.out.println( aContext.registeredObjects() );
- }
-
- }
- ((TestObject)anObject).setChildList( result );
- }
-
-
-/*
- * $Log$
- * Revision 1.1 2006/02/19 16:30:25 cgruber
- * Update imports and maven dependencies.
- *
- * Revision 1.1 2006/02/16 13:18:56 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
- *
- * Revision 1.18 2002/03/11 03:18:39 mpowers
- * Now properly handling ObserverChangesLater.
- *
- * Revision 1.17 2001/10/26 18:39:44 mpowers
- * Posting notifications immediately, rather than delayed.
- *
- * Revision 1.16 2001/05/06 18:27:10 mpowers
- * More broadly catching editing contexts for now.
- *
- * Revision 1.15 2001/05/05 23:05:43 mpowers
- * Implemented Array Faults.
- *
- * Revision 1.14 2001/05/05 15:00:06 mpowers
- * Tested load-on-demand: still works.
- * Now using registerClone for consistency.
- * Editing context is temporarily posting notification on objectWillChange.
- *
- * Revision 1.13 2001/05/04 23:24:30 mpowers
- * Changes to test code.
- *
- * Revision 1.12 2001/05/04 16:57:56 mpowers
- * Now correctly transposing references to editing contexts when
- * cloning/copying between editing contexts.
- *
- * Revision 1.11 2001/05/02 17:33:28 mpowers
- * More changes for testing.
- *
- * Revision 1.10 2001/04/30 13:15:24 mpowers
- * Child contexts re-initializing objects invalidated in parent now
- * propery transpose relationships.
- *
- * Revision 1.9 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
- *
- * Revision 1.8 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
- *
- * Revision 1.7 2001/04/28 22:17:51 mpowers
- * Revised PropertyDataSource to be EOClassDescription-aware.
- *
- * Revision 1.6 2001/04/28 16:18:44 mpowers
- * Implementing relationships.
- *
- * Revision 1.5 2001/04/13 16:33:36 mpowers
- * Now broadcasting notifications.
- *
- * Revision 1.4 2001/04/08 21:00:54 mpowers
- * Changes to support new objectsForFetchSpecification scheme.
- *
- * Revision 1.3 2001/03/22 21:37:52 mpowers
- * Testing new features.
- *
- * Revision 1.2 2001/03/15 21:10:41 mpowers
- * Implemented global id re-registration for newly saved inserts.
- *
- * Revision 1.1 2001/03/05 22:12:11 mpowers
- * Created the control package for a datastore-specific implementation
- * of EOObjectStore.
- *
- *
- */
-}
+ id = (DataKeyID) aContext.globalIDForObject(o);
+
+ // if object still exists in context
+ if (id != null) {
+ result.add(id.getKey());
+ } else // object was deleted
+ {
+ // do not add
+ System.out.println("convertRelationObjectsToKeys: could not find id for object: " + o);
+ System.out.println(aContext.registeredObjects());
+ }
+ }
+ ((TestObject) anObject).setChildList(result);
+ }
+
+ /*
+ * $Log$ Revision 1.1 2006/02/19 16:30:25 cgruber Update imports and maven
+ * dependencies.
+ *
+ * Revision 1.1 2006/02/16 13:18:56 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.18 2002/03/11 03:18:39 mpowers Now properly handling
+ * ObserverChangesLater.
+ *
+ * Revision 1.17 2001/10/26 18:39:44 mpowers Posting notifications immediately,
+ * rather than delayed.
+ *
+ * Revision 1.16 2001/05/06 18:27:10 mpowers More broadly catching editing
+ * contexts for now.
+ *
+ * Revision 1.15 2001/05/05 23:05:43 mpowers Implemented Array Faults.
+ *
+ * Revision 1.14 2001/05/05 15:00:06 mpowers Tested load-on-demand: still works.
+ * Now using registerClone for consistency. Editing context is temporarily
+ * posting notification on objectWillChange.
+ *
+ * Revision 1.13 2001/05/04 23:24:30 mpowers Changes to test code.
+ *
+ * Revision 1.12 2001/05/04 16:57:56 mpowers Now correctly transposing
+ * references to editing contexts when cloning/copying between editing contexts.
+ *
+ * Revision 1.11 2001/05/02 17:33:28 mpowers More changes for testing.
+ *
+ * Revision 1.10 2001/04/30 13:15:24 mpowers Child contexts re-initializing
+ * objects invalidated in parent now propery transpose relationships.
+ *
+ * Revision 1.9 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
+ *
+ * Revision 1.8 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
+ *
+ * Revision 1.7 2001/04/28 22:17:51 mpowers Revised PropertyDataSource to be
+ * EOClassDescription-aware.
+ *
+ * Revision 1.6 2001/04/28 16:18:44 mpowers Implementing relationships.
+ *
+ * Revision 1.5 2001/04/13 16:33:36 mpowers Now broadcasting notifications.
+ *
+ * Revision 1.4 2001/04/08 21:00:54 mpowers Changes to support new
+ * objectsForFetchSpecification scheme.
+ *
+ * Revision 1.3 2001/03/22 21:37:52 mpowers Testing new features.
+ *
+ * Revision 1.2 2001/03/15 21:10:41 mpowers Implemented global id
+ * re-registration for newly saved inserts.
+ *
+ * Revision 1.1 2001/03/05 22:12:11 mpowers Created the control package for a
+ * datastore-specific implementation of EOObjectStore.
+ *
+ *
+ */
+}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditController.java
index b304ade..6a36db3 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditController.java
@@ -28,187 +28,153 @@ import net.wotonomy.ui.swing.components.ButtonPanel;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* A simple editor panel with a few textfields.
-*/
-public class EditController
-{
- EODisplayGroup group;
- JDialog dialog;
-
- public EditController( EODataSource aDataSource )
- {
+ * A simple editor panel with a few textfields.
+ */
+public class EditController {
+ EODisplayGroup group;
+ JDialog dialog;
+
+ public EditController(EODataSource aDataSource) {
EditPanel editPanel = new EditPanel();
- editPanel.infoPanel.setBorder(
- BorderFactory.createCompoundBorder(
- BorderFactory.createRaisedBevelBorder(),
- BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ) );
- editPanel.setBorder(
- BorderFactory.createEmptyBorder( 0, 0, 0, 0 ) );
- ButtonPanel okPanel = new ButtonPanel(
- new String[] { "Revert", "Refault", "Refresh", "Commit" } );
- editPanel.add( okPanel, BorderLayout.SOUTH );
-
+ editPanel.infoPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
+ BorderFactory.createEmptyBorder(10, 10, 10, 10)));
+ editPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+ ButtonPanel okPanel = new ButtonPanel(new String[] { "Revert", "Refault", "Refresh", "Commit" });
+ editPanel.add(okPanel, BorderLayout.SOUTH);
+
group = new EODisplayGroup();
- group.setDataSource( aDataSource );
- group.fetch();
+ group.setDataSource(aDataSource);
+ group.fetch();
group.selectNext();
-
+
// text associations
-
+
EOAssociation ta;
-
- ta = new TextAssociation( editPanel.firstNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "firstName" );
+
+ ta = new TextAssociation(editPanel.firstNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "firstName");
ta.establishConnection();
-
- ta = new TextAssociation( editPanel.middleNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "middleName" );
+
+ ta = new TextAssociation(editPanel.middleNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "middleName");
ta.establishConnection();
-
- ta = new TextAssociation( editPanel.lastNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "lastName" );
+
+ ta = new TextAssociation(editPanel.lastNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "lastName");
ta.establishConnection();
-
+
// radio panels
-
- ta = new RadioPanelAssociation( editPanel.yearRadioPanel );
- ta.bindAspect( EOAssociation.ValueAspect, group, "createDate.year" );
-
+
+ ta = new RadioPanelAssociation(editPanel.yearRadioPanel);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "createDate.year");
+
EODisplayGroup yearTitles = new EODisplayGroup();
- yearTitles.setObjectArray( new NSArray(
- new Object[] { "1999", "2000", "2001" } ) );
- ta.bindAspect( EOAssociation.TitlesAspect, yearTitles, "" );
-
+ yearTitles.setObjectArray(new NSArray(new Object[] { "1999", "2000", "2001" }));
+ ta.bindAspect(EOAssociation.TitlesAspect, yearTitles, "");
+
EODisplayGroup yearObjects = new EODisplayGroup();
- yearObjects.setObjectArray( new NSArray(
- new Object[] { new Integer( 99 ), new Integer( 100 ), new Integer( 101 ) } ) );
- ta.bindAspect( EOAssociation.ObjectsAspect, yearObjects, "" );
-
+ yearObjects.setObjectArray(new NSArray(new Object[] { new Integer(99), new Integer(100), new Integer(101) }));
+ ta.bindAspect(EOAssociation.ObjectsAspect, yearObjects, "");
+
ta.establishConnection();
-
+
// detail group
-
+
final EODisplayGroup detailGroup = new EODisplayGroup();
- detailGroup.setDataSource( new PropertyDataSource(
- aDataSource.editingContext(), TestObject.class ) );
-
- ta = new MasterDetailAssociation( detailGroup );
- ta.bindAspect( EOAssociation.ParentAspect, group, "childList" );
+ detailGroup.setDataSource(new PropertyDataSource(aDataSource.editingContext(), TestObject.class));
+
+ ta = new MasterDetailAssociation(detailGroup);
+ ta.bindAspect(EOAssociation.ParentAspect, group, "childList");
ta.establishConnection();
-
- ta = new ListAssociation( editPanel.list );
- ta.bindAspect( EOAssociation.TitlesAspect, detailGroup, "fullName" );
+
+ ta = new ListAssociation(editPanel.list);
+ ta.bindAspect(EOAssociation.TitlesAspect, detailGroup, "fullName");
ta.establishConnection();
-
+
// display group action associations
- AbstractButton button = (AbstractButton)
- editPanel.addPanel.getButton( "Add" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- detailGroup.insertNewObjectAtIndex( 0 );
+ AbstractButton button = (AbstractButton) editPanel.addPanel.getButton("Add");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ detailGroup.insertNewObjectAtIndex(0);
}
- } );
-
- ta = new DisplayGroupActionAssociation(
- editPanel.addPanel.getButton( "Remove" ) );
- ta.bindAspect( EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
+ });
+
+ ta = new DisplayGroupActionAssociation(editPanel.addPanel.getButton("Remove"));
+ ta.bindAspect(EOAssociation.ActionAspect, detailGroup, "deleteSelection");
ta.establishConnection();
- // ok / cancel buttons
-
- button = (AbstractButton)
- okPanel.getButton( "Commit" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- group.dataSource().editingContext().saveChanges();
+ // ok / cancel buttons
+
+ button = (AbstractButton) okPanel.getButton("Commit");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ group.dataSource().editingContext().saveChanges();
}
- } );
-
- button = (AbstractButton)
- okPanel.getButton( "Refresh" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- group.dataSource().editingContext().invalidateAllObjects();
+ });
+
+ button = (AbstractButton) okPanel.getButton("Refresh");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ group.dataSource().editingContext().invalidateAllObjects();
}
- } );
-
- button = (AbstractButton)
- okPanel.getButton( "Refault" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
-/*
- Object o = group.displayedObjects().objectAtIndex( 0 );
- group.dataSource().editingContext().refaultObject(
- o,
- group.dataSource().editingContext().globalIDForObject( o ),
- group.dataSource().editingContext() );
-*/
- group.dataSource().editingContext().revert();
- group.dataSource().editingContext().refaultObjects();
+ });
+
+ button = (AbstractButton) okPanel.getButton("Refault");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ /*
+ * Object o = group.displayedObjects().objectAtIndex( 0 );
+ * group.dataSource().editingContext().refaultObject( o,
+ * group.dataSource().editingContext().globalIDForObject( o ),
+ * group.dataSource().editingContext() );
+ */
+ group.dataSource().editingContext().revert();
+ group.dataSource().editingContext().refaultObjects();
}
- } );
-
- button = (AbstractButton)
- okPanel.getButton( "Revert" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- group.dataSource().editingContext().revert();
+ });
+
+ button = (AbstractButton) okPanel.getButton("Revert");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ group.dataSource().editingContext().revert();
}
- } );
-
+ });
+
// add mouse listener for list
-
- editPanel.list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getClickCount() == 2 )
- {
+
+ editPanel.list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
Object item = detailGroup.selectedObject();
- if ( item != null )
- {
+ if (item != null) {
// new InspectorController( item );
-
- new EditController(
- new ChildDataSource(
- group.dataSource(), item ) );
- }
+
+ new EditController(new ChildDataSource(group.dataSource(), item));
+ }
}
}
});
-
+
// launch
-
+
dialog = new JDialog();
// add WindowListener for frame
- dialog.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
- dialog.getContentPane().add( editPanel );
- dialog.setTitle( "Edit Panel" );
+ dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ dialog.getContentPane().add(editPanel);
+ dialog.setTitle("Edit Panel");
dialog.pack();
// dialog.setSize( 300, dialog.getSize().height );
- WindowUtilities.cascade( dialog );
+ WindowUtilities.cascade(dialog);
dialog.show();
- // workaround for memory issues on jdk1.2.2
- dialog.addWindowListener( new WindowAdapter()
- {
+ // workaround for memory issues on jdk1.2.2
+ dialog.addWindowListener(new WindowAdapter() {
// exit on close
- public void windowClosing(WindowEvent e)
- {
- ((JDialog)e.getWindow()).getContentPane().removeAll();
+ public void windowClosing(WindowEvent e) {
+ ((JDialog) e.getWindow()).getContentPane().removeAll();
}
});
}
-
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditPanel.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditPanel.java
index 63b1317..19110f8 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditPanel.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/EditPanel.java
@@ -15,47 +15,44 @@ import net.wotonomy.ui.swing.components.InfoPanel;
import net.wotonomy.ui.swing.components.RadioButtonPanel;
/**
-* A simple editor panel with a few textfields.
-*/
-public class EditPanel extends JPanel
-{
+ * A simple editor panel with a few textfields.
+ */
+public class EditPanel extends JPanel {
public JTextComponent firstNameField;
public JTextField middleNameField, lastNameField;
public RadioButtonPanel yearRadioPanel;
public InfoPanel infoPanel;
public JList list;
- public ButtonPanel addPanel;
-
+ public ButtonPanel addPanel;
- public EditPanel()
- {
- this.setLayout( new BorderLayout() );
- this.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
-
- infoPanel = new InfoPanel();
+ public EditPanel() {
+ this.setLayout(new BorderLayout());
+ this.setBorder(new EmptyBorder(10, 10, 10, 10));
+
+ infoPanel = new InfoPanel();
// name fields
- firstNameField = new JTextField();
- infoPanel.addPair( "First Name", firstNameField );
+ firstNameField = new JTextField();
+ infoPanel.addPair("First Name", firstNameField);
middleNameField = new JTextField();
- infoPanel.addPair( "Middle Name", middleNameField );
+ infoPanel.addPair("Middle Name", middleNameField);
lastNameField = new JTextField();
- infoPanel.addPair( "Last Name", lastNameField );
+ infoPanel.addPair("Last Name", lastNameField);
yearRadioPanel = new RadioButtonPanel();
- infoPanel.addPair( "Year", yearRadioPanel );
-
+ infoPanel.addPair("Year", yearRadioPanel);
+
list = new JList();
- JPanel containerPanel = new JPanel();
- containerPanel.setLayout( new BorderLayout( 0, 5 ) );
- JScrollPane scrollPane = new JScrollPane( list );
- scrollPane.setPreferredSize( new java.awt.Dimension( 100, 100 ) );
- addPanel = new ButtonPanel( new String[] { "Add", "Remove" } );
- addPanel.setAlignment( FlowLayout.CENTER );
- containerPanel.add( scrollPane, BorderLayout.CENTER );
- containerPanel.add( addPanel, BorderLayout.SOUTH );
- infoPanel.addRow( "Children", containerPanel );
-
- this.add( infoPanel, BorderLayout.CENTER );
- }
-
+ JPanel containerPanel = new JPanel();
+ containerPanel.setLayout(new BorderLayout(0, 5));
+ JScrollPane scrollPane = new JScrollPane(list);
+ scrollPane.setPreferredSize(new java.awt.Dimension(100, 100));
+ addPanel = new ButtonPanel(new String[] { "Add", "Remove" });
+ addPanel.setAlignment(FlowLayout.CENTER);
+ containerPanel.add(scrollPane, BorderLayout.CENTER);
+ containerPanel.add(addPanel, BorderLayout.SOUTH);
+ infoPanel.addRow("Children", containerPanel);
+
+ this.add(infoPanel, BorderLayout.CENTER);
+ }
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/InspectorController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/InspectorController.java
index 58e2d9a..eeb6dd9 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/InspectorController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/InspectorController.java
@@ -21,117 +21,103 @@ import net.wotonomy.ui.swing.TextAssociation;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* A simple editor panel with a few textfields.
-*/
-public class InspectorController
-{
- public InspectorController( Object o )
- {
+ * A simple editor panel with a few textfields.
+ */
+public class InspectorController {
+ public InspectorController(Object o) {
EditPanel editPanel = new EditPanel();
-
+
EODisplayGroup group = new EODisplayGroup();
- group.setDataSource( new TestDataSource() );
- group.setObjectArray( new NSArray( o ) );
+ group.setDataSource(new TestDataSource());
+ group.setObjectArray(new NSArray(o));
group.selectNext();
-
+
// text associations
-
+
EOAssociation ta;
-
- ta = new TextAssociation( editPanel.firstNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "firstName" );
+
+ ta = new TextAssociation(editPanel.firstNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "firstName");
ta.establishConnection();
-
- ta = new TextAssociation( editPanel.middleNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "middleName" );
+
+ ta = new TextAssociation(editPanel.middleNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "middleName");
ta.establishConnection();
-
- ta = new TextAssociation( editPanel.lastNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "lastName" );
+
+ ta = new TextAssociation(editPanel.lastNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "lastName");
ta.establishConnection();
-
+
// radio panels
-
- ta = new RadioPanelAssociation( editPanel.yearRadioPanel );
- ta.bindAspect( EOAssociation.ValueAspect, group, "createDate.year" );
-
+
+ ta = new RadioPanelAssociation(editPanel.yearRadioPanel);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "createDate.year");
+
EODisplayGroup yearTitles = new EODisplayGroup();
- yearTitles.setObjectArray( new NSArray(
- new Object[] { "1999", "2000", "2001" } ) );
- ta.bindAspect( EOAssociation.TitlesAspect, yearTitles, "" );
-
+ yearTitles.setObjectArray(new NSArray(new Object[] { "1999", "2000", "2001" }));
+ ta.bindAspect(EOAssociation.TitlesAspect, yearTitles, "");
+
EODisplayGroup yearObjects = new EODisplayGroup();
- yearObjects.setObjectArray( new NSArray(
- new Object[] { new Integer( 99 ), new Integer( 100 ), new Integer( 101 ) } ) );
- ta.bindAspect( EOAssociation.ObjectsAspect, yearObjects, "" );
-
+ yearObjects.setObjectArray(new NSArray(new Object[] { new Integer(99), new Integer(100), new Integer(101) }));
+ ta.bindAspect(EOAssociation.ObjectsAspect, yearObjects, "");
+
ta.establishConnection();
-
+
// detail group
-
+
final EODisplayGroup detailGroup = new EODisplayGroup();
-
- ta = new MasterDetailAssociation( detailGroup );
- ta.bindAspect( EOAssociation.ParentAspect, group, "childList" );
+
+ ta = new MasterDetailAssociation(detailGroup);
+ ta.bindAspect(EOAssociation.ParentAspect, group, "childList");
ta.establishConnection();
-
- ta = new ListAssociation( editPanel.list );
- ta.bindAspect( EOAssociation.TitlesAspect, detailGroup, "fullName" );
+
+ ta = new ListAssociation(editPanel.list);
+ ta.bindAspect(EOAssociation.TitlesAspect, detailGroup, "fullName");
ta.establishConnection();
-
+
// display group action associations
- AbstractButton button = (AbstractButton)
- editPanel.addPanel.getButton( "Add" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- detailGroup.insertNewObjectAtIndex( 0 );
+ AbstractButton button = (AbstractButton) editPanel.addPanel.getButton("Add");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ detailGroup.insertNewObjectAtIndex(0);
}
- } );
-
- ta = new DisplayGroupActionAssociation(
- editPanel.addPanel.getButton( "Remove" ) );
- ta.bindAspect( EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
+ });
+
+ ta = new DisplayGroupActionAssociation(editPanel.addPanel.getButton("Remove"));
+ ta.bindAspect(EOAssociation.ActionAspect, detailGroup, "deleteSelection");
ta.establishConnection();
// add mouse listener for list
-
- editPanel.list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getClickCount() == 2 )
- {
+
+ editPanel.list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
Object item = detailGroup.selectedObject();
- if ( item != null )
- {
- new InspectorController( item );
- }
+ if (item != null) {
+ new InspectorController(item);
+ }
}
}
});
-
+
// launch
-
+
JDialog dialog = new JDialog();
- dialog.getContentPane().add( editPanel );
- dialog.setTitle( "Inspector Panel" );
+ dialog.getContentPane().add(editPanel);
+ dialog.setTitle("Inspector Panel");
dialog.pack();
- dialog.setSize( 300, dialog.getSize().height );
- WindowUtilities.cascade( dialog );
+ dialog.setSize(300, dialog.getSize().height);
+ WindowUtilities.cascade(dialog);
dialog.show();
- // workaround for memory issues on jdk1.2.2
- dialog.addWindowListener( new WindowAdapter()
- {
+ // workaround for memory issues on jdk1.2.2
+ dialog.addWindowListener(new WindowAdapter() {
// exit on close
- public void windowClosing(WindowEvent e)
- {
- ((JDialog)e.getWindow()).getContentPane().removeAll();
+ public void windowClosing(WindowEvent e) {
+ ((JDialog) e.getWindow()).getContentPane().removeAll();
}
});
}
-
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/Test.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/Test.java
index ba6a1dc..5b4533d 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/Test.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/Test.java
@@ -18,103 +18,91 @@ import net.wotonomy.control.EOEditingContext;
import net.wotonomy.control.EOObjectStore;
/**
-* A simple test-bed for wotonomy.
-* Shows a JFrame containing the TestPanel
-* which is controlled by the TestController.
-*/
-public class Test
-{
- static EOObjectStore objectStore;
- static EOEditingContext editingContext;
- static public void main( String[] argv )
- {
+ * A simple test-bed for wotonomy. Shows a JFrame containing the TestPanel which
+ * is controlled by the TestController.
+ */
+public class Test {
+ static EOObjectStore objectStore;
+ static EOEditingContext editingContext;
+
+ static public void main(String[] argv) {
// NSRunLoop.currentRunLoop();
-
- // system l&f
- try
- {
+
+ // system l&f
+ try {
// UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
- UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
// no system l&f - fail silently
- }
-
- // launch notification monitor if desired
- for ( int i = 0; i < argv.length; i++ )
- {
- if ( argv[i].indexOf( "monitor" ) != -1 )
- {
- new net.wotonomy.ui.swing.NotificationInspector();
- }
- }
- new net.wotonomy.ui.swing.NotificationInspector();
-
- // set up editing context hierarchy
- objectStore = new DataObjectStore( "data" );
- editingContext = new EOEditingContext( objectStore );
+ }
+
+ // launch notification monitor if desired
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].indexOf("monitor") != -1) {
+ new net.wotonomy.ui.swing.NotificationInspector();
+ }
+ }
+ new net.wotonomy.ui.swing.NotificationInspector();
+
+ // set up editing context hierarchy
+ objectStore = new DataObjectStore("data");
+ editingContext = new EOEditingContext(objectStore);
// connect panel to controller
- TestPanel testPanel = new TestPanel();
- final TestController controller = new TestController( testPanel );
-
+ TestPanel testPanel = new TestPanel();
+ final TestController controller = new TestController(testPanel);
+
// create frame and show
- JFrame frame = new JFrame();
- frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
-
+ JFrame frame = new JFrame();
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
// setup menus
JMenu menu;
- JMenuItem menuItem;
+ JMenuItem menuItem;
JMenuBar menuBar = new JMenuBar();
- menu = new JMenu( "File" );
- menu.add( "New" );
- menuItem = new JMenuItem( "Save" );
- menuItem.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, KeyEvent.CTRL_MASK ) );
- menuItem.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- controller.displayGroup.dataSource().editingContext().saveChanges();
- }
- });
-
- menu.add( menuItem );
- menu.add( "Close" );
- menuBar.add( menu );
- menu = new JMenu( "Edit" );
- menu.add( "Cut" );
- menu.add( "Copy" );
- menu.add( "Paste" );
- menuBar.add( menu );
- frame.setJMenuBar( menuBar );
-
- frame.getContentPane().add( testPanel, BorderLayout.CENTER );
- frame.setTitle( "Test Frame" );
- frame.setBounds( 50, 50, 750, 500 );
+ menu = new JMenu("File");
+ menu.add("New");
+ menuItem = new JMenuItem("Save");
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK));
+ menuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ controller.displayGroup.dataSource().editingContext().saveChanges();
+ }
+ });
+
+ menu.add(menuItem);
+ menu.add("Close");
+ menuBar.add(menu);
+ menu = new JMenu("Edit");
+ menu.add("Cut");
+ menu.add("Copy");
+ menu.add("Paste");
+ menuBar.add(menu);
+ frame.setJMenuBar(menuBar);
+
+ frame.getContentPane().add(testPanel, BorderLayout.CENTER);
+ frame.setTitle("Test Frame");
+ frame.setBounds(50, 50, 750, 500);
frame.show(); // comment out this to avoid memory leak from jdk1.2.2 bug
// add WindowListener for frame
- frame.addWindowListener( new WindowAdapter()
- {
+ frame.addWindowListener(new WindowAdapter() {
// exit on close
- public void windowClosing(WindowEvent e)
- {
- System.exit( 0 );
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
}
});
- /* uncomment this to avoid memory leak from jdk1.2.2 bug
- frame.getContentPane().removeAll();
- */
-/*
- NSNotificationCenter.defaultCenter().addObserver(
- frame,
- new NSSelector( "hitMe", new Class[] { NSNotification.class } ),
- null, null );
-*/
- }
-
+ /*
+ * uncomment this to avoid memory leak from jdk1.2.2 bug
+ * frame.getContentPane().removeAll();
+ */
+ /*
+ * NSNotificationCenter.defaultCenter().addObserver( frame, new NSSelector(
+ * "hitMe", new Class[] { NSNotification.class } ), null, null );
+ */
+ }
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestController.java
index 8bbb452..83fe97c 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestController.java
@@ -39,357 +39,311 @@ import net.wotonomy.ui.swing.components.IconCellRenderer;
import net.wotonomy.ui.swing.components.KeyableCellEditor;
/**
-* Controller for the TestPanel.
-*/
-public class TestController implements ActionListener
-{
+ * Controller for the TestPanel.
+ */
+public class TestController implements ActionListener {
EODisplayGroup displayGroup;
TestPanel panel;
- public TestController( TestPanel aPanel )
- {
+ public TestController(TestPanel aPanel) {
panel = aPanel;
-
- // setup display group
- displayGroup = new EODisplayGroup();
- displayGroup.setSortOrderings( new NSArray( new Object[]
- { "firstName", "middleName", "lastName" } ) );
+ // setup display group
+
+ displayGroup = new EODisplayGroup();
+ displayGroup.setSortOrderings(new NSArray(new Object[] { "firstName", "middleName", "lastName" }));
// fetch the data
// displayGroup.setUsesOptimisticRefresh( true );
- displayGroup.setDataSource( new TestDataSource() );
+ displayGroup.setDataSource(new TestDataSource());
// displayGroup.setSelectsFirstObjectAfterFetch( true );
- displayGroup.fetch();
- displayGroup.selectNext();
+ displayGroup.fetch();
+ displayGroup.selectNext();
-displayGroup.setDelegate( this );
+ displayGroup.setDelegate(this);
// set up associations
- EOAssociation assoc;
-
+ EOAssociation assoc;
+
// table association
-
+
TableColumn column;
-
+
column = new TableColumn();
- column.setHeaderValue( "First" );
- IconCellRenderer iconRenderer = new IconCellRenderer()
- {
- private Icon icon = UIManager.getIcon("FileChooser.homeFolderIcon");
- public Icon getIconForContext(
- JComponent container, Object value,
- int row, int col,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- return icon;
- }
- };
- iconRenderer.addActionListener( this );
- column.setCellRenderer( new AlternatingRowCellRenderer( iconRenderer ) );
+ column.setHeaderValue("First");
+ IconCellRenderer iconRenderer = new IconCellRenderer() {
+ private Icon icon = UIManager.getIcon("FileChooser.homeFolderIcon");
+
+ public Icon getIconForContext(JComponent container, Object value, int row, int col, boolean isSelected,
+ boolean hasFocus, boolean isExpanded, boolean isLeaf) {
+ return icon;
+ }
+ };
+ iconRenderer.addActionListener(this);
+ column.setCellRenderer(new AlternatingRowCellRenderer(iconRenderer));
// column.setCellEditor( iconRenderer );
// assoc = new TableColumnAssociation( column );
- assoc = new TreeColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "firstName" );
+ assoc = new TreeColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "firstName");
//new net.wotonomy.ui.swing.DisplayGroupInspector( displayGroup );
//displayGroup = new EODisplayGroup();
// assoc.bindAspect( EOAssociation.ChildrenAspect, displayGroup, "childList" );
- assoc.bindAspect( EOAssociation.EditableAspect, null, "true" );
- assoc.bindAspect( EOAssociation.IsLeafAspect, null, "childCount" );
- ((TableColumnAssociation)assoc).setTable( panel.table );
+ assoc.bindAspect(EOAssociation.EditableAspect, null, "true");
+ assoc.bindAspect(EOAssociation.IsLeafAspect, null, "childCount");
+ ((TableColumnAssociation) assoc).setTable(panel.table);
assoc.establishConnection();
- ((TreeColumnAssociation)assoc).getTreeModelAssociation().setInsertingAfter( false );
- ((TreeColumnAssociation)assoc).getTreeModelAssociation().setInsertingChild( false );
+ ((TreeColumnAssociation) assoc).getTreeModelAssociation().setInsertingAfter(false);
+ ((TreeColumnAssociation) assoc).getTreeModelAssociation().setInsertingChild(false);
// column.setCellRenderer( new AlternatingRowCellRenderer( column.getCellRenderer() ) );
-/*
- // test the standalone mode of the icon cell renderer
- panel.add( iconRenderer, java.awt.BorderLayout.SOUTH );
- iconRenderer.setText( "Hello World!" );
- iconRenderer.setIcon( UIManager.getIcon("FileChooser.homeFolderIcon") );
-*/
-
+ /*
+ * // test the standalone mode of the icon cell renderer panel.add(
+ * iconRenderer, java.awt.BorderLayout.SOUTH ); iconRenderer.setText(
+ * "Hello World!" ); iconRenderer.setIcon(
+ * UIManager.getIcon("FileChooser.homeFolderIcon") );
+ */
+
column = new TableColumn();
- column.setHeaderValue( "Middle" );
- column.setCellRenderer( new AlternatingRowCellRenderer() );
- assoc = new TableColumnAssociation( column );
- ((TableColumnAssociation)assoc).setSortCaseSensitive( true );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "middleName" );
- ((TableColumnAssociation)assoc).setTable( panel.table );
+ column.setHeaderValue("Middle");
+ column.setCellRenderer(new AlternatingRowCellRenderer());
+ assoc = new TableColumnAssociation(column);
+ ((TableColumnAssociation) assoc).setSortCaseSensitive(true);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "middleName");
+ ((TableColumnAssociation) assoc).setTable(panel.table);
assoc.establishConnection();
-
+
column = new TableColumn();
- column.setHeaderValue( "Last" );
- column.setCellRenderer( new AlternatingRowCellRenderer() );
- column.setCellEditor( new KeyableCellEditor() );
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "lastName" );
- assoc.bindAspect( EOAssociation.EditableAspect, null, "true" );
- ((TableColumnAssociation)assoc).setTable( panel.table );
+ column.setHeaderValue("Last");
+ column.setCellRenderer(new AlternatingRowCellRenderer());
+ column.setCellEditor(new KeyableCellEditor());
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "lastName");
+ assoc.bindAspect(EOAssociation.EditableAspect, null, "true");
+ ((TableColumnAssociation) assoc).setTable(panel.table);
assoc.establishConnection();
-
+
column = new TableColumn();
- column.setHeaderValue( "Created" );
+ column.setHeaderValue("Created");
FormattedCellRenderer renderer = new FormattedCellRenderer();
- renderer.setFormat( DateFormat.getDateInstance() );
- column.setCellRenderer( new AlternatingRowCellRenderer( renderer ) );
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "createDate" );
- ((TableColumnAssociation)assoc).setTable( panel.table );
+ renderer.setFormat(DateFormat.getDateInstance());
+ column.setCellRenderer(new AlternatingRowCellRenderer(renderer));
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "createDate");
+ ((TableColumnAssociation) assoc).setTable(panel.table);
assoc.establishConnection();
-
+
column = new TableColumn();
- column.setHeaderValue( "Special" );
- column.setCellRenderer( new AlternatingRowCellRenderer(
- panel.table.getDefaultRenderer( Boolean.class ) ) );
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "special" );
- assoc.bindAspect( EOAssociation.EditableAspect, null, "true" );
- ((TableColumnAssociation)assoc).setTable( panel.table );
+ column.setHeaderValue("Special");
+ column.setCellRenderer(new AlternatingRowCellRenderer(panel.table.getDefaultRenderer(Boolean.class)));
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "special");
+ assoc.bindAspect(EOAssociation.EditableAspect, null, "true");
+ ((TableColumnAssociation) assoc).setTable(panel.table);
assoc.establishConnection();
-
- // text associations
- assoc = new TextAssociation( panel.firstNameField );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "firstName" );
+ // text associations
+
+ assoc = new TextAssociation(panel.firstNameField);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "firstName");
//EODisplayGroup controllerDisplayGroup = new EODisplayGroup();
//controllerDisplayGroup.setObjectArray( new NSArray( this ) );
//controllerDisplayGroup.selectNext();
//assoc.bindAspect( EOAssociation.ValueAspect, controllerDisplayGroup, "filter" );
assoc.establishConnection();
- assoc = new TextAssociation( panel.middleNameField );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "middleName" );
+ assoc = new TextAssociation(panel.middleNameField);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "middleName");
assoc.establishConnection();
-
- assoc = new TextAssociation( panel.lastNameField );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "lastName" );
- assoc.bindAspect( EOAssociation.LabelAspect, displayGroup, "special" );
+
+ assoc = new TextAssociation(panel.lastNameField);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "lastName");
+ assoc.bindAspect(EOAssociation.LabelAspect, displayGroup, "special");
assoc.establishConnection();
-
- assoc = new ButtonAssociation( panel.checkbox );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "special" );
+
+ assoc = new ButtonAssociation(panel.checkbox);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "special");
// assoc.bindAspect( EOAssociation.EnabledAspect, displayGroup, "special" );
// assoc.bindAspect( EOAssociation.VisibleAspect, displayGroup, "special" );
assoc.establishConnection();
-
+
// combo associations
-
- assoc = new ComboBoxAssociation( panel.dateBox );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "createDate.date" );
- // no titles aspect: uses existing combobox options
+
+ assoc = new ComboBoxAssociation(panel.dateBox);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "createDate.date");
+ // no titles aspect: uses existing combobox options
assoc.establishConnection();
-
- assoc = new ComboBoxAssociation( panel.monthBox );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "createDate.month" );
+
+ assoc = new ComboBoxAssociation(panel.monthBox);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "createDate.month");
EODisplayGroup monthTitlesGroup = new EODisplayGroup();
- monthTitlesGroup.setObjectArray( new NSArray(
- new Object[] { "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December" } ) );
- assoc.bindAspect( EOAssociation.TitlesAspect, monthTitlesGroup, "" );
+ monthTitlesGroup.setObjectArray(new NSArray(new Object[] { "January", "February", "March", "April", "May",
+ "June", "July", "August", "September", "October", "November", "December" }));
+ assoc.bindAspect(EOAssociation.TitlesAspect, monthTitlesGroup, "");
EODisplayGroup monthObjectsGroup = new EODisplayGroup();
- monthObjectsGroup.setObjectArray( new NSArray(
- new Object[] { new Integer( 0 ),
- new Integer( 1 ), new Integer( 2 ), new Integer( 3 ),
- new Integer( 4 ), new Integer( 5 ), new Integer( 6 ),
- new Integer( 7 ), new Integer( 8 ), new Integer( 9 ),
- new Integer( 10 ), new Integer( 11 ) } ) );
- assoc.bindAspect( EOAssociation.ObjectsAspect, monthObjectsGroup, "" );
-
+ monthObjectsGroup.setObjectArray(new NSArray(new Object[] { new Integer(0), new Integer(1), new Integer(2),
+ new Integer(3), new Integer(4), new Integer(5), new Integer(6), new Integer(7), new Integer(8),
+ new Integer(9), new Integer(10), new Integer(11) }));
+ assoc.bindAspect(EOAssociation.ObjectsAspect, monthObjectsGroup, "");
+
assoc.establishConnection();
-
- assoc = new ComboBoxAssociation( panel.yearBox );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "createDate.year" );
-
+ assoc = new ComboBoxAssociation(panel.yearBox);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "createDate.year");
+
EODisplayGroup yearTitlesGroup = new EODisplayGroup();
- yearTitlesGroup.setObjectArray( new NSArray(
- new Object[] { "1999", "2000", "2001" } ) );
- assoc.bindAspect( EOAssociation.TitlesAspect, yearTitlesGroup, "" );
+ yearTitlesGroup.setObjectArray(new NSArray(new Object[] { "1999", "2000", "2001" }));
+ assoc.bindAspect(EOAssociation.TitlesAspect, yearTitlesGroup, "");
EODisplayGroup yearObjectsGroup = new EODisplayGroup();
- yearObjectsGroup.setObjectArray( new NSArray(
- new Object[] { new Integer( 99 ), new Integer( 100 ), new Integer( 101 ) } ) );
- assoc.bindAspect( EOAssociation.ObjectsAspect, yearObjectsGroup, "" );
-
+ yearObjectsGroup
+ .setObjectArray(new NSArray(new Object[] { new Integer(99), new Integer(100), new Integer(101) }));
+ assoc.bindAspect(EOAssociation.ObjectsAspect, yearObjectsGroup, "");
+
assoc.establishConnection();
-
- assoc = new SliderAssociation( panel.slider );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "createDate.date" );
- assoc.bindAspect( EOAssociation.VisibleAspect, displayGroup, "special" );
+
+ assoc = new SliderAssociation(panel.slider);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "createDate.date");
+ assoc.bindAspect(EOAssociation.VisibleAspect, displayGroup, "special");
assoc.establishConnection();
-
- assoc = new TextAssociation( panel.infoPanel.getLabelForKey( "Day of Month" ) );
- assoc.bindAspect( EOAssociation.VisibleAspect, displayGroup, "special" );
+
+ assoc = new TextAssociation(panel.infoPanel.getLabelForKey("Day of Month"));
+ assoc.bindAspect(EOAssociation.VisibleAspect, displayGroup, "special");
assoc.establishConnection();
-
+
// display group action associations
- AbstractButton button;
-
- button = (AbstractButton)
- panel.savePanel.getButton( "Refresh All" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- { // panel.lastNameField.setText( panel.lastNameField.getText().trim() );
-
- // test all three ways
-
- displayGroup.dataSource().editingContext().invalidateAllObjects();
+ AbstractButton button;
+
+ button = (AbstractButton) panel.savePanel.getButton("Refresh All");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) { // panel.lastNameField.setText(
+ // panel.lastNameField.getText().trim() );
+
+ // test all three ways
+
+ displayGroup.dataSource().editingContext().invalidateAllObjects();
// displayGroup.dataSource().editingContext().parentObjectStore().invalidateAllObjects();
// displayGroup.dataSource().editingContext().revert();
}
- } );
-
- button = (AbstractButton)
- panel.savePanel.getButton( "Commit" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- try
- {
- displayGroup.dataSource().editingContext().saveChanges();
- }
- catch ( RuntimeException exc )
- {
- JOptionPane.showMessageDialog(
- (java.awt.Component)evt.getSource(), exc.getMessage() );
- exc.printStackTrace();
- }
+ });
+
+ button = (AbstractButton) panel.savePanel.getButton("Commit");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ try {
+ displayGroup.dataSource().editingContext().saveChanges();
+ } catch (RuntimeException exc) {
+ JOptionPane.showMessageDialog((java.awt.Component) evt.getSource(), exc.getMessage());
+ exc.printStackTrace();
+ }
}
- } );
-
- button = (AbstractButton)
- panel.buttonPanel.getButton( "Add" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- displayGroup.insertNewObjectAtIndex( 0 );
+ });
+
+ button = (AbstractButton) panel.buttonPanel.getButton("Add");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ displayGroup.insertNewObjectAtIndex(0);
}
- } );
-
- assoc = new DisplayGroupActionAssociation(
- panel.buttonPanel.getButton( "Remove" ) );
- assoc.bindAspect( EOAssociation.ActionAspect, displayGroup, "deleteSelection" );
- assoc.establishConnection();
-/*
- assoc = new DisplayGroupActionAssociation(
- panel.infoPanel.getButtonPanel().getButton( "Refresh" ) );
- assoc.bindAspect( EOAssociation.ActionAspect, displayGroup, "updateDisplayedObjects" );
- assoc.establishConnection();
+ });
- assoc = new DisplayGroupActionAssociation(
- panel.infoPanel.getButtonPanel().getButton( "Commit" ) );
- assoc.bindAspect( EOAssociation.ActionAspect, displayGroup, "updateDisplayedObjects" );
+ assoc = new DisplayGroupActionAssociation(panel.buttonPanel.getButton("Remove"));
+ assoc.bindAspect(EOAssociation.ActionAspect, displayGroup, "deleteSelection");
assoc.establishConnection();
-*/
+ /*
+ * assoc = new DisplayGroupActionAssociation(
+ * panel.infoPanel.getButtonPanel().getButton( "Refresh" ) ); assoc.bindAspect(
+ * EOAssociation.ActionAspect, displayGroup, "updateDisplayedObjects" );
+ * assoc.establishConnection();
+ *
+ * assoc = new DisplayGroupActionAssociation(
+ * panel.infoPanel.getButtonPanel().getButton( "Commit" ) ); assoc.bindAspect(
+ * EOAssociation.ActionAspect, displayGroup, "updateDisplayedObjects" );
+ * assoc.establishConnection();
+ */
// add MouseListener for table
- panel.table.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getClickCount() == 2 )
- {
+ panel.table.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
Object o = displayGroup.selectedObject();
- if ( o != null )
- {
+ if (o != null) {
// new InspectorController( o );
- new EditController(
- new ChildDataSource(
- displayGroup.dataSource(), o ) );
- }
+ new EditController(new ChildDataSource(displayGroup.dataSource(), o));
+ }
}
}
});
-
+
// add ActionListener for tree button
- ((JButton) panel.buttonPanel.getButton(
- "Tree View" ) ).addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- EOEditingContext parentContext = Test.editingContext;
- EOEditingContext childContext = new EOEditingContext( parentContext );
-
- // transpose objects to ids to faults
- List ids = new LinkedList();
- Iterator i = displayGroup.selectedObjects().iterator();
- while ( i.hasNext() )
- {
- ids.add( parentContext.globalIDForObject( i.next() ) );
- }
- List objects = new LinkedList();
- i = ids.iterator();
- while( i.hasNext() )
- {
- objects.add( childContext.faultForGlobalID( (EOGlobalID) i.next(), childContext ) );
- }
-
+ ((JButton) panel.buttonPanel.getButton("Tree View")).addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ EOEditingContext parentContext = Test.editingContext;
+ EOEditingContext childContext = new EOEditingContext(parentContext);
+
+ // transpose objects to ids to faults
+ List ids = new LinkedList();
+ Iterator i = displayGroup.selectedObjects().iterator();
+ while (i.hasNext()) {
+ ids.add(parentContext.globalIDForObject(i.next()));
+ }
+ List objects = new LinkedList();
+ i = ids.iterator();
+ while (i.hasNext()) {
+ objects.add(childContext.faultForGlobalID((EOGlobalID) i.next(), childContext));
+ }
+
EODisplayGroup treeGroup = new EODisplayGroup();
- treeGroup.setSortOrderings( new NSArray( "lastName" ) );
- treeGroup.setObjectArray( objects );
+ treeGroup.setSortOrderings(new NSArray("lastName"));
+ treeGroup.setObjectArray(objects);
- EODisplayGroup childGroup = new EODisplayGroup();
-
- //childGroup.setDelegate( new DebuggingDelegate() );
- //new TreeInspectorController( treeGroup, childGroup );
- //new BindingController( treeGroup, childGroup );
+ EODisplayGroup childGroup = new EODisplayGroup();
- new TreeController( childContext, treeGroup, childGroup );
+ // childGroup.setDelegate( new DebuggingDelegate() );
+ // new TreeInspectorController( treeGroup, childGroup );
+ // new BindingController( treeGroup, childGroup );
- //NOTE: ChildDataSource is fundamentally broken
+ new TreeController(childContext, treeGroup, childGroup);
+
+ // NOTE: ChildDataSource is fundamentally broken
// new TreeController( new ChildDataSource(
// displayGroup.dataSource(), displayGroup.selectedObjects() ) );
}
});
-/*
- NSNotificationCenter.defaultCenter().addObserver(
- this,
- new NSSelector( "hitMe", new Class[] { NSNotification.class } ),
- null, null );
-*/
+ /*
+ * NSNotificationCenter.defaultCenter().addObserver( this, new NSSelector(
+ * "hitMe", new Class[] { NSNotification.class } ), null, null );
+ */
+ }
+
+ private String filter;
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String aFilter) {
+ filter = aFilter;
+
+ EOQualifier qualifier = null;
+ if (!"".equals(aFilter)) {
+ qualifier = new EOKeyValueQualifier("firstName", EOQualifier.QualifierOperatorContains, filter);
+ }
+ displayGroup.setQualifier(qualifier);
+ displayGroup.updateDisplayedObjects();
+ }
+
+ public void hitMe(NSNotification aNote) {
+ System.out.println(aNote);
}
-
- private String filter;
- public String getFilter()
- {
- return filter;
- }
-
- public void setFilter( String aFilter )
- {
- filter = aFilter;
-
- EOQualifier qualifier = null;
- if ( ! "".equals( aFilter ) )
- {
- qualifier = new EOKeyValueQualifier(
- "firstName", EOQualifier.QualifierOperatorContains, filter );
- }
- displayGroup.setQualifier( qualifier );
- displayGroup.updateDisplayedObjects();
- }
-
- public void hitMe( NSNotification aNote )
- {
- System.out.println( aNote );
- }
-
- public void actionPerformed( ActionEvent evt )
- {
- Object o = displayGroup.selectedObject();
- if ( o != null )
- {
+
+ public void actionPerformed(ActionEvent evt) {
+ Object o = displayGroup.selectedObject();
+ if (o != null) {
// new ObjectInspector( o );
- new InspectorController( o );
- }
- }
-
+ new InspectorController(o);
+ }
+ }
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestDataSource.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestDataSource.java
index 1d36bef..c55a386 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestDataSource.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestDataSource.java
@@ -7,109 +7,83 @@ import net.wotonomy.control.EOFetchSpecification;
import net.wotonomy.foundation.NSArray;
/**
-* A custom DataSource that works with
-* the datastore package for persistence.
-*/
-public class TestDataSource extends EODataSource
-{
- private EOEditingContext context;
- private Object source;
- private String key;
-
- public TestDataSource()
- {
- this( Test.editingContext );
+ * A custom DataSource that works with the datastore package for persistence.
+ */
+public class TestDataSource extends EODataSource {
+ private EOEditingContext context;
+ private Object source;
+ private String key;
+
+ public TestDataSource() {
+ this(Test.editingContext);
}
-
- public TestDataSource( EOEditingContext aContext )
- {
- context = aContext;
+
+ public TestDataSource(EOEditingContext aContext) {
+ context = aContext;
}
-
- public EOEditingContext editingContext()
- {
- return context;
- }
-
- /**
- * This implementation does nothing.
- */
- public void insertObject ( Object anObject )
- {
- // creates are handled by createObject().
+
+ public EOEditingContext editingContext() {
+ return context;
}
- /**
- * Deletes the specified object from this data source.
- */
- public void deleteObject ( Object anObject )
- {
- editingContext().deleteObject( anObject );
+ /**
+ * This implementation does nothing.
+ */
+ public void insertObject(Object anObject) {
+ // creates are handled by createObject().
}
- /**
- * Returns a List containing the objects in this
- * data source. This implementation returns all
- * TestObjects that have been persisted to the
- * datastore in the data directory.
- */
- public NSArray fetchObjects ()
- {
- if ( source == null )
- {
- NSArray result = editingContext().objectsWithFetchSpecification(
- new EOFetchSpecification() );
- if ( result.size() > 0 )
- {
- result = new NSArray( result.objectAtIndex( 0 ) );
+ /**
+ * Deletes the specified object from this data source.
+ */
+ public void deleteObject(Object anObject) {
+ editingContext().deleteObject(anObject);
+ }
+
+ /**
+ * Returns a List containing the objects in this data source. This
+ * implementation returns all TestObjects that have been persisted to the
+ * datastore in the data directory.
+ */
+ public NSArray fetchObjects() {
+ if (source == null) {
+ NSArray result = editingContext().objectsWithFetchSpecification(new EOFetchSpecification());
+ if (result.size() > 0) {
+ result = new NSArray(result.objectAtIndex(0));
//result.add( result.objectAtIndex( 0 ) );
- }
- return result;
- }
- else
- {
- return new NSArray(
- ((TestObject)source).getChildList() );
- }
- }
+ }
+ return result;
+ } else {
+ return new NSArray(((TestObject) source).getChildList());
+ }
+ }
- /**
- * Returns a data source that is capable of
- * manipulating objects of the type returned by
- * applying the specified key to objects
- * vended by this data source.
- * @see #qualifyWithRelationshipKey
- */
- public EODataSource
- dataSourceQualifiedByKey ( String aKey )
- {
- return new TestDataSource( editingContext() );
+ /**
+ * Returns a data source that is capable of manipulating objects of the type
+ * returned by applying the specified key to objects vended by this data source.
+ *
+ * @see #qualifyWithRelationshipKey
+ */
+ public EODataSource dataSourceQualifiedByKey(String aKey) {
+ return new TestDataSource(editingContext());
}
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- */
- public void
- qualifyWithRelationshipKey (
- String aKey, Object anObject )
- {
- key = aKey;
- source = anObject;
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object.
+ */
+ public void qualifyWithRelationshipKey(String aKey, Object anObject) {
+ key = aKey;
+ source = anObject;
}
- /**
- * Returns the description of the class of the
- * objects that is vended by this data source,
- * or null if this cannot be determined.
- * This implementation returns TestObject.
- */
- public EOClassDescription
- classDescriptionForObjects ()
- {
- return EOClassDescription.classDescriptionForClass(
- TestObject.class );
- }
+ /**
+ * Returns the description of the class of the objects that is vended by this
+ * data source, or null if this cannot be determined. This implementation
+ * returns TestObject.
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ return EOClassDescription.classDescriptionForClass(TestObject.class);
+ }
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestMap.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestMap.java
index 8a88e68..a7f4e06 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestMap.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestMap.java
@@ -12,153 +12,131 @@ import net.wotonomy.datastore.SerializedFileSoup;
import net.wotonomy.datastore.XMLFileSoup;
import net.wotonomy.foundation.internal.ValueConverter;
-public class TestMap extends HashMap
-{
- public TestMap()
- {
- put( "date", new Date() );
- put( "firstName", randomParse(
- "Bert|Ernie|Elmo|Zoe|Arthur|Emily|DJ|Grover|Oscar|Max|Big|Twinkle") );
- put( "middleName", new StringBuffer( randomParse(
- "Rufus|Remy|Martin|Josephus|Ulysses|Homer|Bart|Tip|Onegin|Meredith|Jay") ) );
- put( "lastName", randomParse(
- "Alejandro|Alexander|Bird|Gosling|Joy|Van Hoff|Pedia|Marr|McNealy|Ping") );
- put( "address", randomParse( "1|2|3|4" ) + randomParse( "0|1|00|10|5|50" ) +
- randomParse( "0|00|1|01|5|05|9|09||000" ) + " " + randomParse(
- "Merry|Berry|Perry|Jerry|Meadow|Falls|Elm|Raspberry|Strawberry") + " "
- + randomParse( "Road|Lane|Court|Drive|Parkway|Terrace" ) );
- put( "city", randomParse(
- "Springfield|Sterling|Cascades|Vienna|Reston|Paris|London|Runnymeade") );
- put( "state", randomParse(
- "TX|NJ|NY|VA|DC|MD|NC|SC|WV|AR|FL|CA|TN" ) );
- put( "zip", ValueConverter.getInteger(
- randomParse( "1|2|3|4" ) + "0" + randomParse( "0|1|2|3|5" ) +
- randomParse( "6|7|8|9" ) + randomParse( "6|7|8|9" ) ) );
- put( "age", new Short( (short) ( new Random().nextDouble() * 40 + 18 ) ) );
+public class TestMap extends HashMap {
+ public TestMap() {
+ put("date", new Date());
+ put("firstName", randomParse("Bert|Ernie|Elmo|Zoe|Arthur|Emily|DJ|Grover|Oscar|Max|Big|Twinkle"));
+ put("middleName",
+ new StringBuffer(randomParse("Rufus|Remy|Martin|Josephus|Ulysses|Homer|Bart|Tip|Onegin|Meredith|Jay")));
+ put("lastName", randomParse("Alejandro|Alexander|Bird|Gosling|Joy|Van Hoff|Pedia|Marr|McNealy|Ping"));
+ put("address",
+ randomParse("1|2|3|4") + randomParse("0|1|00|10|5|50") + randomParse("0|00|1|01|5|05|9|09||000") + " "
+ + randomParse("Merry|Berry|Perry|Jerry|Meadow|Falls|Elm|Raspberry|Strawberry") + " "
+ + randomParse("Road|Lane|Court|Drive|Parkway|Terrace"));
+ put("city", randomParse("Springfield|Sterling|Cascades|Vienna|Reston|Paris|London|Runnymeade"));
+ put("state", randomParse("TX|NJ|NY|VA|DC|MD|NC|SC|WV|AR|FL|CA|TN"));
+ put("zip", ValueConverter.getInteger(randomParse("1|2|3|4") + "0" + randomParse("0|1|2|3|5")
+ + randomParse("6|7|8|9") + randomParse("6|7|8|9")));
+ put("age", new Short((short) (new Random().nextDouble() * 40 + 18)));
childCount = -1;
- }
-
+ }
+
protected int childCount;
- public int getChildCount()
- {
- if ( childCount == -1 )
- {
- //childCount = (int) ( random.nextDouble() * 6 ) - 3; // + 100; // tree scalability test
- if ( childCount < 0 ) childCount = 0;
+
+ public int getChildCount() {
+ if (childCount == -1) {
+ // childCount = (int) ( random.nextDouble() * 6 ) - 3; // + 100; // tree
+ // scalability test
+ if (childCount < 0)
+ childCount = 0;
}
- return childCount;
+ return childCount;
};
-
+
protected TestMap[] children;
- public TestMap[] getChildren()
- {
- if ( get( "children" ) == null )
- {
+
+ public TestMap[] getChildren() {
+ if (get("children") == null) {
int n = getChildCount();
- TestMap[] children = new TestMap[ n ];
- for ( int i = 0; i < n; i++ )
- {
+ TestMap[] children = new TestMap[n];
+ for (int i = 0; i < n; i++) {
children[i] = new TestMap();
}
- put( "children", children );
+ put("children", children);
}
- return (TestMap[]) get( "children" );
+ return (TestMap[]) get("children");
}
- public void setChildren( TestMap[] aChildArray )
- {
- put( "children", aChildArray );
+
+ public void setChildren(TestMap[] aChildArray) {
+ put("children", aChildArray);
}
- public List getChildList()
- {
+
+ public List getChildList() {
List result = new LinkedList();
TestMap[] childArray = getChildren();
- for ( int i = 0; i < childArray.length; i++ )
- {
- result.add( childArray[i] );
+ for (int i = 0; i < childArray.length; i++) {
+ result.add(childArray[i]);
}
return result;
}
- public void setChildList( List aChildList )
- {
- TestMap[] children = new TestMap[ aChildList.size() ];
- for ( int i = 0; i < children.length; i++ )
- {
- children[i] = (TestMap) aChildList.get( i );
+
+ public void setChildList(List aChildList) {
+ TestMap[] children = new TestMap[aChildList.size()];
+ for (int i = 0; i < children.length; i++) {
+ children[i] = (TestMap) aChildList.get(i);
}
- setChildren( children );
+ setChildren(children);
}
-
- public String getFullName()
- {
- return get( "firstName" ) + " " + get( "middleName" ) + " " + get( "lastName" );
- }
-
- public boolean equals( Object anObject )
- {
- return anObject == this;
- }
-
- public String toString()
- {
- return "[" + getClass().getName() + ":" + getFullName() + "]";
+
+ public String getFullName() {
+ return get("firstName") + " " + get("middleName") + " " + get("lastName");
+ }
+
+ public boolean equals(Object anObject) {
+ return anObject == this;
+ }
+
+ public String toString() {
+ return "[" + getClass().getName() + ":" + getFullName() + "]";
+ }
+
+ // statics
+
+ private static Random random = new Random();
+
+ private static String randomParse(String aString) {
+ String result = "";
+ StringTokenizer tokens = new StringTokenizer(aString, "|");
+ int n = (int) (random.nextDouble() * tokens.countTokens());
+ for (int i = 0; i <= n; i++) {
+ result = tokens.nextToken();
+ }
+ return result;
+ }
+
+ public static void main(String[] argv) {
+ int count = 100;
+ boolean xmlMode = false;
+ if (argv.length > 0) {
+ Integer parsed = ValueConverter.getInteger(argv[0]);
+ if (parsed != null)
+ count = parsed.intValue();
+
+ if (argv.length > 1) {
+ if (argv[1].indexOf("xml") > -1) {
+ xmlMode = true;
+ }
+ }
+ }
+
+ long millis = System.currentTimeMillis();
+
+ DataSoup store = null;
+ if (xmlMode) {
+ store = new XMLFileSoup("testMaps-xml");
+ } else {
+ store = new SerializedFileSoup("testMaps-java");
+ }
+
+ Object o;
+ for (int i = 0; i < count; i++) {
+ store.addObject(new TestMap());
+ }
+ /*
+ * store.addIndex( "age", "age" ); store.addIndex( "zipCode", "zipCode" );
+ * store.addIndex( "firstName", "firstName" ); store.addIndex( "lastName",
+ * "lastName" );
+ */
+ System.out.println(System.currentTimeMillis() - millis + " milliseconds");
}
-
- // statics
-
- private static Random random = new Random();
- private static String randomParse( String aString )
- {
- String result = "";
- StringTokenizer tokens = new StringTokenizer( aString, "|" );
- int n = (int) ( random.nextDouble() * tokens.countTokens() );
- for ( int i = 0; i <= n; i++ )
- {
- result = tokens.nextToken();
- }
- return result;
- }
-
- public static void main( String[] argv )
- {
- int count = 100;
- boolean xmlMode = false;
- if ( argv.length > 0 )
- {
- Integer parsed = ValueConverter.getInteger( argv[0] );
- if ( parsed != null ) count = parsed.intValue();
-
- if ( argv.length > 1 )
- {
- if ( argv[1].indexOf( "xml" ) > -1 )
- {
- xmlMode = true;
- }
- }
- }
-
-long millis = System.currentTimeMillis();
-
- DataSoup store = null;
- if ( xmlMode )
- {
- store = new XMLFileSoup( "testMaps-xml" );
- }
- else
- {
- store = new SerializedFileSoup( "testMaps-java" );
- }
-
- Object o;
- for ( int i = 0; i < count; i++ )
- {
- store.addObject( new TestMap() );
- }
- /*
- store.addIndex( "age", "age" );
- store.addIndex( "zipCode", "zipCode" );
- store.addIndex( "firstName", "firstName" );
- store.addIndex( "lastName", "lastName" );
-*/
-System.out.println( System.currentTimeMillis() - millis + " milliseconds" );
- }
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObject.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObject.java
index 72a3dbc..08b46b7 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObject.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObject.java
@@ -16,347 +16,344 @@ import net.wotonomy.foundation.internal.ValueConverter;
public class TestObject implements Serializable // , EOKeyValueCoding
{
- static final long serialVersionUID = -5482454640042392838L;
-
+ static final long serialVersionUID = -5482454640042392838L;
+
// for testing manual array faulting
-public EOEditingContext editingContext;
-public EOEditingContext getEditingContext() { return editingContext; };
-
- public TestObject()
- {
- date = new Date();
- firstName = randomParse(
- "Bert|Ernie|Elmo|Zoe|Arthur|Emily|DJ|Grover|Oscar|Max|Big|Twinkle");
- middleName = new StringBuffer( randomParse(
- "Rufus|Remy|Martin|Josephus|Ulysses|Homer|Bart|Tip|Onegin|Meredith|Jay") );
- lastName = randomParse(
- "Alejandro|Alexander|Bird|Gosling|Joy|Van Hoff|Pedia|Marr|McNealy|Ping");
- address = randomParse( "1|2|3|4" ) + randomParse( "0|1|00|10|5|50" ) +
- randomParse( "0|00|1|01|5|05|9|09||000" ) + " " + randomParse(
- "Merry|Berry|Perry|Jerry|Meadow|Falls|Elm|Raspberry|Strawberry") + " "
- + randomParse( "Road|Lane|Court|Drive|Parkway|Terrace" );
- city = randomParse(
- "Springfield|Sterling|Cascades|Vienna|Reston|Paris|London|Runnymeade");
- state = randomParse(
- "TX|NJ|NY|VA|DC|MD|NC|SC|WV|AR|FL|CA|TN" );
- zip = ValueConverter.getIntValue(
- randomParse( "1|2|3|4" ) + "0" + randomParse( "0|1|2|3|5" ) +
- randomParse( "6|7|8|9" ) + randomParse( "6|7|8|9" ) );
- age = (short) ( new Random().nextDouble() * 40 + 18 );
+ public EOEditingContext editingContext;
+
+ public EOEditingContext getEditingContext() {
+ return editingContext;
+ };
+
+ public TestObject() {
+ date = new Date();
+ firstName = randomParse("Bert|Ernie|Elmo|Zoe|Arthur|Emily|DJ|Grover|Oscar|Max|Big|Twinkle");
+ middleName = new StringBuffer(
+ randomParse("Rufus|Remy|Martin|Josephus|Ulysses|Homer|Bart|Tip|Onegin|Meredith|Jay"));
+ lastName = randomParse("Alejandro|Alexander|Bird|Gosling|Joy|Van Hoff|Pedia|Marr|McNealy|Ping");
+ address = randomParse("1|2|3|4") + randomParse("0|1|00|10|5|50") + randomParse("0|00|1|01|5|05|9|09||000") + " "
+ + randomParse("Merry|Berry|Perry|Jerry|Meadow|Falls|Elm|Raspberry|Strawberry") + " "
+ + randomParse("Road|Lane|Court|Drive|Parkway|Terrace");
+ city = randomParse("Springfield|Sterling|Cascades|Vienna|Reston|Paris|London|Runnymeade");
+ state = randomParse("TX|NJ|NY|VA|DC|MD|NC|SC|WV|AR|FL|CA|TN");
+ zip = ValueConverter.getIntValue(randomParse("1|2|3|4") + "0" + randomParse("0|1|2|3|5")
+ + randomParse("6|7|8|9") + randomParse("6|7|8|9"));
+ age = (short) (new Random().nextDouble() * 40 + 18);
childCount = -1;
// children = null;
- childList = null;
- }
-
- protected Date date;
- public Date getCreateDate() { return date; }
- public void setCreateDate( Date aDate ) { date = aDate; }
-
- protected String firstName;
- public String getFirstName() { return firstName; }
- public void setFirstName( String aName ) { firstName = aName; }
-
- protected String lastName;
- public String getLastName() { return lastName; }
- public void setLastName( String aName ) {
- if ( "Jones".equals( aName ) ) throw new RuntimeException( "Jones not allowed" ) ;
- lastName = aName;
- }
-
- protected StringBuffer middleName;
- public StringBuffer getMiddleName() { return middleName; }
- public void setMiddleName( StringBuffer aName ) { middleName = aName; }
-
- protected String address;
- public String getAddress() { return address; }
- public void setAddress( String anAddress ) { address = anAddress; }
-
- protected String city;
- public String getCity() { return city; }
- public void setCity( String aCity ) { city = aCity; }
-
- protected String state;
- public String getState() { return state; }
- public void setState( String aState ) { state = aState; }
-
- protected int zip;
- public int getZipCode() { return zip; }
- public void setZipCode( int aZipCode ) { zip = aZipCode; }
-
- protected short age;
- public short getAge() { return age; }
- public void setAge( short anAge ) { age = anAge; }
-
- protected boolean special;
- public Boolean isSpecial() { return new Boolean( special ); }
- public void setSpecial( Boolean isSpecial ) { special = isSpecial.booleanValue(); }
-
-/*
- protected Object[] children;
-
- private Object[] getChildren()
- {
- if ( children == null )
- {
- int n = getChildCount();
- children = new Object[ n ];
- for ( int i = 0; i < n; i++ )
- {
- children[i] = new TestObject();
- }
- //System.out.println( "TestObject.getChildren: " + toString() + " : " + getChildCount() );
- }
- return children;
- }
- private void setChildren( Object[] aChildArray )
- {
- children = aChildArray;
- childCount = aChildArray.length;
- }
-
- // following child list implementation wraps child array
-
- public List getChildList()
- {
- List result = new LinkedList();
- Object[] childArray = getChildren();
- for ( int i = 0; i < childArray.length; i++ )
- {
- result.add( childArray[i] );
- }
- return result;
+ childList = null;
}
- public void setChildList( List aChildList )
- {
- children = new Object[ aChildList.size() ];
- for ( int i = 0; i < children.length; i++ )
- {
- children[i] = (TestObject) aChildList.get( i );
- }
- childCount = children.length;
+
+ protected Date date;
+
+ public Date getCreateDate() {
+ return date;
+ }
+
+ public void setCreateDate(Date aDate) {
+ date = aDate;
+ }
+
+ protected String firstName;
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String aName) {
+ firstName = aName;
+ }
+
+ protected String lastName;
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String aName) {
+ if ("Jones".equals(aName))
+ throw new RuntimeException("Jones not allowed");
+ lastName = aName;
+ }
+
+ protected StringBuffer middleName;
+
+ public StringBuffer getMiddleName() {
+ return middleName;
+ }
+
+ public void setMiddleName(StringBuffer aName) {
+ middleName = aName;
+ }
+
+ protected String address;
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String anAddress) {
+ address = anAddress;
+ }
+
+ protected String city;
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String aCity) {
+ city = aCity;
+ }
+
+ protected String state;
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String aState) {
+ state = aState;
+ }
+
+ protected int zip;
+
+ public int getZipCode() {
+ return zip;
+ }
+
+ public void setZipCode(int aZipCode) {
+ zip = aZipCode;
+ }
+
+ protected short age;
+
+ public short getAge() {
+ return age;
+ }
+
+ public void setAge(short anAge) {
+ age = anAge;
+ }
+
+ protected boolean special;
+
+ public Boolean isSpecial() {
+ return new Boolean(special);
}
-*/
+
+ public void setSpecial(Boolean isSpecial) {
+ special = isSpecial.booleanValue();
+ }
+
+ /*
+ * protected Object[] children;
+ *
+ * private Object[] getChildren() { if ( children == null ) { int n =
+ * getChildCount(); children = new Object[ n ]; for ( int i = 0; i < n; i++ ) {
+ * children[i] = new TestObject(); } //System.out.println(
+ * "TestObject.getChildren: " + toString() + " : " + getChildCount() ); } return
+ * children; } private void setChildren( Object[] aChildArray ) { children =
+ * aChildArray; childCount = aChildArray.length; }
+ *
+ * // following child list implementation wraps child array
+ *
+ * public List getChildList() { List result = new LinkedList(); Object[]
+ * childArray = getChildren(); for ( int i = 0; i < childArray.length; i++ ) {
+ * result.add( childArray[i] ); } return result; } public void setChildList(
+ * List aChildList ) { children = new Object[ aChildList.size() ]; for ( int i =
+ * 0; i < children.length; i++ ) { children[i] = (TestObject) aChildList.get( i
+ * ); } childCount = children.length; }
+ */
protected int childCount;
- public int getChildCount()
- {
- if ( childCount == -1 )
- {
+
+ public int getChildCount() {
+ if (childCount == -1) {
// uncomment this to enable random children
// childCount = (int) ( random.nextDouble() * 6 ) - 3; // + 100; // tree scalability test
- if ( childCount < 0 ) childCount = 0;
+ if (childCount < 0)
+ childCount = 0;
}
-
+
// this tests internal count
// return childCount;
// this tests deferred count
- if ( childList != null )
- {
- return childList.size();
- }
- else
- {
- return 0;
- }
+ if (childList != null) {
+ return childList.size();
+ } else {
+ return 0;
+ }
};
- // following child list implementation stands alone
+ // following child list implementation stands alone
+
+ protected List childList;
- protected List childList;
- public List getChildList()
- {
-/*
- // this tests random child population
- if ( childList == null )
- {
- int n = getChildCount();
+ public List getChildList() {
+ /*
+ * // this tests random child population if ( childList == null ) { int n =
+ * getChildCount(); childList = new LinkedList(); for ( int i = 0; i < n; i++ )
+ * { childList.add( new TestObject() ); } }
+ */
+ // this tests manual loading
+ if (childList == null) {
childList = new LinkedList();
- for ( int i = 0; i < n; i++ )
- {
- childList.add( new TestObject() );
- }
- }
-*/
- // this tests manual loading
- if ( childList == null )
- {
- childList = new LinkedList();
}
return childList;
}
- public void setChildList( List aChildList )
- {
- childList = aChildList;
- }
-
- protected TestObject parent;
- public TestObject getParent() { return parent; }
- public void setParent( TestObject anObject ) { parent = anObject; }
-
- public String getHash() { return Integer.toHexString( System.identityHashCode( this ) ); }
-
- public String getFullName()
- {
+
+ public void setChildList(List aChildList) {
+ childList = aChildList;
+ }
+
+ protected TestObject parent;
+
+ public TestObject getParent() {
+ return parent;
+ }
+
+ public void setParent(TestObject anObject) {
+ parent = anObject;
+ }
+
+ public String getHash() {
+ return Integer.toHexString(System.identityHashCode(this));
+ }
+
+ public String getFullName() {
// return getHash() + ": " + firstName + " " + middleName + " " + lastName;
- return firstName + " " + middleName + " " + lastName;
- }
-
- public boolean equals( Object anObject )
- {
- return anObject == this;
- }
-
- public String toString()
- {
- return "[" + getClass().getName()
- + "@" + Integer.toHexString( System.identityHashCode(this) )
- + ":" + getFullName() + "]";
- }
-
- // statics
-
- private static Random random = new Random();
- private static String randomParse( String aString )
- {
- String result = "";
- StringTokenizer tokens = new StringTokenizer( aString, "|" );
- int n = (int) ( random.nextDouble() * tokens.countTokens() );
- for ( int i = 0; i <= n; i++ )
- {
- result = tokens.nextToken();
- }
- return result;
- }
-
-
- // interface EOKeyValueCoding:
- // disable this interface by commenting out the "implements" declaration
-
- /**
- * Returns the value for the specified property.
- * If the property does not exist, this method should
- * call handleQueryWithUnboundKey.
- */
- public Object valueForKey( String aKey )
- {
- System.out.println( "valueForKey: " + aKey );
- return EOKeyValueCodingSupport.valueForKey( this, aKey );
- }
-
- /**
- * Sets the property to the specified value.
- * If the property does not exist, this method should
- * call handleTakeValueForUnboundKey.
- * If the property is of a type that cannot allow
- * null (e.g. primitive types) and aValue is null,
- * this method should call unableToSetNullForKey.
- */
- public void takeValueForKey( Object aValue, String aKey )
- {
- System.out.println( "takeValueForKey: " + aValue + " : " + aKey );
- EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
- }
-
- /**
- * Returns the value for the private field that
- * corresponds to the specified property.
- */
- public Object storedValueForKey( String aKey )
- {
- System.out.println( "storedValueForKey: " + aKey );
- return EOKeyValueCodingSupport.storedValueForKey( this, aKey );
- }
-
- /**
- * Sets the the private field that corresponds to the
- * specified property to the specified value.
- */
- public void takeStoredValueForKey( Object aValue, String aKey )
- {
- System.out.println( "takeStoredValueForKey: " + aValue + " : " + aKey );
- EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
- }
-
- /**
- * Called by valueForKey when the specified key is
- * not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- public Object handleQueryWithUnboundKey( String aKey )
- {
- System.out.println( "handleQueryWithUnboundKey: " + aKey );
- return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- /**
- * Called by takeValueForKey when the specified key
- * is not found on this object. Implementing classes
- * should handle the specified value or otherwise
- * throw an exception.
- */
- public void handleTakeValueForUnboundKey( Object aValue, String aKey )
- {
- System.out.println( "handleTakeValueForUnboundKey: " + aValue + " : " + aKey );
- EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- /**
- * Called by takeValueForKey when the type of the
- * specified key is not allowed to be null, as is
- * the case with primitive types. Implementing
- * classes should handle this case appropriately
- * or otherwise throw an exception.
- */
- public void unableToSetNullForKey( String aKey )
- {
- System.out.println( "unableToSetNullForKey: " + aKey );
- EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
-
- // main entry point
-
- public static void main( String[] argv )
- {
- int count = 100;
- boolean xmlMode = false;
- if ( argv.length > 0 )
- {
- Integer parsed = ValueConverter.getInteger( argv[0] );
- if ( parsed != null ) count = parsed.intValue();
-
- if ( argv.length > 1 )
- {
- if ( argv[1].indexOf( "xml" ) > -1 )
- {
- xmlMode = true;
- }
- }
- }
-
-long millis = System.currentTimeMillis();
-
- DataSoup store = null;
- if ( xmlMode )
- {
- store = new XMLFileSoup( "testObjects-xml" );
- }
- else
- {
- store = new SerializedFileSoup( "testObjects-java" );
- }
-
- Object o;
- for ( int i = 0; i < count; i++ )
- {
- store.addObject( new TestObject() );
- }
- /*
- store.addIndex( "age", "age" );
- store.addIndex( "zipCode", "zipCode" );
- store.addIndex( "firstName", "firstName" );
- store.addIndex( "lastName", "lastName" );
-*/
-System.out.println( System.currentTimeMillis() - millis + " milliseconds" );
- }
+ return firstName + " " + middleName + " " + lastName;
+ }
+
+ public boolean equals(Object anObject) {
+ return anObject == this;
+ }
+
+ public String toString() {
+ return "[" + getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this)) + ":"
+ + getFullName() + "]";
+ }
+
+ // statics
+
+ private static Random random = new Random();
+
+ private static String randomParse(String aString) {
+ String result = "";
+ StringTokenizer tokens = new StringTokenizer(aString, "|");
+ int n = (int) (random.nextDouble() * tokens.countTokens());
+ for (int i = 0; i <= n; i++) {
+ result = tokens.nextToken();
+ }
+ return result;
+ }
+
+ // interface EOKeyValueCoding:
+ // disable this interface by commenting out the "implements" declaration
+
+ /**
+ * Returns the value for the specified property. If the property does not exist,
+ * this method should call handleQueryWithUnboundKey.
+ */
+ public Object valueForKey(String aKey) {
+ System.out.println("valueForKey: " + aKey);
+ return EOKeyValueCodingSupport.valueForKey(this, aKey);
+ }
+
+ /**
+ * Sets the property to the specified value. If the property does not exist,
+ * this method should call handleTakeValueForUnboundKey. If the property is of a
+ * type that cannot allow null (e.g. primitive types) and aValue is null, this
+ * method should call unableToSetNullForKey.
+ */
+ public void takeValueForKey(Object aValue, String aKey) {
+ System.out.println("takeValueForKey: " + aValue + " : " + aKey);
+ EOKeyValueCodingSupport.takeValueForKey(this, aValue, aKey);
+ }
+
+ /**
+ * Returns the value for the private field that corresponds to the specified
+ * property.
+ */
+ public Object storedValueForKey(String aKey) {
+ System.out.println("storedValueForKey: " + aKey);
+ return EOKeyValueCodingSupport.storedValueForKey(this, aKey);
+ }
+
+ /**
+ * Sets the the private field that corresponds to the specified property to the
+ * specified value.
+ */
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ System.out.println("takeStoredValueForKey: " + aValue + " : " + aKey);
+ EOKeyValueCodingSupport.takeStoredValueForKey(this, aValue, aKey);
+ }
+
+ /**
+ * Called by valueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ public Object handleQueryWithUnboundKey(String aKey) {
+ System.out.println("handleQueryWithUnboundKey: " + aKey);
+ return EOKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ /**
+ * Called by takeValueForKey when the specified key is not found on this object.
+ * Implementing classes should handle the specified value or otherwise throw an
+ * exception.
+ */
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ System.out.println("handleTakeValueForUnboundKey: " + aValue + " : " + aKey);
+ EOKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ /**
+ * Called by takeValueForKey when the type of the specified key is not allowed
+ * to be null, as is the case with primitive types. Implementing classes should
+ * handle this case appropriately or otherwise throw an exception.
+ */
+ public void unableToSetNullForKey(String aKey) {
+ System.out.println("unableToSetNullForKey: " + aKey);
+ EOKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ // main entry point
+
+ public static void main(String[] argv) {
+ int count = 100;
+ boolean xmlMode = false;
+ if (argv.length > 0) {
+ Integer parsed = ValueConverter.getInteger(argv[0]);
+ if (parsed != null)
+ count = parsed.intValue();
+
+ if (argv.length > 1) {
+ if (argv[1].indexOf("xml") > -1) {
+ xmlMode = true;
+ }
+ }
+ }
+
+ long millis = System.currentTimeMillis();
+
+ DataSoup store = null;
+ if (xmlMode) {
+ store = new XMLFileSoup("testObjects-xml");
+ } else {
+ store = new SerializedFileSoup("testObjects-java");
+ }
+
+ Object o;
+ for (int i = 0; i < count; i++) {
+ store.addObject(new TestObject());
+ }
+ /*
+ * store.addIndex( "age", "age" ); store.addIndex( "zipCode", "zipCode" );
+ * store.addIndex( "firstName", "firstName" ); store.addIndex( "lastName",
+ * "lastName" );
+ */
+ System.out.println(System.currentTimeMillis() - millis + " milliseconds");
+ }
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectClassDesc.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectClassDesc.java
index beb852c..409d900 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectClassDesc.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectClassDesc.java
@@ -4,28 +4,22 @@ import net.wotonomy.control.EOClassDescription;
import net.wotonomy.foundation.NSArray;
/**
-* A simple class description for testing.
-*/
-public class TestObjectClassDesc extends EOClassDescription
-{
- public TestObjectClassDesc()
- {
- super( TestObject.class );
- }
+ * A simple class description for testing.
+ */
+public class TestObjectClassDesc extends EOClassDescription {
+ public TestObjectClassDesc() {
+ super(TestObject.class);
+ }
- public EOClassDescription classDescriptionForDestinationKey(
- String detailKey )
- {
- if ( "childList".equals( detailKey ) )
- {
- return this;
- }
- return null;
- }
-
- public NSArray toManyRelationshipKeys()
- {
- return new NSArray( "childList" );
- }
+ public EOClassDescription classDescriptionForDestinationKey(String detailKey) {
+ if ("childList".equals(detailKey)) {
+ return this;
+ }
+ return null;
+ }
+
+ public NSArray toManyRelationshipKeys() {
+ return new NSArray("childList");
+ }
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectStore.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectStore.java
index 8fcb8a0..316fcf7 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectStore.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestObjectStore.java
@@ -19,240 +19,177 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* An object store that wraps a datastore
-* for vending test objects.
-*/
-public class TestObjectStore extends EOObjectStore
-{
- DataSoup soup;
-
- /**
- * Constructor specifies path to datastore.
- */
- public TestObjectStore( String aPath )
- {
- soup = new XMLFileSoup( aPath );
- }
-
- /**
- * This implementation simply returns
- * objectsWithSourceGlobalID.
- */
- public NSArray arrayFaultWithSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext )
- {
- return objectsForSourceGlobalID(
- aGlobalID, aRelationship, aContext );
- }
-
- /**
- * This implementation returns the actual
- * object for the specified id.
- */
- public Object faultForGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
-System.out.println( "TestObjectStore: * reading object * : " + aGlobalID );
- return soup.getObjectByKey(
- ((DataKeyID)aGlobalID).getKey() );
- }
-
- /**
- * Returns a fault representing an object of
- * the specified entity type with values from
- * the specified dictionary. The fault should
- * belong to the specified editing context.
- */
- public Object faultForRawRow (
- Map aDictionary,
- String anEntityName,
- EOEditingContext aContext )
- {
- //TODO: faults are not yet supported
- throw new WotonomyException(
- "Faults are not yet supported." );
- }
-
- /**
- * Given a newly instantiated object, this method
- * initializes its properties to values appropriate
- * for the specified id. The object should belong
- * to the specified editing context.
- * This method is called to populate faults.
- */
- public void initializeObject (
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
-System.out.println( "TestObjectStore: * reading object * : " + aGlobalID );
- Object original = soup.getObjectByKey(
- ((DataKeyID)aGlobalID).getKey() );
- EOObserverCenter.notifyObserversObjectWillChange( anObject );
- Duplicator.deepCopy( original, anObject );
- //TODO: need to handle child object registration in aContext
- }
-
- /**
- * Remove all values from all objects in memory,
- * turning them into faults, and posts a notification
- * that all objects have been invalidated.
- */
- public void invalidateAllObjects ()
- {
- // does nothing
- }
-
- /**
- * Removes values with the specified ids from memory,
- * turning them into faults, and posts a notification
- * that those objects have been invalidated.
- */
- public void invalidateObjectsWithGlobalIDs (
- List aList )
- {
- // does nothing
- }
-
- /**
- * Returns false because locking is not permitted.
- */
- public boolean isObjectLockedWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- return false;
- }
-
- /**
- * Does nothing because locking is not permitted.
- */
- public void lockObjectWithGlobalID (
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- // does nothing
- }
-
- /**
- * Returns a List of objects associated with the object
- * with the specified id for the specified property
- * relationship. Faults are not allowed in the array.
- * All objects should belong to the specified editing context.
- */
- public NSArray objectsForSourceGlobalID (
- EOGlobalID aGlobalID,
- String aRelationship,
- EOEditingContext aContext )
- {
- //TODO: relationships are not yet supported
- throw new WotonomyException(
- "Relationships are not yet supported." );
- }
-
- /**
- * Returns a List of objects the meet the criteria of
- * the supplied specification. Faults are not allowed in the array.
- * Each object is registered with the specified editing context.
- * If any object is already registered in the specified context,
- * it is not refetched and that object should be used in the array.
- */
- public NSArray objectsWithFetchSpecification (
- EOFetchSpecification aFetchSpec,
- EOEditingContext aContext )
- {
- //TODO: fetch specs are not yet supported
-
- DataView view = soup.queryObjects( null, null );
-System.out.println( "TestObjectStore: ** querying all objects **" );
- NSMutableArray result = new NSMutableArray();
- Object o;
- Object existing;
- DataKeyID id;
- Iterator it = view.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- id = new DataKeyID( view.getKeyForObject( o ) );
- existing = aContext.objectForGlobalID( id );
- if ( existing != null )
- {
- o = existing;
- }
- else
- {
- aContext.recordObject( o, id );
- }
- result.addObject( o );
- }
- return result;
- }
-
- /**
- * Removes all values from the specified object,
- * converting it into a fault for the specified id.
- * New or deleted objects should not be refaulted.
- */
- public void refaultObject (
- Object anObject,
- EOGlobalID aGlobalID,
- EOEditingContext aContext )
- {
- //TODO: faults are not yet supported
- // just re-initialize the object
- initializeObject( anObject, aGlobalID, aContext );
- }
-
- /**
- * Writes all changes in the specified editing context
- * to the respository.
- */
- public void saveChangesInEditingContext (
- EOEditingContext aContext )
- {
- Object o;
- DataKeyID id;
- Iterator it;
-
- System.out.println( aContext.updatedObjects() );
-
- // process updates
- it = aContext.updatedObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- id = (DataKeyID) aContext.globalIDForObject( o );
-System.out.println( "TestObjectStore: * updating object * : " + id );
- soup.updateObject( id.getKey(), o );
- }
-
- // process deletes
- it = aContext.deletedObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- id = (DataKeyID) aContext.globalIDForObject( o );
-System.out.println( "TestObjectStore: * deleting object * : " + id );
- soup.removeObject( id.getKey() );
- // remove object from editing context
- aContext.forgetObject( o );
- }
-
- // process inserts
- it = aContext.insertedObjects().iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- id = new DataKeyID( soup.addObject( o ) );
-System.out.println( "TestObjectStore: * adding object * : " + id );
- // register object in editing context with new id
- aContext.forgetObject( o );
- aContext.recordObject( o, id );
- }
-
- }
-}
+ * An object store that wraps a datastore for vending test objects.
+ */
+public class TestObjectStore extends EOObjectStore {
+ DataSoup soup;
+
+ /**
+ * Constructor specifies path to datastore.
+ */
+ public TestObjectStore(String aPath) {
+ soup = new XMLFileSoup(aPath);
+ }
+
+ /**
+ * This implementation simply returns objectsWithSourceGlobalID.
+ */
+ public NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) {
+ return objectsForSourceGlobalID(aGlobalID, aRelationship, aContext);
+ }
+
+ /**
+ * This implementation returns the actual object for the specified id.
+ */
+ public Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ System.out.println("TestObjectStore: * reading object * : " + aGlobalID);
+ return soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
+ }
+
+ /**
+ * Returns a fault representing an object of the specified entity type with
+ * values from the specified dictionary. The fault should belong to the
+ * specified editing context.
+ */
+ public Object faultForRawRow(Map aDictionary, String anEntityName, EOEditingContext aContext) {
+ // TODO: faults are not yet supported
+ throw new WotonomyException("Faults are not yet supported.");
+ }
+
+ /**
+ * Given a newly instantiated object, this method initializes its properties to
+ * values appropriate for the specified id. The object should belong to the
+ * specified editing context. This method is called to populate faults.
+ */
+ public void initializeObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ System.out.println("TestObjectStore: * reading object * : " + aGlobalID);
+ Object original = soup.getObjectByKey(((DataKeyID) aGlobalID).getKey());
+ EOObserverCenter.notifyObserversObjectWillChange(anObject);
+ Duplicator.deepCopy(original, anObject);
+ // TODO: need to handle child object registration in aContext
+ }
+
+ /**
+ * Remove all values from all objects in memory, turning them into faults, and
+ * posts a notification that all objects have been invalidated.
+ */
+ public void invalidateAllObjects() {
+ // does nothing
+ }
+
+ /**
+ * Removes values with the specified ids from memory, turning them into faults,
+ * and posts a notification that those objects have been invalidated.
+ */
+ public void invalidateObjectsWithGlobalIDs(List aList) {
+ // does nothing
+ }
+
+ /**
+ * Returns false because locking is not permitted.
+ */
+ public boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ return false;
+ }
+
+ /**
+ * Does nothing because locking is not permitted.
+ */
+ public void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) {
+ // does nothing
+ }
+ /**
+ * Returns a List of objects associated with the object with the specified id
+ * for the specified property relationship. Faults are not allowed in the array.
+ * All objects should belong to the specified editing context.
+ */
+ public NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) {
+ // TODO: relationships are not yet supported
+ throw new WotonomyException("Relationships are not yet supported.");
+ }
+
+ /**
+ * Returns a List of objects the meet the criteria of the supplied
+ * specification. Faults are not allowed in the array. Each object is registered
+ * with the specified editing context. If any object is already registered in
+ * the specified context, it is not refetched and that object should be used in
+ * the array.
+ */
+ public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext) {
+ // TODO: fetch specs are not yet supported
+
+ DataView view = soup.queryObjects(null, null);
+ System.out.println("TestObjectStore: ** querying all objects **");
+ NSMutableArray result = new NSMutableArray();
+ Object o;
+ Object existing;
+ DataKeyID id;
+ Iterator it = view.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ id = new DataKeyID(view.getKeyForObject(o));
+ existing = aContext.objectForGlobalID(id);
+ if (existing != null) {
+ o = existing;
+ } else {
+ aContext.recordObject(o, id);
+ }
+ result.addObject(o);
+ }
+ return result;
+ }
+
+ /**
+ * Removes all values from the specified object, converting it into a fault for
+ * the specified id. New or deleted objects should not be refaulted.
+ */
+ public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) {
+ // TODO: faults are not yet supported
+ // just re-initialize the object
+ initializeObject(anObject, aGlobalID, aContext);
+ }
+
+ /**
+ * Writes all changes in the specified editing context to the respository.
+ */
+ public void saveChangesInEditingContext(EOEditingContext aContext) {
+ Object o;
+ DataKeyID id;
+ Iterator it;
+
+ System.out.println(aContext.updatedObjects());
+
+ // process updates
+ it = aContext.updatedObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ id = (DataKeyID) aContext.globalIDForObject(o);
+ System.out.println("TestObjectStore: * updating object * : " + id);
+ soup.updateObject(id.getKey(), o);
+ }
+
+ // process deletes
+ it = aContext.deletedObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ id = (DataKeyID) aContext.globalIDForObject(o);
+ System.out.println("TestObjectStore: * deleting object * : " + id);
+ soup.removeObject(id.getKey());
+ // remove object from editing context
+ aContext.forgetObject(o);
+ }
+
+ // process inserts
+ it = aContext.insertedObjects().iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ id = new DataKeyID(soup.addObject(o));
+ System.out.println("TestObjectStore: * adding object * : " + id);
+ // register object in editing context with new id
+ aContext.forgetObject(o);
+ aContext.recordObject(o, id);
+ }
+
+ }
+}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestPanel.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestPanel.java
index 7e868d0..78eedb6 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestPanel.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TestPanel.java
@@ -20,14 +20,12 @@ import net.wotonomy.ui.swing.components.ButtonPanel;
import net.wotonomy.ui.swing.components.InfoPanel;
/**
-* A master-detail panel with a list, some
-* textfields and some buttons.
-*/
-public class TestPanel extends JPanel
-{
+ * A master-detail panel with a list, some textfields and some buttons.
+ */
+public class TestPanel extends JPanel {
// public JList list;
public JTable table;
- public InfoPanel infoPanel;
+ public InfoPanel infoPanel;
public ButtonPanel savePanel;
public ButtonPanel buttonPanel;
public JTextComponent firstNameField;
@@ -35,76 +33,73 @@ public class TestPanel extends JPanel
public JComboBox dateBox, monthBox, yearBox;
public JSlider slider;
public JCheckBox checkbox;
-
- public TestPanel()
- {
- this.setLayout( new BorderLayout( 10, 10 ) );
- this.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
-
- JPanel overviewPanel = new JPanel();
- overviewPanel.setLayout( new BorderLayout() );
-
- //list = new JList();
- //JScrollPane scrollPane = new JScrollPane( list );
+
+ public TestPanel() {
+ this.setLayout(new BorderLayout(10, 10));
+ this.setBorder(new EmptyBorder(10, 10, 10, 10));
+
+ JPanel overviewPanel = new JPanel();
+ overviewPanel.setLayout(new BorderLayout());
+
+ // list = new JList();
+ // JScrollPane scrollPane = new JScrollPane( list );
table = new JTable();
- JScrollPane scrollPane = new JScrollPane( table );
-
- overviewPanel.add( scrollPane, BorderLayout.CENTER );
-
- this.add( overviewPanel, BorderLayout.CENTER );
-
- infoPanel = new InfoPanel();
- infoPanel.setColumns( 1 );
+ JScrollPane scrollPane = new JScrollPane(table);
+
+ overviewPanel.add(scrollPane, BorderLayout.CENTER);
+
+ this.add(overviewPanel, BorderLayout.CENTER);
+
+ infoPanel = new InfoPanel();
+ infoPanel.setColumns(1);
// name fields
- firstNameField = new JTextField();
+ firstNameField = new JTextField();
// infoPanel.addPair( "First Name", firstNameField );
middleNameField = new JTextField();
// infoPanel.addPair( "Middle Name", middleNameField );
lastNameField = new JTextField();
// infoPanel.addPair( "Last Name", lastNameField );
- checkbox = new JCheckBox();
+ checkbox = new JCheckBox();
+
+ infoPanel.addRow("Name", new Component[] { firstNameField, middleNameField, lastNameField, checkbox });
- infoPanel.addRow( "Name", new Component[] {
- firstNameField, middleNameField, lastNameField, checkbox } );
-
// date comboboxen
Vector datesList = new Vector();
- for ( int i = 1; i < 32; i++ ) datesList.add( new Integer( i ) );
- dateBox = new JComboBox( datesList );
- dateBox.setEditable( true );
+ for (int i = 1; i < 32; i++)
+ datesList.add(new Integer(i));
+ dateBox = new JComboBox(datesList);
+ dateBox.setEditable(true);
monthBox = new JComboBox();
yearBox = new JComboBox();
- infoPanel.addRow( "Create Date",
- dateBox, monthBox, yearBox );
-
+ infoPanel.addRow("Create Date", dateBox, monthBox, yearBox);
+
// year slider
- infoPanel.addRow( "Day of Month", slider = new JSlider(
- JSlider.HORIZONTAL, 1, 31, 1 ) );
-
+ infoPanel.addRow("Day of Month", slider = new JSlider(JSlider.HORIZONTAL, 1, 31, 1));
+
// navigation buttons
-
- JPanel navigationPanel = new JPanel();
- navigationPanel.setLayout( new BorderLayout() );
-
- buttonPanel = new ButtonPanel( new String[] { "Tree View", "Add", "Remove" } );
- buttonPanel.setAlignment( BetterFlowLayout.LEFT );
- buttonPanel.setInsets( new Insets( 0, 0, 0, 0 ) );
- navigationPanel.add( buttonPanel, BorderLayout.WEST );
-
- savePanel = new ButtonPanel( new String[] { "Refresh All", "Commit" } );
- savePanel.setAlignment( BetterFlowLayout.RIGHT );
- navigationPanel.add( savePanel, BorderLayout.EAST );
-
- // bottom panel layout
-
- JPanel bottomPanel = new JPanel();
- bottomPanel.setLayout( new BorderLayout() );
- bottomPanel.add( infoPanel, BorderLayout.NORTH );
- bottomPanel.add( navigationPanel, BorderLayout.SOUTH );
-
- this.add( bottomPanel, BorderLayout.SOUTH );
- }
-
+
+ JPanel navigationPanel = new JPanel();
+ navigationPanel.setLayout(new BorderLayout());
+
+ buttonPanel = new ButtonPanel(new String[] { "Tree View", "Add", "Remove" });
+ buttonPanel.setAlignment(BetterFlowLayout.LEFT);
+ buttonPanel.setInsets(new Insets(0, 0, 0, 0));
+ navigationPanel.add(buttonPanel, BorderLayout.WEST);
+
+ savePanel = new ButtonPanel(new String[] { "Refresh All", "Commit" });
+ savePanel.setAlignment(BetterFlowLayout.RIGHT);
+ navigationPanel.add(savePanel, BorderLayout.EAST);
+
+ // bottom panel layout
+
+ JPanel bottomPanel = new JPanel();
+ bottomPanel.setLayout(new BorderLayout());
+ bottomPanel.add(infoPanel, BorderLayout.NORTH);
+ bottomPanel.add(navigationPanel, BorderLayout.SOUTH);
+
+ this.add(bottomPanel, BorderLayout.SOUTH);
+ }
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeController.java
index d61d8ff..c5f596b 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeController.java
@@ -27,259 +27,203 @@ import net.wotonomy.ui.swing.util.ObjectInspector;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* A simple editor panel with a few textfields.
-*/
-public class TreeController implements ActionListener
-{
- final EODisplayGroup group;
- final EODisplayGroup titlesGroup;
- final EODisplayGroup detailGroup;
- final EOEditingContext editingContext;
-
- public TreeController( EODataSource aDataSource )
- {
- titlesGroup = new EODisplayGroup();
- group = new EODisplayGroup();
- detailGroup = new EODisplayGroup();
- titlesGroup.setDataSource( aDataSource );
- editingContext = aDataSource.editingContext();
- init();
- }
-
- public TreeController( EOEditingContext aContext,
- EODisplayGroup aTitlesGroup, EODisplayGroup aChildGroup )
- {
- titlesGroup = aTitlesGroup;
- group = aChildGroup;
- detailGroup = new EODisplayGroup();
- editingContext = aContext;
- init();
- }
-
- public void init()
- {
+ * A simple editor panel with a few textfields.
+ */
+public class TreeController implements ActionListener {
+ final EODisplayGroup group;
+ final EODisplayGroup titlesGroup;
+ final EODisplayGroup detailGroup;
+ final EOEditingContext editingContext;
+
+ public TreeController(EODataSource aDataSource) {
+ titlesGroup = new EODisplayGroup();
+ group = new EODisplayGroup();
+ detailGroup = new EODisplayGroup();
+ titlesGroup.setDataSource(aDataSource);
+ editingContext = aDataSource.editingContext();
+ init();
+ }
+
+ public TreeController(EOEditingContext aContext, EODisplayGroup aTitlesGroup, EODisplayGroup aChildGroup) {
+ titlesGroup = aTitlesGroup;
+ group = aChildGroup;
+ detailGroup = new EODisplayGroup();
+ editingContext = aContext;
+ init();
+ }
+
+ public void init() {
final TreePanel treePanel = new TreePanel();
- treePanel.panel.setBorder(
- BorderFactory.createCompoundBorder(
- BorderFactory.createRaisedBevelBorder(),
- BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ) );
- treePanel.setBorder(
- BorderFactory.createEmptyBorder( 0, 0, 0, 0 ) );
- ButtonPanel okPanel = new ButtonPanel(
- new String[] { "Refresh", "Commit" } );
- treePanel.add( okPanel, BorderLayout.SOUTH );
-/*
-
- // set up renderer
- IconCellRenderer iconRenderer = new IconCellRenderer()
- {
- private Icon icon = UIManager.getIcon("FileChooser.homeFolderIcon");
- public Icon getIconForContext(
- JComponent container, Object value,
- int row, int col,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- return icon;
- }
- };
- treePanel.tree.setCellRenderer( iconRenderer );
-
- // enable icon clicking
- treePanel.tree.setCellEditor( iconRenderer );
- iconRenderer.addActionListener( this );
-*/
-
- treePanel.tree.setEditable( true );
-
- // set up display groups
-
- titlesGroup.fetch();
+ treePanel.panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
+ BorderFactory.createEmptyBorder(10, 10, 10, 10)));
+ treePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+ ButtonPanel okPanel = new ButtonPanel(new String[] { "Refresh", "Commit" });
+ treePanel.add(okPanel, BorderLayout.SOUTH);
+ /*
+ *
+ * // set up renderer IconCellRenderer iconRenderer = new IconCellRenderer() {
+ * private Icon icon = UIManager.getIcon("FileChooser.homeFolderIcon"); public
+ * Icon getIconForContext( JComponent container, Object value, int row, int col,
+ * boolean isSelected, boolean hasFocus, boolean isExpanded, boolean isLeaf ) {
+ * return icon; } }; treePanel.tree.setCellRenderer( iconRenderer );
+ *
+ * // enable icon clicking treePanel.tree.setCellEditor( iconRenderer );
+ * iconRenderer.addActionListener( this );
+ */
+
+ treePanel.tree.setEditable(true);
+
+ // set up display groups
+
+ titlesGroup.fetch();
// text associations
EOAssociation ta;
-
- ta = new TreeAssociation( treePanel.tree, "People" );
- ta.bindAspect( EOAssociation.TitlesAspect, titlesGroup, "fullName" );
- ta.bindAspect( EOAssociation.ChildrenAspect, group, "childList" );
- ta.bindAspect( EOAssociation.IsLeafAspect, titlesGroup, "childCount" );
+
+ ta = new TreeAssociation(treePanel.tree, "People");
+ ta.bindAspect(EOAssociation.TitlesAspect, titlesGroup, "fullName");
+ ta.bindAspect(EOAssociation.ChildrenAspect, group, "childList");
+ ta.bindAspect(EOAssociation.IsLeafAspect, titlesGroup, "childCount");
// ta.bindAspect( EOAssociation.IsLeafAspect, null, "false" );
ta.establishConnection();
- treePanel.tree.setEditable( true );
-
- ta = new TextAssociation( treePanel.editPanel.firstNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "firstName" );
+ treePanel.tree.setEditable(true);
+
+ ta = new TextAssociation(treePanel.editPanel.firstNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "firstName");
ta.establishConnection();
-
- ta = new TextAssociation( treePanel.editPanel.middleNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "middleName" );
+
+ ta = new TextAssociation(treePanel.editPanel.middleNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "middleName");
ta.establishConnection();
-
- ta = new TextAssociation( treePanel.editPanel.lastNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "lastName" );
+
+ ta = new TextAssociation(treePanel.editPanel.lastNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "lastName");
ta.establishConnection();
- ta = new RadioPanelAssociation( treePanel.editPanel.yearRadioPanel );
- ta.bindAspect( EOAssociation.ValueAspect, group, "createDate.year" );
-
+ ta = new RadioPanelAssociation(treePanel.editPanel.yearRadioPanel);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "createDate.year");
+
EODisplayGroup yearTitles = new EODisplayGroup();
- yearTitles.setObjectArray( new NSArray(
- new Object[] { "1999", "2000", "2001" } ) );
- ta.bindAspect( EOAssociation.TitlesAspect, yearTitles, "" );
-
+ yearTitles.setObjectArray(new NSArray(new Object[] { "1999", "2000", "2001" }));
+ ta.bindAspect(EOAssociation.TitlesAspect, yearTitles, "");
+
EODisplayGroup yearObjects = new EODisplayGroup();
- yearObjects.setObjectArray( new NSArray(
- new Object[] { new Integer( 99 ), new Integer( 100 ), new Integer( 101 ) } ) );
- ta.bindAspect( EOAssociation.ObjectsAspect, yearObjects, "" );
-
+ yearObjects.setObjectArray(new NSArray(new Object[] { new Integer(99), new Integer(100), new Integer(101) }));
+ ta.bindAspect(EOAssociation.ObjectsAspect, yearObjects, "");
+
ta.establishConnection();
// detail group
-
- ta = new MasterDetailAssociation( detailGroup );
- ta.bindAspect( EOAssociation.ParentAspect, group, "childList" );
+
+ ta = new MasterDetailAssociation(detailGroup);
+ ta.bindAspect(EOAssociation.ParentAspect, group, "childList");
ta.establishConnection();
-
- ta = new ListAssociation( treePanel.editPanel.list );
- ta.bindAspect( EOAssociation.TitlesAspect, detailGroup, "fullName" );
+
+ ta = new ListAssociation(treePanel.editPanel.list);
+ ta.bindAspect(EOAssociation.TitlesAspect, detailGroup, "fullName");
ta.establishConnection();
-
+
// display group action associations
- AbstractButton addButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Add" );
- addButton.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- Object testObject = new TestObject();
- editingContext.insertObject( testObject );
- detailGroup.insertObjectAtIndex( testObject, 0 );
+ AbstractButton addButton = (AbstractButton) treePanel.editPanel.addPanel.getButton("Add");
+ addButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ Object testObject = new TestObject();
+ editingContext.insertObject(testObject);
+ detailGroup.insertObjectAtIndex(testObject, 0);
}
- } );
-
- AbstractButton removeButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Remove" );
- removeButton.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- if ( detailGroup.selectedObject() != null )
- detailGroup.deleteSelection();
+ });
+
+ AbstractButton removeButton = (AbstractButton) treePanel.editPanel.addPanel.getButton("Remove");
+ removeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ if (detailGroup.selectedObject() != null)
+ detailGroup.deleteSelection();
}
- } );
-
- // ok / cancel buttons
-
- AbstractButton button;
-
- button = (AbstractButton)
- okPanel.getButton( "Commit" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- editingContext.saveChanges();
+ });
+
+ // ok / cancel buttons
+
+ AbstractButton button;
+
+ button = (AbstractButton) okPanel.getButton("Commit");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ editingContext.saveChanges();
}
- } );
-
- button = (AbstractButton)
- okPanel.getButton( "Refresh" );
- button.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- editingContext.revert();
+ });
+
+ button = (AbstractButton) okPanel.getButton("Refresh");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ editingContext.revert();
// editingContext.invalidateAllObjects();
}
- } );
-
-
-/*
- AbstractButton refreshButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Refresh" );
- refreshButton.addActionListener( new ActionListener()
- {
- int count = 0;
- public void actionPerformed( ActionEvent evt )
- {
- EODisplayGroup displayGroup = (EODisplayGroup)
- treePanel.tree.getSelectionPath().getLastPathComponent();
-// displayGroup.insertObjectAtIndex( new TestObject(), 0 );
-// displayGroup.deleteObjectAtIndex( 0 );
- List sortOrderings = new LinkedList();
- if ( count++ % 2 == 0 )
- {
- sortOrderings.add( new EOSortOrdering(
- "lastName", EOSortOrdering.CompareAscending ) );
- }
- else
- {
- sortOrderings.add( new EOSortOrdering(
- "lastName", EOSortOrdering.CompareDescending ) );
- }
- displayGroup.setSortOrderings( sortOrderings );
- displayGroup.updateDisplayedObjects();
- }
- } );
-*/
-/*
- ta = new DisplayGroupActionAssociation(
- treePanel.editPanel.addPanel.getButton( "Remove" ) );
- ta.bindAspect( EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
- ta.establishConnection();
-
- ta = new DisplayGroupActionAssociation(
- treePanel.editPanel.addPanel.getButton( "Refresh" ) );
- ta.bindAspect( EOAssociation.ActionAspect, group, "updateDisplayedObjects" );
- ta.establishConnection();
-*/
+ });
+
+ /*
+ * AbstractButton refreshButton = (AbstractButton)
+ * treePanel.editPanel.addPanel.getButton( "Refresh" );
+ * refreshButton.addActionListener( new ActionListener() { int count = 0; public
+ * void actionPerformed( ActionEvent evt ) { EODisplayGroup displayGroup =
+ * (EODisplayGroup) treePanel.tree.getSelectionPath().getLastPathComponent(); //
+ * displayGroup.insertObjectAtIndex( new TestObject(), 0 ); //
+ * displayGroup.deleteObjectAtIndex( 0 ); List sortOrderings = new LinkedList();
+ * if ( count++ % 2 == 0 ) { sortOrderings.add( new EOSortOrdering( "lastName",
+ * EOSortOrdering.CompareAscending ) ); } else { sortOrderings.add( new
+ * EOSortOrdering( "lastName", EOSortOrdering.CompareDescending ) ); }
+ * displayGroup.setSortOrderings( sortOrderings );
+ * displayGroup.updateDisplayedObjects(); } } );
+ */
+ /*
+ * ta = new DisplayGroupActionAssociation(
+ * treePanel.editPanel.addPanel.getButton( "Remove" ) ); ta.bindAspect(
+ * EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
+ * ta.establishConnection();
+ *
+ * ta = new DisplayGroupActionAssociation(
+ * treePanel.editPanel.addPanel.getButton( "Refresh" ) ); ta.bindAspect(
+ * EOAssociation.ActionAspect, group, "updateDisplayedObjects" );
+ * ta.establishConnection();
+ */
// add mouse listener for list
-
- treePanel.editPanel.list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getClickCount() == 2 )
- {
+
+ treePanel.editPanel.list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
Object item = detailGroup.selectedObject();
- if ( item != null )
- {
- new InspectorController( item );
- }
+ if (item != null) {
+ new InspectorController(item);
+ }
}
}
});
// launch
-
+
JDialog d = new JDialog();
- d.getContentPane().add( treePanel );
- d.setTitle( "Tree Panel" );
+ d.getContentPane().add(treePanel);
+ d.setTitle("Tree Panel");
d.pack();
- WindowUtilities.cascade( d );
+ WindowUtilities.cascade(d);
d.show();
- // workaround for memory issues on jdk1.2.2
- d.addWindowListener( new WindowAdapter()
- {
+ // workaround for memory issues on jdk1.2.2
+ d.addWindowListener(new WindowAdapter() {
// exit on close
- public void windowClosing(WindowEvent e)
- {
- ((JDialog)e.getWindow()).getContentPane().removeAll();
+ public void windowClosing(WindowEvent e) {
+ ((JDialog) e.getWindow()).getContentPane().removeAll();
}
});
}
-
- public void actionPerformed( ActionEvent evt )
- {
- Object item = group.selectedObject();
- if ( item != null )
- {
+
+ public void actionPerformed(ActionEvent evt) {
+ Object item = group.selectedObject();
+ if (item != null) {
// new InspectorController( item );
- new ObjectInspector( item );
- }
- }
-
+ new ObjectInspector(item);
+ }
+ }
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeInspectorController.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeInspectorController.java
index 8ec9554..1695103 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeInspectorController.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreeInspectorController.java
@@ -21,164 +21,134 @@ import net.wotonomy.ui.swing.TreeAssociation;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* A simple editor panel with a few textfields.
-*/
-public class TreeInspectorController
-{
- public TreeInspectorController( EODisplayGroup titlesGroup, EODisplayGroup childrenGroup )
- {
- final EODisplayGroup group = childrenGroup;
+ * A simple editor panel with a few textfields.
+ */
+public class TreeInspectorController {
+ public TreeInspectorController(EODisplayGroup titlesGroup, EODisplayGroup childrenGroup) {
+ final EODisplayGroup group = childrenGroup;
// final EODisplayGroup group = titlesGroup;
final TreePanel treePanel = new TreePanel();
-
+
// text associations
-
+
EOAssociation ta;
-
- ta = new TreeAssociation( treePanel.tree, "People" );
- ta.bindAspect( EOAssociation.TitlesAspect, titlesGroup, "lastName" );
- ta.bindAspect( EOAssociation.ChildrenAspect, group, "childList" );
- ta.bindAspect( EOAssociation.IsLeafAspect, titlesGroup, "childCount" );
+
+ ta = new TreeAssociation(treePanel.tree, "People");
+ ta.bindAspect(EOAssociation.TitlesAspect, titlesGroup, "lastName");
+ ta.bindAspect(EOAssociation.ChildrenAspect, group, "childList");
+ ta.bindAspect(EOAssociation.IsLeafAspect, titlesGroup, "childCount");
// ta.bindAspect( EOAssociation.IsLeafAspect, null, "false" );
ta.establishConnection();
- treePanel.tree.setEditable( true );
-
- ta = new TextAssociation( treePanel.editPanel.firstNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "firstName" );
+ treePanel.tree.setEditable(true);
+
+ ta = new TextAssociation(treePanel.editPanel.firstNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "firstName");
ta.establishConnection();
-
- ta = new TextAssociation( treePanel.editPanel.middleNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "middleName" );
+
+ ta = new TextAssociation(treePanel.editPanel.middleNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "middleName");
ta.establishConnection();
-
- ta = new TextAssociation( treePanel.editPanel.lastNameField );
- ta.bindAspect( EOAssociation.ValueAspect, group, "lastName" );
+
+ ta = new TextAssociation(treePanel.editPanel.lastNameField);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "lastName");
ta.establishConnection();
- ta = new RadioPanelAssociation( treePanel.editPanel.yearRadioPanel );
- ta.bindAspect( EOAssociation.ValueAspect, group, "createDate.year" );
-
+ ta = new RadioPanelAssociation(treePanel.editPanel.yearRadioPanel);
+ ta.bindAspect(EOAssociation.ValueAspect, group, "createDate.year");
+
EODisplayGroup yearTitles = new EODisplayGroup();
- yearTitles.setObjectArray( new NSArray(
- new Object[] { "1999", "2000", "2001" } ) );
- ta.bindAspect( EOAssociation.TitlesAspect, yearTitles, "" );
-
+ yearTitles.setObjectArray(new NSArray(new Object[] { "1999", "2000", "2001" }));
+ ta.bindAspect(EOAssociation.TitlesAspect, yearTitles, "");
+
EODisplayGroup yearObjects = new EODisplayGroup();
- yearObjects.setObjectArray( new NSArray(
- new Object[] { new Integer( 99 ), new Integer( 100 ), new Integer( 101 ) } ) );
- ta.bindAspect( EOAssociation.ObjectsAspect, yearObjects, "" );
-
+ yearObjects.setObjectArray(new NSArray(new Object[] { new Integer(99), new Integer(100), new Integer(101) }));
+ ta.bindAspect(EOAssociation.ObjectsAspect, yearObjects, "");
+
ta.establishConnection();
// detail group
-
+
final EODisplayGroup detailGroup = new EODisplayGroup();
-
- ta = new MasterDetailAssociation( detailGroup );
- ta.bindAspect( EOAssociation.ParentAspect, group, "childList" );
+
+ ta = new MasterDetailAssociation(detailGroup);
+ ta.bindAspect(EOAssociation.ParentAspect, group, "childList");
ta.establishConnection();
-
- ta = new ListAssociation( treePanel.editPanel.list );
- ta.bindAspect( EOAssociation.TitlesAspect, detailGroup, "fullName" );
+
+ ta = new ListAssociation(treePanel.editPanel.list);
+ ta.bindAspect(EOAssociation.TitlesAspect, detailGroup, "fullName");
ta.establishConnection();
-
+
// display group action associations
- AbstractButton addButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Add" );
- addButton.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- detailGroup.insertObjectAtIndex( new TestObject(), 0 );
- }
- } );
-
- AbstractButton removeButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Remove" );
- removeButton.addActionListener( new ActionListener()
- {
- public void actionPerformed( ActionEvent evt )
- {
- if ( detailGroup.selectedObject() != null )
- detailGroup.deleteSelection();
+ AbstractButton addButton = (AbstractButton) treePanel.editPanel.addPanel.getButton("Add");
+ addButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ detailGroup.insertObjectAtIndex(new TestObject(), 0);
}
- } );
-/*
- AbstractButton refreshButton = (AbstractButton)
- treePanel.editPanel.addPanel.getButton( "Refresh" );
- refreshButton.addActionListener( new ActionListener()
- {
- int count = 0;
- public void actionPerformed( ActionEvent evt )
- {
- EODisplayGroup displayGroup = (EODisplayGroup)
- treePanel.tree.getSelectionPath().getLastPathComponent();
-// displayGroup.insertObjectAtIndex( new TestObject(), 0 );
-// displayGroup.deleteObjectAtIndex( 0 );
- List sortOrderings = new LinkedList();
- if ( count++ % 2 == 0 )
- {
- sortOrderings.add( new EOSortOrdering(
- "lastName", EOSortOrdering.CompareAscending ) );
- }
- else
- {
- sortOrderings.add( new EOSortOrdering(
- "lastName", EOSortOrdering.CompareDescending ) );
- }
- displayGroup.setSortOrderings( sortOrderings );
- displayGroup.updateDisplayedObjects();
+ });
+
+ AbstractButton removeButton = (AbstractButton) treePanel.editPanel.addPanel.getButton("Remove");
+ removeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ if (detailGroup.selectedObject() != null)
+ detailGroup.deleteSelection();
}
- } );
-*/
-/*
- ta = new DisplayGroupActionAssociation(
- treePanel.editPanel.addPanel.getButton( "Remove" ) );
- ta.bindAspect( EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
- ta.establishConnection();
-
- ta = new DisplayGroupActionAssociation(
- treePanel.editPanel.addPanel.getButton( "Refresh" ) );
- ta.bindAspect( EOAssociation.ActionAspect, group, "updateDisplayedObjects" );
- ta.establishConnection();
-*/
+ });
+ /*
+ * AbstractButton refreshButton = (AbstractButton)
+ * treePanel.editPanel.addPanel.getButton( "Refresh" );
+ * refreshButton.addActionListener( new ActionListener() { int count = 0; public
+ * void actionPerformed( ActionEvent evt ) { EODisplayGroup displayGroup =
+ * (EODisplayGroup) treePanel.tree.getSelectionPath().getLastPathComponent(); //
+ * displayGroup.insertObjectAtIndex( new TestObject(), 0 ); //
+ * displayGroup.deleteObjectAtIndex( 0 ); List sortOrderings = new LinkedList();
+ * if ( count++ % 2 == 0 ) { sortOrderings.add( new EOSortOrdering( "lastName",
+ * EOSortOrdering.CompareAscending ) ); } else { sortOrderings.add( new
+ * EOSortOrdering( "lastName", EOSortOrdering.CompareDescending ) ); }
+ * displayGroup.setSortOrderings( sortOrderings );
+ * displayGroup.updateDisplayedObjects(); } } );
+ */
+ /*
+ * ta = new DisplayGroupActionAssociation(
+ * treePanel.editPanel.addPanel.getButton( "Remove" ) ); ta.bindAspect(
+ * EOAssociation.ActionAspect, detailGroup, "deleteSelection" );
+ * ta.establishConnection();
+ *
+ * ta = new DisplayGroupActionAssociation(
+ * treePanel.editPanel.addPanel.getButton( "Refresh" ) ); ta.bindAspect(
+ * EOAssociation.ActionAspect, group, "updateDisplayedObjects" );
+ * ta.establishConnection();
+ */
// add mouse listener for list
-
- treePanel.editPanel.list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getClickCount() == 2 )
- {
+
+ treePanel.editPanel.list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
Object item = detailGroup.selectedObject();
- if ( item != null )
- {
- new InspectorController( item );
- }
+ if (item != null) {
+ new InspectorController(item);
+ }
}
}
});
// launch
-
+
JDialog d = new JDialog();
- d.getContentPane().add( treePanel );
- d.setTitle( "Tree Panel" );
+ d.getContentPane().add(treePanel);
+ d.setTitle("Tree Panel");
d.pack();
- WindowUtilities.cascade( d );
+ WindowUtilities.cascade(d);
d.show();
- // workaround for memory issues on jdk1.2.2
- d.addWindowListener( new WindowAdapter()
- {
+ // workaround for memory issues on jdk1.2.2
+ d.addWindowListener(new WindowAdapter() {
// exit on close
- public void windowClosing(WindowEvent e)
- {
- ((JDialog)e.getWindow()).getContentPane().removeAll();
+ public void windowClosing(WindowEvent e) {
+ ((JDialog) e.getWindow()).getContentPane().removeAll();
}
});
}
-
+
}
diff --git a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreePanel.java b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreePanel.java
index 48ebd81..48c2571 100644
--- a/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreePanel.java
+++ b/projects/net.wotonomy.test/src/main/java/net/wotonomy/test/TreePanel.java
@@ -9,31 +9,29 @@ import javax.swing.JTree;
import javax.swing.border.EmptyBorder;
/**
-* A simple editor panel with a few textfields.
-*/
-public class TreePanel extends JPanel
-{
+ * A simple editor panel with a few textfields.
+ */
+public class TreePanel extends JPanel {
public JTree tree;
public EditPanel editPanel;
- public JPanel panel;
-
- public TreePanel()
- {
- panel = new JPanel();
- panel.setLayout( new BorderLayout() );
- panel.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
-
+ public JPanel panel;
+
+ public TreePanel() {
+ panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.setBorder(new EmptyBorder(10, 10, 10, 10));
+
tree = new JTree();
- tree.setRootVisible( false );
- tree.setShowsRootHandles( true );
- JScrollPane scrollPane = new JScrollPane( tree );
- scrollPane.setPreferredSize( new Dimension( 150, 200 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
+ tree.setRootVisible(false);
+ tree.setShowsRootHandles(true);
+ JScrollPane scrollPane = new JScrollPane(tree);
+ scrollPane.setPreferredSize(new Dimension(150, 200));
+ panel.add(scrollPane, BorderLayout.CENTER);
editPanel = new EditPanel();
- panel.add( editPanel, BorderLayout.EAST );
-
- this.setLayout( new BorderLayout() );
- this.add( panel, BorderLayout.CENTER );
+ panel.add(editPanel, BorderLayout.EAST);
+
+ this.setLayout(new BorderLayout());
+ this.add(panel, BorderLayout.CENTER);
}
-
+
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ActionAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ActionAssociation.java
index cc3af69..ae3fa50 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ActionAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ActionAssociation.java
@@ -31,305 +31,228 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* ActionAssociation binds any ActionEvent broadcaster
-* (typically Buttons and the like) to a display group.
-* Actions are invoked on all selected objects in the
-* display group bound to the action aspect.
-* Bindings are:
-* <ul>
-* <li>action: a method to be invoked on selected objects.
-* If the argument aspect is bound, the method must take
-* one argument. Otherwise, the method must take no arguments.</li>
-* <li>argument: the attribute of the selected object(s) (possibly
-* from a different display group) that will be used as an argument
-* to the action method</li>
-* <li>enabled: a boolean property that determines whether
-* the controlled component is enabled</li>
-* <li>visible: a boolean property that determines whether
-* the controlled component is visible</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class ActionAssociation extends EOAssociation
- implements ActionListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ActionAspect, ArgumentAspect, EnabledAspect, VisibleAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "target"
- } );
-
- static NSSelector addActionListener =
- new NSSelector( "addActionListener",
- new Class[] { ActionListener.class } );
- static NSSelector removeActionListener =
- new NSSelector( "removeActionListener",
- new Class[] { ActionListener.class } );
+ * ActionAssociation binds any ActionEvent broadcaster (typically Buttons and
+ * the like) to a display group. Actions are invoked on all selected objects in
+ * the display group bound to the action aspect. Bindings are:
+ * <ul>
+ * <li>action: a method to be invoked on selected objects. If the argument
+ * aspect is bound, the method must take one argument. Otherwise, the method
+ * must take no arguments.</li>
+ * <li>argument: the attribute of the selected object(s) (possibly from a
+ * different display group) that will be used as an argument to the action
+ * method</li>
+ * <li>enabled: a boolean property that determines whether the controlled
+ * component is enabled</li>
+ * <li>visible: a boolean property that determines whether the controlled
+ * component is visible</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class ActionAssociation extends EOAssociation implements ActionListener {
+ static final NSArray aspects = new NSArray(
+ new Object[] { ActionAspect, ArgumentAspect, EnabledAspect, VisibleAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "target" });
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public ActionAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return
- ( addActionListener.implementedByObject( anObject ) )
- && ( removeActionListener.implementedByObject( anObject ) );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default.
- */
- public static String primaryAspect ()
- {
- return ActionAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- try
- {
- addActionListener.invoke( object(), this );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( "EOActionAssociation: " +
- "could not add action listener to object:" + object() );
- }
- super.establishConnection();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- try
- {
- removeActionListener.invoke( object(), this );
+ static NSSelector addActionListener = new NSSelector("addActionListener", new Class[] { ActionListener.class });
+ static NSSelector removeActionListener = new NSSelector("removeActionListener",
+ new Class[] { ActionListener.class });
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public ActionAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (addActionListener.implementedByObject(anObject))
+ && (removeActionListener.implementedByObject(anObject));
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default.
+ */
+ public static String primaryAspect() {
+ return ActionAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ try {
+ addActionListener.invoke(object(), this);
+ } catch (Exception exc) {
+ throw new WotonomyException(
+ "EOActionAssociation: " + "could not add action listener to object:" + object());
}
- catch ( Exception exc )
- {
- throw new WotonomyException( "EOActionAssociation: " +
- "could not add action listener to object:" + object() );
+ super.establishConnection();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ try {
+ removeActionListener.invoke(object(), this);
+ } catch (Exception exc) {
+ throw new WotonomyException(
+ "EOActionAssociation: " + "could not add action listener to object:" + object());
}
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- * This implementation does nothing.
- */
- public void subjectChanged ()
- {
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed. This implementation does nothing.
+ */
+ public void subjectChanged() {
Object component = object();
EODisplayGroup displayGroup;
String key;
-
- if ( component instanceof Component )
- {
+
+ if (component instanceof Component) {
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( EnabledAspect );
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() !=
- ((Component)component).isEnabled() )
- {
- ((Component)component).setEnabled(
- converted.booleanValue() );
- }
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(EnabledAspect);
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != ((Component) component).isEnabled()) {
+ ((Component) component).setEnabled(converted.booleanValue());
+ }
}
-
+
// visible aspect
- displayGroup = displayGroupForAspect( VisibleAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( VisibleAspect );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- if ( converted != null )
- {
- if ( converted.booleanValue() !=
- ((Component)component).isVisible() )
- {
- ((Component)component).setVisible(
- converted.booleanValue() );
+ displayGroup = displayGroupForAspect(VisibleAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(VisibleAspect);
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ if (converted != null) {
+ if (converted.booleanValue() != ((Component) component).isVisible()) {
+ ((Component) component).setVisible(converted.booleanValue());
}
- }
+ }
}
}
- }
-
- // interface ActionListener
-
- public void actionPerformed( ActionEvent evt )
- {
+ }
+
+ // interface ActionListener
+
+ public void actionPerformed(ActionEvent evt) {
EODisplayGroup actionDisplayGroup = null;
String actionKey = null;
-
+
// action aspect
- actionDisplayGroup = displayGroupForAspect( ActionAspect );
- if ( actionDisplayGroup != null )
- {
- actionKey = displayGroupKeyForAspect( ActionAspect );
+ actionDisplayGroup = displayGroupForAspect(ActionAspect);
+ if (actionDisplayGroup != null) {
+ actionKey = displayGroupKeyForAspect(ActionAspect);
- //TODO: argument aspect not implemented
+ // TODO: argument aspect not implemented
- try
- {
-
- NSSelector selector = new NSSelector( actionKey );
- Enumeration e =
- actionDisplayGroup.selectedObjects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- selector.invoke( e.nextElement() );
+ try {
+
+ NSSelector selector = new NSSelector(actionKey);
+ Enumeration e = actionDisplayGroup.selectedObjects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ selector.invoke(e.nextElement());
}
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "ActionAssociation: error invoking action: " + actionKey, exc );
+ } catch (Exception exc) {
+ throw new WotonomyException("ActionAssociation: error invoking action: " + actionKey, exc);
}
}
- }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.4 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.2 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.1.1.1 2000/12/21 15:48:28 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:28 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/AdjustableAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/AdjustableAssociation.java
index 2dc7fec..4f90c79 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/AdjustableAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/AdjustableAssociation.java
@@ -29,299 +29,234 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* AdjustableAssociation binds any Adjustable component to
-* a display group. Components implementing the adjustable
-* interface include: ScrollBar and JScrollBar.
-* Bindings are:
-* <ul>
-* <li>value: a property convertable to/from a string</li>
-* <li>enabled: a boolean property that determines whether
-* the user can select the text in the field</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class AdjustableAssociation extends EOAssociation
- implements AdjustmentListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "value"
- } );
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public AdjustableAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof Adjustable );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * attempts to add this class as an ActionListener
- * and as a FocusListener to the specified object.
- */
- public void establishConnection ()
- {
- component().addAdjustmentListener( this );
- super.establishConnection();
-
+ * AdjustableAssociation binds any Adjustable component to a display group.
+ * Components implementing the adjustable interface include: ScrollBar and
+ * JScrollBar. Bindings are:
+ * <ul>
+ * <li>value: a property convertable to/from a string</li>
+ * <li>enabled: a boolean property that determines whether the user can select
+ * the text in the field</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class AdjustableAssociation extends EOAssociation implements AdjustmentListener {
+ static final NSArray aspects = new NSArray(new Object[] { ValueAspect, EnabledAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "value" });
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public AdjustableAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof Adjustable);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation attempts to add this class as an ActionListener and as a
+ * FocusListener to the specified object.
+ */
+ public void establishConnection() {
+ component().addAdjustmentListener(this);
+ super.establishConnection();
+
// forces update from bindings
subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- component().removeAdjustmentListener( this );
- super.breakConnection();
- }
+ }
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ component().removeAdjustmentListener(this);
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
Adjustable component = component();
EODisplayGroup displayGroup;
String key;
Object value;
-
+
// value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- if ( component instanceof Component )
- {
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
- }
- value = displayGroup.selectedObjectValueForKey( key );
-
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ if (component instanceof Component) {
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+ }
+ value = displayGroup.selectedObjectValueForKey(key);
+
// convert value to int
- value = ValueConverter.convertObjectToClass(
- value, Integer.class );
+ value = ValueConverter.convertObjectToClass(value, Integer.class);
int intValue;
- if ( value == null )
- {
+ if (value == null) {
intValue = 0;
+ } else {
+ intValue = ((Integer) value).intValue();
}
- else
- {
- intValue = ((Integer)value).intValue();
- }
-
- if ( component.getValue() != intValue )
- {
- component.setValue( intValue );
+
+ if (component.getValue() != intValue) {
+ component.setValue(intValue);
}
}
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- key = displayGroupKeyForAspect( EnabledAspect );
- if ( ( ( displayGroup != null ) || ( key != null ) )
- && ( component instanceof Component ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ key = displayGroupKeyForAspect(EnabledAspect);
+ if (((displayGroup != null) || (key != null)) && (component instanceof Component)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
- value = key;
+ value = key;
+ }
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != ((Component) component).isEnabled()) {
+ ((Component) component).setEnabled(converted.booleanValue());
}
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() != ((Component)component).isEnabled() )
- {
- ((Component)component).setEnabled( converted.booleanValue() );
- }
}
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
return writeValueToDisplayGroup();
- }
-
+ }
+
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- EODisplayGroup displayGroup =
- displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( ValueAspect );
- Object value = new Integer( component().getValue() );
- return displayGroup.setSelectedObjectValue( value, key );
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ EODisplayGroup displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(ValueAspect);
+ Object value = new Integer(component().getValue());
+ return displayGroup.setSelectedObjectValue(value, key);
}
return false;
}
- // interface AdjustmentListener
-
+ // interface AdjustmentListener
+
/**
- * Updates object on action performed.
- */
- public void adjustmentValueChanged(AdjustmentEvent e)
- {
+ * Updates object on action performed.
+ */
+ public void adjustmentValueChanged(AdjustmentEvent e) {
writeValueToDisplayGroup();
}
-
- private Adjustable component()
- {
- return (Adjustable) object();
+
+ private Adjustable component() {
+ return (Adjustable) object();
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.3 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1.1.1 2000/12/21 15:48:35 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:35 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ButtonAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ButtonAssociation.java
index 38cf38b..5a1c85c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ButtonAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ButtonAssociation.java
@@ -33,412 +33,312 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* ButtonAssociation binds any component that uses a ButtonModel
-* (all Swing button classes) to a display group. This association
-* should be used to handle individual JRadioButtons and JCheckBoxes.
-* Bindings are:
-* <ul>
-* <li>value: a boolean property that determines the
-* selected state of the button model. This will set
-* the value for radio buttons and check boxes.</li>
-* <li>enabled: a boolean property that determines the
-* enabled state of the button model.</li>
-* <li>visible: a boolean property that determines the
-* visible state of the button model.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class ButtonAssociation extends EOAssociation
- implements ChangeListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect, VisibleAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "model.selected"
- } );
-
- static NSSelector getModel =
- new NSSelector( "getModel", new Class[] {} );
-
- protected ButtonModel buttonModel;
- protected boolean lastKnownValue;
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- * This implementation expects a ButtonModel or a class
- * that has a "getModel" method that returns a ButtonModel.
- */
- public ButtonAssociation ( Object anObject )
- {
- super( anObject );
-
- if ( anObject instanceof ButtonModel )
- {
- buttonModel = (ButtonModel) anObject;
- }
- else
- {
- try
- {
- buttonModel = (ButtonModel) getModel.invoke( anObject );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( "EOButtonAssociation: " +
- "could not retrieve a button model from object:" + anObject );
- }
- }
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- * This implementation expects a ButtonModel or a class
- * that has a "getModel" method that returns a ButtonModel.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return
- ( anObject instanceof ButtonModel )
- || ( getModel.implementedByObject( anObject ) );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- buttonModel.addChangeListener( this );
- super.establishConnection();
- subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- buttonModel.removeChangeListener( this );
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- * This implementation does nothing.
- */
- public void subjectChanged ()
- {
- Object component = object();
- EODisplayGroup displayGroup;
- String key;
-
- // value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
-
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- if ( component instanceof Component )
- {
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
- }
-
- Object value;
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- }
- else // displayGroup has only one object
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- } // end checking size of displayGroup
-
- buttonModel.setArmed( false );
- buttonModel.setPressed( false );
-
- if ( value != null )
- {
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- if ( converted != null )
- {
- lastKnownValue = converted.booleanValue();
- if ( converted.booleanValue() !=
- buttonModel.isSelected() )
- {
- buttonModel.removeChangeListener( this );
- buttonModel.setSelected(
- converted.booleanValue() );
- buttonModel.addChangeListener( this );
- }
- } // end checking converted == null
- }
- else
- {
- buttonModel.setArmed( true );
- buttonModel.setPressed( true );
- }
- }
-
- // enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( EnabledAspect );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() !=
- buttonModel.isEnabled() )
- {
- buttonModel.removeChangeListener( this );
- buttonModel.setEnabled(
- converted.booleanValue() );
- buttonModel.addChangeListener( this );
- }
- }
-
- // visible aspect
- displayGroup = displayGroupForAspect( VisibleAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( VisibleAspect );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- if ( converted != null )
- {
- if ( converted.booleanValue() !=
- ((Component)component).isVisible() )
- {
- ((Component)component).setVisible(
- converted.booleanValue() );
- }
- }
- }
- }
-
- /**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- EODisplayGroup displayGroup =
- displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- boolean returnValue = true;
- String key = displayGroupKeyForAspect( ValueAspect );
- Object value = new Boolean( buttonModel.isSelected() );
-
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- returnValue = false;
- }
- }
- return returnValue;
-
- }
- return false;
- }
- // interface ChangeListener
-
- public void stateChanged(ChangeEvent e)
- {
- if ( buttonModel.isSelected() != lastKnownValue )
- {
- lastKnownValue = buttonModel.isSelected();
- writeValueToDisplayGroup();
- }
- }
+ * ButtonAssociation binds any component that uses a ButtonModel (all Swing
+ * button classes) to a display group. This association should be used to handle
+ * individual JRadioButtons and JCheckBoxes. Bindings are:
+ * <ul>
+ * <li>value: a boolean property that determines the selected state of the
+ * button model. This will set the value for radio buttons and check boxes.</li>
+ * <li>enabled: a boolean property that determines the enabled state of the
+ * button model.</li>
+ * <li>visible: a boolean property that determines the visible state of the
+ * button model.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class ButtonAssociation extends EOAssociation implements ChangeListener {
+ static final NSArray aspects = new NSArray(new Object[] { ValueAspect, EnabledAspect, VisibleAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "model.selected" });
+
+ static NSSelector getModel = new NSSelector("getModel", new Class[] {});
+
+ protected ButtonModel buttonModel;
+ protected boolean lastKnownValue;
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection. This implementation expects a ButtonModel or a
+ * class that has a "getModel" method that returns a ButtonModel.
+ */
+ public ButtonAssociation(Object anObject) {
+ super(anObject);
+
+ if (anObject instanceof ButtonModel) {
+ buttonModel = (ButtonModel) anObject;
+ } else {
+ try {
+ buttonModel = (ButtonModel) getModel.invoke(anObject);
+ } catch (Exception exc) {
+ throw new WotonomyException(
+ "EOButtonAssociation: " + "could not retrieve a button model from object:" + anObject);
+ }
+ }
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object. This
+ * implementation expects a ButtonModel or a class that has a "getModel" method
+ * that returns a ButtonModel.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof ButtonModel) || (getModel.implementedByObject(anObject));
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ buttonModel.addChangeListener(this);
+ super.establishConnection();
+ subjectChanged();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ buttonModel.removeChangeListener(this);
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed. This implementation does nothing.
+ */
+ public void subjectChanged() {
+ Object component = object();
+ EODisplayGroup displayGroup;
+ String key;
+
+ // value aspect
+ displayGroup = displayGroupForAspect(ValueAspect);
+
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ if (component instanceof Component) {
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+ }
+
+ Object value;
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else // displayGroup has only one object
+ {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking size of displayGroup
+
+ buttonModel.setArmed(false);
+ buttonModel.setPressed(false);
+
+ if (value != null) {
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ if (converted != null) {
+ lastKnownValue = converted.booleanValue();
+ if (converted.booleanValue() != buttonModel.isSelected()) {
+ buttonModel.removeChangeListener(this);
+ buttonModel.setSelected(converted.booleanValue());
+ buttonModel.addChangeListener(this);
+ }
+ } // end checking converted == null
+ } else {
+ buttonModel.setArmed(true);
+ buttonModel.setPressed(true);
+ }
+ }
+
+ // enabled aspect
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(EnabledAspect);
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != buttonModel.isEnabled()) {
+ buttonModel.removeChangeListener(this);
+ buttonModel.setEnabled(converted.booleanValue());
+ buttonModel.addChangeListener(this);
+ }
+ }
+
+ // visible aspect
+ displayGroup = displayGroupForAspect(VisibleAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(VisibleAspect);
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ if (converted != null) {
+ if (converted.booleanValue() != ((Component) component).isVisible()) {
+ ((Component) component).setVisible(converted.booleanValue());
+ }
+ }
+ }
+ }
+
+ /**
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ EODisplayGroup displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ boolean returnValue = true;
+ String key = displayGroupKeyForAspect(ValueAspect);
+ Object value = new Boolean(buttonModel.isSelected());
+
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (!displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+
+ }
+ return false;
+ }
+ // interface ChangeListener
+
+ public void stateChanged(ChangeEvent e) {
+ if (buttonModel.isSelected() != lastKnownValue) {
+ lastKnownValue = buttonModel.isSelected();
+ writeValueToDisplayGroup();
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.8 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.7 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.6 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.5 2001/06/29 22:28:19 mpowers
- * Tabs to spaces.
+ * Revision 1.5 2001/06/29 22:28:19 mpowers Tabs to spaces.
*
- * Revision 1.4 2001/06/29 22:17:31 mpowers
- * Now updating the component on establishConnection.
+ * Revision 1.4 2001/06/29 22:17:31 mpowers Now updating the component on
+ * establishConnection.
*
- * Revision 1.3 2001/02/27 02:10:38 mpowers
- * No longer updating values to the display group if the value
- * has not changed.
+ * Revision 1.3 2001/02/27 02:10:38 mpowers No longer updating values to the
+ * display group if the value has not changed.
*
- * Revision 1.2 2001/02/21 20:33:01 mpowers
- * Fixed bug with change listener.
+ * Revision 1.2 2001/02/21 20:33:01 mpowers Fixed bug with change listener.
*
- * Revision 1.1.1.1 2000/12/21 15:48:38 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:38 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ComboBoxAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ComboBoxAssociation.java
index d0a087e..e6cd0aa 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ComboBoxAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ComboBoxAssociation.java
@@ -37,664 +37,529 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* ComboBoxAssociation binds JComboBoxes to
-* display groups. Bindings are:
-* <ul>
-*
-* <li>value: optional - a property of the selected object in the
-* display group that will be bind to the item the user
-* selects or the text that the user enters in the field.
-* If the value aspect is not bound, then the combo box works
-* as an "overview" assocation and changing the selected object
-* in the combobox will modify the selection of the display group
-* bound to the objects or the titles display groups (in that order).</li>
-*
-* <li>titles: optional - a property of the objects in the bound
-* display group that will appear in the list. If the
-* objects aspect is not bound, this property is also
-* used to populate the value binding. If the titles
-* aspect itself is not bound, the items already in the
-* combobox will be used to update the value in the
-* selected object in the bound display group.</li>
-*
-* <li>objects: optional - if specified, when the user
-* selects a title in the list, the property of the
-* object at the corresponding index of the bound display
-* group will be used to populate the value binding.
-* If the objects aspect is used with an editable combo
-* box, any value entered that does not match one of the
-* titles in the list will produce a null value.</li>
-*
-* <li>enabled: optional - a boolean property of the
-* selected object in the display group that determines whether
-* the user can edit the field.</li>
-*
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class ComboBoxAssociation extends EOAssociation
- implements FocusListener, ActionListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- TitlesAspect, ValueAspect,
- ObjectsAspect, EnabledAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "text"
- } );
-
- private boolean wasNull;
- private static final String EMPTY_STRING = "";
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public ComboBoxAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof JComboBox );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- super.establishConnection();
-
- // prepopulate titles
- EODisplayGroup displayGroup =
- displayGroupForAspect( TitlesAspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( TitlesAspect );
- populateTitles( displayGroup, key );
- }
- addAsListener();
- subjectChanged();
- }
-
- protected void addAsListener()
- {
- component().addActionListener( this );
- component().addFocusListener( this );
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- removeAsListener();
- super.breakConnection();
- }
-
- protected void removeAsListener()
- {
- component().removeActionListener( this );
- component().removeFocusListener( this );
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
- removeAsListener();
-
- JComboBox component = component();
- EODisplayGroup displayGroup;
- String key;
-
- // titles aspect
- displayGroup = displayGroupForAspect( TitlesAspect );
- if ( displayGroup != null )
- {
- ComboBoxModel model = component().getModel();
- // if first time, or if backing group has changed
+ * ComboBoxAssociation binds JComboBoxes to display groups. Bindings are:
+ * <ul>
+ *
+ * <li>value: optional - a property of the selected object in the display group
+ * that will be bind to the item the user selects or the text that the user
+ * enters in the field. If the value aspect is not bound, then the combo box
+ * works as an "overview" assocation and changing the selected object in the
+ * combobox will modify the selection of the display group bound to the objects
+ * or the titles display groups (in that order).</li>
+ *
+ * <li>titles: optional - a property of the objects in the bound display group
+ * that will appear in the list. If the objects aspect is not bound, this
+ * property is also used to populate the value binding. If the titles aspect
+ * itself is not bound, the items already in the combobox will be used to update
+ * the value in the selected object in the bound display group.</li>
+ *
+ * <li>objects: optional - if specified, when the user selects a title in the
+ * list, the property of the object at the corresponding index of the bound
+ * display group will be used to populate the value binding. If the objects
+ * aspect is used with an editable combo box, any value entered that does not
+ * match one of the titles in the list will produce a null value.</li>
+ *
+ * <li>enabled: optional - a boolean property of the selected object in the
+ * display group that determines whether the user can edit the field.</li>
+ *
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class ComboBoxAssociation extends EOAssociation implements FocusListener, ActionListener {
+ static final NSArray aspects = new NSArray(
+ new Object[] { TitlesAspect, ValueAspect, ObjectsAspect, EnabledAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "text" });
+
+ private boolean wasNull;
+ private static final String EMPTY_STRING = "";
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public ComboBoxAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof JComboBox);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ super.establishConnection();
+
+ // prepopulate titles
+ EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(TitlesAspect);
+ populateTitles(displayGroup, key);
+ }
+ addAsListener();
+ subjectChanged();
+ }
+
+ protected void addAsListener() {
+ component().addActionListener(this);
+ component().addFocusListener(this);
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ removeAsListener();
+ super.breakConnection();
+ }
+
+ protected void removeAsListener() {
+ component().removeActionListener(this);
+ component().removeFocusListener(this);
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
+ removeAsListener();
+
+ JComboBox component = component();
+ EODisplayGroup displayGroup;
+ String key;
+
+ // titles aspect
+ displayGroup = displayGroupForAspect(TitlesAspect);
+ if (displayGroup != null) {
+ ComboBoxModel model = component().getModel();
+ // if first time, or if backing group has changed
// if ( ( ! ( model instanceof ComboBoxAssociationModel ) )
// || ( displayGroup.contentsChanged() ) )
// {
- key = displayGroupKeyForAspect( TitlesAspect );
- populateTitles( displayGroup, key );
+ key = displayGroupKeyForAspect(TitlesAspect);
+ populateTitles(displayGroup, key);
// }
- }
-
- // value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- component.setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
- //Object value = displayGroup.selectedObjectValueForKey( key );
- Object value;
-
-
- if ( displayGroup.selectedObjects().size() > 1 )
- {
-
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
-
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- } else {
- // if there's only one object selected.
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking the size of selected objects in displayGroup
-
-
- // objects aspect
- EODisplayGroup objectsDisplayGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( ( objectsDisplayGroup != null ) && ( value != null ) )
- {
- String objectKey = displayGroupKeyForAspect( ObjectsAspect );
- Object match;
- int index = NSArray.NotFound;
- int count = objectsDisplayGroup.displayedObjects().count();
- for ( int i = 0; i < count; i++ )
- {
- match = objectsDisplayGroup.valueForObjectAtIndex( i, objectKey );
- if ( value.equals( match ) )
- {
- index = i;
- }
- }
- if ( index == NSArray.NotFound )
- {
- if ( component.getSelectedItem() != null )
- {
- component.setSelectedItem( null );
- }
- }
- else
- {
- if ( component.getSelectedIndex() != index )
- {
- component.setSelectedIndex( index );
- }
- }
- }
- else
- {
- component.setSelectedItem( value );
- }
- }
- else // values aspect not bound
- {
- // use objects group if specified
- EODisplayGroup sourceGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( sourceGroup == null )
- {
- // fall back on titles group
- sourceGroup = displayGroupForAspect( TitlesAspect );
- }
-
- if ( sourceGroup != null )
- {
- List selection = sourceGroup.selectionIndexes();
- if ( ( selection != null ) && ( selection.size() > 0 ) )
- {
- component.setSelectedIndex( ((Integer)selection.get(0)).intValue() );
- }
- else
- {
- // the combo box model decides what to do with this value
- component.setSelectedItem( null );
- }
- }
- }
-
- // enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( EnabledAspect );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() != component.isEnabled() )
- {
- component.setEnabled( converted.booleanValue() );
- }
- }
-
- addAsListener();
- }
-
- /**
- * Called to repopulate the title list from the
- * specified display group.
- */
- protected void populateTitles(
- EODisplayGroup displayGroup, String key )
- {
- component().setModel(
- new ComboBoxAssociationModel( displayGroup, key ) );
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
- return writeValueToDisplayGroup();
- }
-
- /**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- JComboBox component = component();
- EODisplayGroup displayGroup;
- String key;
-
- // selected title aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- Object value = null;
-
- // selected object aspect, if any
- EODisplayGroup objectsGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( objectsGroup != null )
- {
- try
- {
- String objectKey = displayGroupKeyForAspect( ObjectsAspect );
- int index = component.getSelectedIndex();
- if ( index != -1 )
- {
- value = objectsGroup
- .valueForObjectAtIndex( index, objectKey );
- }
- else // selected index is -1
- {
- // the combo box is probably editable,
- // so there is no corresponding object.
- value = null;
- }
- }
- catch ( NullPointerException npe )
- {
- // catches NPE on line 436 of JComboBox.java:
- // this is a common developer error
- throw new WotonomyException( "ComboBoxAssociation: " +
- "The object in the VALUE property may not have been found in the " +
- "objects in the TITLES group.", npe );
- }
- }
- else // just use the selected item
- {
- value = component.getSelectedItem();
- }
-
- boolean returnValue = true;
- if ( displayGroup.selectedObjects().size() == 1 )
- { // displayGroup has only one object
- // only set value if changed
- Object existingValue = displayGroup.selectedObjectValueForKey( key );
- if ( value == existingValue ) return true;
- if ( ( existingValue != null ) && ( existingValue.equals( value ) ) ) return true;
-
- // value has changed: update the value.
- return displayGroup.setSelectedObjectValue( value, key );
- }
- else if ( displayGroup.selectedObjects().size() > 1 )
- {
- // displayGroup has more than one object
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- returnValue = false;
- }
- }
- return returnValue;
-
- } // end checking size of displayGroup
-
- }
- else // values aspect not bound
- {
- // use objects group if specified
- EODisplayGroup sourceGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( sourceGroup == null )
- {
- // fall back on titles group
- sourceGroup = displayGroupForAspect( TitlesAspect );
- }
-
- if ( sourceGroup != null )
- {
- int index = component.getSelectedIndex();
- if ( index != -1 )
- {
- sourceGroup.setSelectionIndexes( new NSArray( new Integer( index ) ) );
- }
- else
- {
- sourceGroup.setSelectedObject( null );
- }
- return true;
- }
- }
-
- return false;
- }
-
- // interface ActionListener
-
- /**
- * Updates object on action performed.
- */
- public void actionPerformed( ActionEvent evt )
- {
- writeValueToDisplayGroup();
- }
-
- // interface FocusListener
-
- /**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
- }
- }
- }
-
- /**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( component().isEditable() )
- {
- if ( endEditing() )
- {
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
- }
- }
- }
- }
- }
-
- // convenience
-
- private JComboBox component()
- {
- return (JComboBox) object();
- }
-
- /**
- * Used as the data model for the controlled combo box.
- */
- private class ComboBoxAssociationModel extends AbstractListModel
- implements ComboBoxModel
- {
- EODisplayGroup displayGroup;
- String key;
- Object selectedItem;
-
- ComboBoxAssociationModel(
- EODisplayGroup aDisplayGroup, String aKey )
- {
- displayGroup = aDisplayGroup;
- key = aKey;
- selectedItem = null;
- }
-
- public Object getElementAt(int index)
- {
- return displayGroup.valueForObjectAtIndex( index, key );
- }
-
- public int getSize()
- {
- return displayGroup.displayedObjects().count();
- }
-
- public void setSelectedItem(Object anItem)
- { //System.out.println( "setSelectedItem: " + anItem );
- selectedItem = anItem;
-
- // must do this to notify an editable combo,
- // otherwise the wrong value appears.
- fireContentsChanged( this, -1, -1 );
- }
-
- public Object getSelectedItem()
- { //System.out.println( "getSelectedItem: " + selectedItem );
- return selectedItem;
- }
- }
+ }
+
+ // value aspect
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ component.setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+ // Object value = displayGroup.selectedObjectValueForKey( key );
+ Object value;
+
+ if (displayGroup.selectedObjects().size() > 1) {
+
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else {
+ // if there's only one object selected.
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking the size of selected objects in displayGroup
+
+ // objects aspect
+ EODisplayGroup objectsDisplayGroup = displayGroupForAspect(ObjectsAspect);
+ if ((objectsDisplayGroup != null) && (value != null)) {
+ String objectKey = displayGroupKeyForAspect(ObjectsAspect);
+ Object match;
+ int index = NSArray.NotFound;
+ int count = objectsDisplayGroup.displayedObjects().count();
+ for (int i = 0; i < count; i++) {
+ match = objectsDisplayGroup.valueForObjectAtIndex(i, objectKey);
+ if (value.equals(match)) {
+ index = i;
+ }
+ }
+ if (index == NSArray.NotFound) {
+ if (component.getSelectedItem() != null) {
+ component.setSelectedItem(null);
+ }
+ } else {
+ if (component.getSelectedIndex() != index) {
+ component.setSelectedIndex(index);
+ }
+ }
+ } else {
+ component.setSelectedItem(value);
+ }
+ } else // values aspect not bound
+ {
+ // use objects group if specified
+ EODisplayGroup sourceGroup = displayGroupForAspect(ObjectsAspect);
+ if (sourceGroup == null) {
+ // fall back on titles group
+ sourceGroup = displayGroupForAspect(TitlesAspect);
+ }
+
+ if (sourceGroup != null) {
+ List selection = sourceGroup.selectionIndexes();
+ if ((selection != null) && (selection.size() > 0)) {
+ component.setSelectedIndex(((Integer) selection.get(0)).intValue());
+ } else {
+ // the combo box model decides what to do with this value
+ component.setSelectedItem(null);
+ }
+ }
+ }
+
+ // enabled aspect
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(EnabledAspect);
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != component.isEnabled()) {
+ component.setEnabled(converted.booleanValue());
+ }
+ }
+
+ addAsListener();
+ }
+
+ /**
+ * Called to repopulate the title list from the specified display group.
+ */
+ protected void populateTitles(EODisplayGroup displayGroup, String key) {
+ component().setModel(new ComboBoxAssociationModel(displayGroup, key));
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ return writeValueToDisplayGroup();
+ }
+
+ /**
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ JComboBox component = component();
+ EODisplayGroup displayGroup;
+ String key;
+
+ // selected title aspect
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ Object value = null;
+
+ // selected object aspect, if any
+ EODisplayGroup objectsGroup = displayGroupForAspect(ObjectsAspect);
+ if (objectsGroup != null) {
+ try {
+ String objectKey = displayGroupKeyForAspect(ObjectsAspect);
+ int index = component.getSelectedIndex();
+ if (index != -1) {
+ value = objectsGroup.valueForObjectAtIndex(index, objectKey);
+ } else // selected index is -1
+ {
+ // the combo box is probably editable,
+ // so there is no corresponding object.
+ value = null;
+ }
+ } catch (NullPointerException npe) {
+ // catches NPE on line 436 of JComboBox.java:
+ // this is a common developer error
+ throw new WotonomyException(
+ "ComboBoxAssociation: " + "The object in the VALUE property may not have been found in the "
+ + "objects in the TITLES group.",
+ npe);
+ }
+ } else // just use the selected item
+ {
+ value = component.getSelectedItem();
+ }
+
+ boolean returnValue = true;
+ if (displayGroup.selectedObjects().size() == 1) { // displayGroup has only one object
+ // only set value if changed
+ Object existingValue = displayGroup.selectedObjectValueForKey(key);
+ if (value == existingValue)
+ return true;
+ if ((existingValue != null) && (existingValue.equals(value)))
+ return true;
+
+ // value has changed: update the value.
+ return displayGroup.setSelectedObjectValue(value, key);
+ } else if (displayGroup.selectedObjects().size() > 1) {
+ // displayGroup has more than one object
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (!displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+
+ } // end checking size of displayGroup
+
+ } else // values aspect not bound
+ {
+ // use objects group if specified
+ EODisplayGroup sourceGroup = displayGroupForAspect(ObjectsAspect);
+ if (sourceGroup == null) {
+ // fall back on titles group
+ sourceGroup = displayGroupForAspect(TitlesAspect);
+ }
+
+ if (sourceGroup != null) {
+ int index = component.getSelectedIndex();
+ if (index != -1) {
+ sourceGroup.setSelectionIndexes(new NSArray(new Integer(index)));
+ } else {
+ sourceGroup.setSelectedObject(null);
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // interface ActionListener
+
+ /**
+ * Updates object on action performed.
+ */
+ public void actionPerformed(ActionEvent evt) {
+ writeValueToDisplayGroup();
+ }
+
+ // interface FocusListener
+
+ /**
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
+ }
+ }
+ }
+
+ /**
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (component().isEditable()) {
+ if (endEditing()) {
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
+ }
+ }
+ }
+ }
+ }
+
+ // convenience
+
+ private JComboBox component() {
+ return (JComboBox) object();
+ }
+
+ /**
+ * Used as the data model for the controlled combo box.
+ */
+ private class ComboBoxAssociationModel extends AbstractListModel implements ComboBoxModel {
+ EODisplayGroup displayGroup;
+ String key;
+ Object selectedItem;
+
+ ComboBoxAssociationModel(EODisplayGroup aDisplayGroup, String aKey) {
+ displayGroup = aDisplayGroup;
+ key = aKey;
+ selectedItem = null;
+ }
+
+ public Object getElementAt(int index) {
+ return displayGroup.valueForObjectAtIndex(index, key);
+ }
+
+ public int getSize() {
+ return displayGroup.displayedObjects().count();
+ }
+
+ public void setSelectedItem(Object anItem) { // System.out.println( "setSelectedItem: " + anItem );
+ selectedItem = anItem;
+
+ // must do this to notify an editable combo,
+ // otherwise the wrong value appears.
+ fireContentsChanged(this, -1, -1);
+ }
+
+ public Object getSelectedItem() { // System.out.println( "getSelectedItem: " + selectedItem );
+ return selectedItem;
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.13 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.13 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.12 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.12 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.11 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.11 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.10 2001/07/23 20:17:56 mpowers
- * Now works as an overview association if the values aspect is not bound.
+ * Revision 1.10 2001/07/23 20:17:56 mpowers Now works as an overview
+ * association if the values aspect is not bound.
*
- * Revision 1.9 2001/06/30 14:57:29 mpowers
- * Removed a println.
+ * Revision 1.9 2001/06/30 14:57:29 mpowers Removed a println.
*
- * Revision 1.8 2001/06/29 22:28:19 mpowers
- * Tabs to spaces.
+ * Revision 1.8 2001/06/29 22:28:19 mpowers Tabs to spaces.
*
- * Revision 1.7 2001/06/29 22:17:31 mpowers
- * Now updating the component on establishConnection.
+ * Revision 1.7 2001/06/29 22:17:31 mpowers Now updating the component on
+ * establishConnection.
*
- * Revision 1.6 2001/05/14 15:24:49 mpowers
- * Only updating if change was made. Feels like I had fixed this here before.
+ * Revision 1.6 2001/05/14 15:24:49 mpowers Only updating if change was made.
+ * Feels like I had fixed this here before.
*
- * Revision 1.5 2001/04/09 21:41:08 mpowers
- * Fixed a bug I thought that I had fixed before.
+ * Revision 1.5 2001/04/09 21:41:08 mpowers Fixed a bug I thought that I had
+ * fixed before.
*
- * Revision 1.4 2001/03/01 20:37:17 mpowers
- * Updated docs to emphasize that titles aspect is optional.
+ * Revision 1.4 2001/03/01 20:37:17 mpowers Updated docs to emphasize that
+ * titles aspect is optional.
*
- * Revision 1.3 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.3 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.2 2001/01/10 17:01:08 mpowers
- * Caught a common developer error.
+ * Revision 1.2 2001/01/10 17:01:08 mpowers Caught a common developer error.
*
- * Revision 1.1.1.1 2000/12/21 15:48:43 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:43 mpowers Contributing wotonomy.
*
- * Revision 1.8 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.8 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DateAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DateAssociation.java
index ba50879..c201ae3 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DateAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DateAssociation.java
@@ -36,578 +36,430 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* DateAssociation binds any component that has a set and get Date methods and
-* fire actions events when the date has been changed. Bindings are:
-* <ul>
-* <li>value: a property convertable to/from a date</li>
-* <li>editable: a boolean property that determines whether
-* the user can edit the date in the component</li>
-* <li>enabled: a boolean property that determines whether
-* the component is enabled or disabled</li>
-* </ul>
-*
-* @author rob@yahoo.com
-* @version $Revision: 904 $
-*/
-public class DateAssociation extends EOAssociation
- implements ActionListener, FocusListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect, EditableAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "date", "enabled", "editable"
- } );
-
- private final static NSSelector getDate =
- new NSSelector( "getDate" );
- private final static NSSelector setDate =
- new NSSelector( "setDate",
- new Class[] { Date.class } );
- private final static NSSelector addActionListener =
- new NSSelector( "addActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector removeActionListener =
- new NSSelector( "removeActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector addFocusListener =
- new NSSelector( "addFocusListener",
- new Class[] { FocusListener.class } );
- private final static NSSelector removeFocusListener =
- new NSSelector( "removeFocusListener",
- new Class[] { FocusListener.class } );
- private final static NSSelector setEditable =
- new NSSelector( "setEditable",
- new Class[] { boolean.class } );
+ * DateAssociation binds any component that has a set and get Date methods and
+ * fire actions events when the date has been changed. Bindings are:
+ * <ul>
+ * <li>value: a property convertable to/from a date</li>
+ * <li>editable: a boolean property that determines whether the user can edit
+ * the date in the component</li>
+ * <li>enabled: a boolean property that determines whether the component is
+ * enabled or disabled</li>
+ * </ul>
+ *
+ * @author rob@yahoo.com
+ * @version $Revision: 904 $
+ */
+public class DateAssociation extends EOAssociation implements ActionListener, FocusListener {
+ static final NSArray aspects = new NSArray(new Object[] { ValueAspect, EnabledAspect, EditableAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "date", "enabled", "editable" });
+
+ private final static NSSelector getDate = new NSSelector("getDate");
+ private final static NSSelector setDate = new NSSelector("setDate", new Class[] { Date.class });
+ private final static NSSelector addActionListener = new NSSelector("addActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector removeActionListener = new NSSelector("removeActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector addFocusListener = new NSSelector("addFocusListener",
+ new Class[] { FocusListener.class });
+ private final static NSSelector removeFocusListener = new NSSelector("removeFocusListener",
+ new Class[] { FocusListener.class });
+ private final static NSSelector setEditable = new NSSelector("setEditable", new Class[] { boolean.class });
// dirty handling
private boolean needsUpdate;
- private Date nullValue; // placeholder for null value flag
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public DateAssociation ( Object anObject )
- {
- super( anObject );
+ private Date nullValue; // placeholder for null value flag
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public DateAssociation(Object anObject) {
+ super(anObject);
needsUpdate = false;
- nullValue = null;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return setDate.implementedByObject( anObject );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * attempts to add this class as an ActionListener
- * and Focus Listener to the specified object.
- */
- public void establishConnection ()
- {
+ nullValue = null;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return setDate.implementedByObject(anObject);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation attempts to add this class as an ActionListener and Focus
+ * Listener to the specified object.
+ */
+ public void establishConnection() {
Object component = object();
- try
- {
- if ( addActionListener.implementedByObject( component ) )
- {
- addActionListener.invoke( component, this );
+ try {
+ if (addActionListener.implementedByObject(component)) {
+ addActionListener.invoke(component, this);
}
- if ( addFocusListener.implementedByObject( component ) )
- {
- addFocusListener.invoke( component, this );
+ if (addFocusListener.implementedByObject(component)) {
+ addFocusListener.invoke(component, this);
}
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while establishing connection", exc );
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while establishing connection", exc);
}
- super.establishConnection();
+ super.establishConnection();
// forces update from bindings
subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
Object component = object();
- try
- {
- if ( removeActionListener.implementedByObject( component ) )
- {
- removeActionListener.invoke( component, this );
+ try {
+ if (removeActionListener.implementedByObject(component)) {
+ removeActionListener.invoke(component, this);
}
- if ( removeFocusListener.implementedByObject( component ) )
- {
- removeFocusListener.invoke( component, this );
+ if (removeFocusListener.implementedByObject(component)) {
+ removeFocusListener.invoke(component, this);
}
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while breaking connection", exc);
}
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while breaking connection", exc );
- }
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
Object component = object();
EODisplayGroup displayGroup;
String key;
Object value;
// value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- if ( component instanceof Component )
- {
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
- }
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- } else {
-
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking size of displayGroup
-
- // convert value to date
- try
- {
- Date dateValue = null;
- // (Date) ValueConverter.convertObjectToClass( value, Date.class );
-
- if ( value instanceof Date )
- {
- dateValue = (Date) value;
- }
-
- if ( ( dateValue == null ) && ( value instanceof Calendar ) )
- {
- dateValue = ( ( Calendar )value ).getTime();
- }
-
- if ( dateValue == null )
- {
- // current time (placeholder)
- nullValue = new Date();
- dateValue = nullValue;
- }
- else
- {
- nullValue = null;
- }
-
- if ( !dateValue.equals( getDate.invoke( component ) ) )
- { // No need to update if there is no change.
- setDate.invoke( component, dateValue );
- needsUpdate = false;
- }
-
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection", exc );
- }
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ if (component instanceof Component) {
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+ }
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else {
+
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking size of displayGroup
+
+ // convert value to date
+ try {
+ Date dateValue = null;
+ // (Date) ValueConverter.convertObjectToClass( value, Date.class );
+
+ if (value instanceof Date) {
+ dateValue = (Date) value;
+ }
+
+ if ((dateValue == null) && (value instanceof Calendar)) {
+ dateValue = ((Calendar) value).getTime();
+ }
+
+ if (dateValue == null) {
+ // current time (placeholder)
+ nullValue = new Date();
+ dateValue = nullValue;
+ } else {
+ nullValue = null;
+ }
+
+ if (!dateValue.equals(getDate.invoke(component))) { // No need to update if there is no change.
+ setDate.invoke(component, dateValue);
+ needsUpdate = false;
+ }
+
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection", exc);
+ }
}
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- key = displayGroupKeyForAspect( EnabledAspect );
- if ( ( ( displayGroup != null ) || ( key != null ) )
- && ( component instanceof Component ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ key = displayGroupKeyForAspect(EnabledAspect);
+ if (((displayGroup != null) || (key != null)) && (component instanceof Component)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
value = key;
}
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() != ((Component)component).isEnabled() )
- {
- ((Component)component).setEnabled( converted.booleanValue() );
- }
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != ((Component) component).isEnabled()) {
+ ((Component) component).setEnabled(converted.booleanValue());
+ }
}
// editable aspect
- displayGroup = displayGroupForAspect( EditableAspect );
- key = displayGroupKeyForAspect( EditableAspect );
- if ( ( ( displayGroup != null ) || ( key != null ) )
- && ( setEditable.implementedByObject( component ) ) )
- {
- try
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group as a value
- value = key;
- }
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- setEditable.invoke( component, converted );
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection (editable aspect)", exc );
+ displayGroup = displayGroupForAspect(EditableAspect);
+ key = displayGroupKeyForAspect(EditableAspect);
+ if (((displayGroup != null) || (key != null)) && (setEditable.implementedByObject(component))) {
+ try {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group as a value
+ value = key;
+ }
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ setEditable.invoke(component, converted);
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection (editable aspect)", exc);
}
}
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
return writeValueToDisplayGroup();
- }
+ }
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- if ( !needsUpdate ) return true;
-
- EODisplayGroup displayGroup =
- displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( ValueAspect );
- Object component = object();
- Object value = null;
- try
- {
- if ( getDate.implementedByObject( component ) )
- {
- value = getDate.invoke( component );
- }
- if ( nullValue != null )
- {
- if ( nullValue.equals( value ) )
- {
- value = null;
- }
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error updating display group", exc );
- }
-
- needsUpdate = false;
-
- boolean returnValue = true;
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- returnValue = false;
- }
- }
- return returnValue;
-
- }
- return false;
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ if (!needsUpdate)
+ return true;
+
+ EODisplayGroup displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(ValueAspect);
+ Object component = object();
+ Object value = null;
+ try {
+ if (getDate.implementedByObject(component)) {
+ value = getDate.invoke(component);
+ }
+ if (nullValue != null) {
+ if (nullValue.equals(value)) {
+ value = null;
+ }
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error updating display group", exc);
+ }
+
+ needsUpdate = false;
+
+ boolean returnValue = true;
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (!displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+
+ }
+ return false;
}
- // interface ActionListener
+ // interface ActionListener
/**
- * Updates object on action performed.
- */
- public void actionPerformed( ActionEvent evt )
- {
- needsUpdate = true;
- writeValueToDisplayGroup(); // TODO: Should we do this here or on focus lost?
+ * Updates object on action performed.
+ */
+ public void actionPerformed(ActionEvent evt) {
+ needsUpdate = true;
+ writeValueToDisplayGroup(); // TODO: Should we do this here or on focus lost?
}
- // interface FocusListener
+ // interface FocusListener
/**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
Object o;
EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
}
}
- }
+ }
/**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( endEditing() )
- {
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (endEditing()) {
Object o;
EODisplayGroup displayGroup;
Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
}
}
- }
- else
- {
+ } else {
// probably should notify of a validation error here,
// but how to also handle actionPerformed without copying code?
-/*
- Object value = null;
- try
- {
- if ( getText.implementedByObject( object() ) )
- {
- value = getText.invoke( object() );
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error updating display group", exc );
- }
-
- EODisplayGroup displayGroup =
- displayGroupForAspect( ValueAspect );
- String key = displayGroupKeyForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- if ( displayGroup.associationFailedToValidateValue(
- this, (String) value, key, object(),
- "That format was not recognized." ) )
- {
- new net.wotonomy.ui.swing.util.StackTraceInspector();
- }
- if ( object() instanceof Component )
- {
- ((Component)object()).requestFocus();
- }
- }
-*/
+ /*
+ * Object value = null; try { if ( getText.implementedByObject( object() ) ) {
+ * value = getText.invoke( object() ); } } catch ( Exception exc ) { throw new
+ * WotonomyException( "Error updating display group", exc ); }
+ *
+ * EODisplayGroup displayGroup = displayGroupForAspect( ValueAspect ); String
+ * key = displayGroupKeyForAspect( ValueAspect ); if ( displayGroup != null ) {
+ * if ( displayGroup.associationFailedToValidateValue( this, (String) value,
+ * key, object(), "That format was not recognized." ) ) { new
+ * net.wotonomy.ui.swing.util.StackTraceInspector(); } if ( object() instanceof
+ * Component ) { ((Component)object()).requestFocus(); } }
+ */
}
- }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.7 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.6 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.6 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.5 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.5 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.4 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.4 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.3 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.3 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.2 2001/01/17 16:25:26 mpowers
- * Now catching null values from data object.
+ * Revision 1.2 2001/01/17 16:25:26 mpowers Now catching null values from data
+ * object.
*
- * Revision 1.1 2001/01/10 22:26:32 mpowers
- * Contributing DateAssociation.
+ * Revision 1.1 2001/01/10 22:26:32 mpowers Contributing DateAssociation.
*
- * Revision 1.1 2001/01/10 21:30:27 rglista
- * Initial checkin
+ * Revision 1.1 2001/01/10 21:30:27 rglista Initial checkin
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupActionAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupActionAssociation.java
index 290480d..f891ede 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupActionAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupActionAssociation.java
@@ -27,108 +27,82 @@ import net.wotonomy.foundation.internal.WotonomyException;
import net.wotonomy.ui.EODisplayGroup;
/**
-* ActionAssociation binds any ActionEvent broadcaster
-* (typically Buttons and the like) to a display group,
-* but invokes actions directly on the bound display
-* group rather than the selected objects.
-* Bindings are:
-* <ul>
-* <li>action: a method to be invoked on the bound display group.
-* If the argument aspect is bound, the method must take
-* one argument. Otherwise, the method must take no arguments.</li>
-* <li>argument: the attribute of the selected object(s) (possibly
-* from a different display group) that will be used as an argument
-* to the action method</li>
-* <li>enabled: a boolean property that determines whether
-* the controlled component is enabled</li>
-* <li>visible: a boolean property that determines whether
-* the controlled component is visible</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class DisplayGroupActionAssociation extends ActionAssociation
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ActionAspect, ArgumentAspect, EnabledAspect, VisibleAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "target"
- } );
-
- static NSSelector addActionListener =
- new NSSelector( "addActionListener",
- new Class[] { ActionListener.class } );
- static NSSelector removeActionListener =
- new NSSelector( "removeActionListener",
- new Class[] { ActionListener.class } );
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public DisplayGroupActionAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- // interface ActionListener
-
- public void actionPerformed( ActionEvent evt )
- {
+ * ActionAssociation binds any ActionEvent broadcaster (typically Buttons and
+ * the like) to a display group, but invokes actions directly on the bound
+ * display group rather than the selected objects. Bindings are:
+ * <ul>
+ * <li>action: a method to be invoked on the bound display group. If the
+ * argument aspect is bound, the method must take one argument. Otherwise, the
+ * method must take no arguments.</li>
+ * <li>argument: the attribute of the selected object(s) (possibly from a
+ * different display group) that will be used as an argument to the action
+ * method</li>
+ * <li>enabled: a boolean property that determines whether the controlled
+ * component is enabled</li>
+ * <li>visible: a boolean property that determines whether the controlled
+ * component is visible</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class DisplayGroupActionAssociation extends ActionAssociation {
+ static final NSArray aspects = new NSArray(
+ new Object[] { ActionAspect, ArgumentAspect, EnabledAspect, VisibleAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "target" });
+
+ static NSSelector addActionListener = new NSSelector("addActionListener", new Class[] { ActionListener.class });
+ static NSSelector removeActionListener = new NSSelector("removeActionListener",
+ new Class[] { ActionListener.class });
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public DisplayGroupActionAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ // interface ActionListener
+
+ public void actionPerformed(ActionEvent evt) {
EODisplayGroup actionDisplayGroup = null;
String actionKey = null;
-
+
// action aspect
- actionDisplayGroup = displayGroupForAspect( ActionAspect );
- if ( actionDisplayGroup != null )
- {
- actionKey = displayGroupKeyForAspect( ActionAspect );
+ actionDisplayGroup = displayGroupForAspect(ActionAspect);
+ if (actionDisplayGroup != null) {
+ actionKey = displayGroupKeyForAspect(ActionAspect);
- //TODO: argument aspect not implemented
+ // TODO: argument aspect not implemented
- try
- {
- NSSelector.invoke( actionKey, actionDisplayGroup );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( "DisplayGroupActionAssociation: "
- + "error invoking action: " + actionKey, exc );
+ try {
+ NSSelector.invoke(actionKey, actionDisplayGroup);
+ } catch (Exception exc) {
+ throw new WotonomyException("DisplayGroupActionAssociation: " + "error invoking action: " + actionKey,
+ exc);
}
}
}
-
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1.1.1 2000/12/21 15:48:46 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:46 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupInspector.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupInspector.java
index c8ecd36..d782252 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupInspector.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupInspector.java
@@ -35,86 +35,75 @@ import net.wotonomy.ui.swing.util.ObjectInspector;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* The DisplayGroupInspector displays a JFrame that
-* shows allows you to view and manipulate a display group.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
+ * The DisplayGroupInspector displays a JFrame that shows allows you to view and
+ * manipulate a display group.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
-public class DisplayGroupInspector
-{
- protected JList list;
- protected EODisplayGroup displayGroup;
-
-/**
-* Displays and manipulats the specified display group.
-*/
- public DisplayGroupInspector( EODisplayGroup aDisplayGroup )
- {
- displayGroup = aDisplayGroup;
-
- list = new JList();
- list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked( MouseEvent e )
- {
- if ( e.getClickCount() == 2 )
- {
- Object selection = displayGroup.selectedObject();
- if ( selection != null )
- {
- new ObjectInspector( selection );
- }
- }
- }
- } );
-
- EOAssociation assoc = new ListAssociation( list );
- assoc.bindAspect( EOAssociation.TitlesAspect, displayGroup, "" );
- assoc.establishConnection();
-
- initLayout();
-
- }
-
- protected void initLayout()
- {
- JPanel panel = new JPanel();
- panel.setLayout( new BorderLayout() );
- panel.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
-
- JScrollPane scrollPane = new JScrollPane( list );
- scrollPane.setPreferredSize( new Dimension( 200, 200 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
-
- JFrame window = new JFrame();
- window.setTitle( "Display Group Inspector" );
- window.getContentPane().add( panel );
-
- window.pack();
- WindowUtilities.cascade( window );
- window.show();
- }
+public class DisplayGroupInspector {
+ protected JList list;
+ protected EODisplayGroup displayGroup;
+
+ /**
+ * Displays and manipulats the specified display group.
+ */
+ public DisplayGroupInspector(EODisplayGroup aDisplayGroup) {
+ displayGroup = aDisplayGroup;
+
+ list = new JList();
+ list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ Object selection = displayGroup.selectedObject();
+ if (selection != null) {
+ new ObjectInspector(selection);
+ }
+ }
+ }
+ });
+
+ EOAssociation assoc = new ListAssociation(list);
+ assoc.bindAspect(EOAssociation.TitlesAspect, displayGroup, "");
+ assoc.establishConnection();
+
+ initLayout();
+
+ }
+
+ protected void initLayout() {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.setBorder(new EmptyBorder(10, 10, 10, 10));
+
+ JScrollPane scrollPane = new JScrollPane(list);
+ scrollPane.setPreferredSize(new Dimension(200, 200));
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+ JFrame window = new JFrame();
+ window.setTitle("Display Group Inspector");
+ window.getContentPane().add(panel);
+
+ window.pack();
+ WindowUtilities.cascade(window);
+ window.show();
+ }
}
-
+
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2003/06/26 23:28:00 mpowers
- * Added double click.
+ * Revision 1.2 2003/06/26 23:28:00 mpowers Added double click.
*
- * Revision 1.1 2001/05/29 19:57:47 mpowers
- * Added some neglected files.
+ * Revision 1.1 2001/05/29 19:57:47 mpowers Added some neglected files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupNode.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupNode.java
index 1756285..d530f36 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupNode.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/DisplayGroupNode.java
@@ -46,901 +46,727 @@ import net.wotonomy.ui.EODisplayGroup;
import net.wotonomy.ui.swing.TreeModelAssociation.DelegatingTreeDataSource;
/**
-* DisplayGroupNodes are used as nodes in the
-* TreeModelAssociation's implementation of TreeModel,
-* and is tightly coupled with TreeModelAssociation
-* and MasterDetailAssociation. <br><br>
-*
-* Even though it is no longer package access,
-* don't rely on this class because we want to
-* have the option of completely replacing this
-* approach in the future.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
- abstract public class DisplayGroupNode
- extends EODisplayGroup
- {
- protected TreeModelAssociation parentAssociation;
- protected EODelayedObserver targetObserver;
- protected NSMutableDictionary childNodes;
- protected EODisplayGroup parentGroup;
- protected Object target;
- protected boolean isFetched;
- protected boolean isFetchNeeded;
- protected boolean useParentOrderings;
- protected boolean useParentQualifier;
-
- /**
- * Constructor for all nodes.
- * Root node must have a null target.
- */
- public DisplayGroupNode(
- TreeModelAssociation aParentAssociation,
- EODisplayGroup aParentGroup,
- Object aTarget )
- {
+ * DisplayGroupNodes are used as nodes in the TreeModelAssociation's
+ * implementation of TreeModel, and is tightly coupled with TreeModelAssociation
+ * and MasterDetailAssociation. <br>
+ * <br>
+ *
+ * Even though it is no longer package access, don't rely on this class because
+ * we want to have the option of completely replacing this approach in the
+ * future.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+abstract public class DisplayGroupNode extends EODisplayGroup {
+ protected TreeModelAssociation parentAssociation;
+ protected EODelayedObserver targetObserver;
+ protected NSMutableDictionary childNodes;
+ protected EODisplayGroup parentGroup;
+ protected Object target;
+ protected boolean isFetched;
+ protected boolean isFetchNeeded;
+ protected boolean useParentOrderings;
+ protected boolean useParentQualifier;
+
+ /**
+ * Constructor for all nodes. Root node must have a null target.
+ */
+ public DisplayGroupNode(TreeModelAssociation aParentAssociation, EODisplayGroup aParentGroup, Object aTarget) {
//new net.wotonomy.ui.swing.util.StackTraceInspector( ""+aTarget );
//System.out.println( "DisplayGroupNode.new: " + aTarget );
- parentAssociation = aParentAssociation;
- target = null;
- targetObserver = null;
- parentGroup = aParentGroup;
- childNodes = new NSMutableDictionary();
- isFetched = false;
- isFetchNeeded = false;
- useParentOrderings = true;
- useParentQualifier = true;
-
- EODataSource parentSource = null;
- if ( parentGroup != null )
- {
- parentSource = parentGroup.dataSource();
- }
- else
- if ( parentAssociation.titlesDisplayGroup != null )
- {
- parentSource = parentAssociation.titlesDisplayGroup.dataSource();
- }
-
- // create child datasource
- if ( aTarget != null ) // not root node
- {
- if ( parentAssociation.childrenKey != null )
- {
- if ( parentSource == null )
- {
- throw new WotonomyException(
- "Need a data source when children aspect is bound." );
- }
-
- NSArray displayedObjects = parentGroup.displayedObjects();
- EODataSource childSource = parentSource.dataSourceQualifiedByKey(
- parentAssociation.childrenKey );
- childSource.qualifyWithRelationshipKey(
- parentAssociation.childrenKey, aTarget );
-
- // create new display group using child data source
- this.setDataSource( childSource );
-
- // establish observer for target object
- setTarget( aTarget );
- }
- else // only titles is bound
- {
- // establish observer for target object
- setTarget( aTarget );
-
- setDataSource( new PropertyDataSource()
- {
- public NSArray fetchObjects()
- {
- return new NSArray();
- }
- } );
- }
- }
- else // else root node
- {
- // root node uses PropertyDataSource by default
- if ( parentSource == null )
- {
- setDataSource( new PropertyDataSource()
- {
- public NSArray fetchObjects()
- {
- if ( parentGroup != null )
- {
- return parentGroup.displayedObjects();
- }
- return null;
- }
- } );
- }
- else
- {
- // root node uses parent source directly
- setDataSource( parentSource );
- }
- }
- }
-
- /**
- * Overridden to unregister as an editor of the editing context,
- * since we don't directly present a user interface.
- */
- public void setDataSource ( EODataSource aDataSource )
- {
- super.setDataSource( aDataSource );
- if ( ( aDataSource != null )
- && ( aDataSource.editingContext() != null ) )
- {
- aDataSource.editingContext().removeEditor( this );
- }
- }
-
- /**
- * Returns whether the node should call fetch().
- */
- protected boolean isFetched()
- {
- if ( isFetchNeeded() )
- {
- setFetchNeeded( false );
- fetch();
- }
- return isFetched;
- }
-
- /**
- * Sets whether the node should call fetch().
- */
- protected void setFetched( boolean fetched )
- {
+ parentAssociation = aParentAssociation;
+ target = null;
+ targetObserver = null;
+ parentGroup = aParentGroup;
+ childNodes = new NSMutableDictionary();
+ isFetched = false;
+ isFetchNeeded = false;
+ useParentOrderings = true;
+ useParentQualifier = true;
+
+ EODataSource parentSource = null;
+ if (parentGroup != null) {
+ parentSource = parentGroup.dataSource();
+ } else if (parentAssociation.titlesDisplayGroup != null) {
+ parentSource = parentAssociation.titlesDisplayGroup.dataSource();
+ }
+
+ // create child datasource
+ if (aTarget != null) // not root node
+ {
+ if (parentAssociation.childrenKey != null) {
+ if (parentSource == null) {
+ throw new WotonomyException("Need a data source when children aspect is bound.");
+ }
+
+ NSArray displayedObjects = parentGroup.displayedObjects();
+ EODataSource childSource = parentSource.dataSourceQualifiedByKey(parentAssociation.childrenKey);
+ childSource.qualifyWithRelationshipKey(parentAssociation.childrenKey, aTarget);
+
+ // create new display group using child data source
+ this.setDataSource(childSource);
+
+ // establish observer for target object
+ setTarget(aTarget);
+ } else // only titles is bound
+ {
+ // establish observer for target object
+ setTarget(aTarget);
+
+ setDataSource(new PropertyDataSource() {
+ public NSArray fetchObjects() {
+ return new NSArray();
+ }
+ });
+ }
+ } else // else root node
+ {
+ // root node uses PropertyDataSource by default
+ if (parentSource == null) {
+ setDataSource(new PropertyDataSource() {
+ public NSArray fetchObjects() {
+ if (parentGroup != null) {
+ return parentGroup.displayedObjects();
+ }
+ return null;
+ }
+ });
+ } else {
+ // root node uses parent source directly
+ setDataSource(parentSource);
+ }
+ }
+ }
+
+ /**
+ * Overridden to unregister as an editor of the editing context, since we don't
+ * directly present a user interface.
+ */
+ public void setDataSource(EODataSource aDataSource) {
+ super.setDataSource(aDataSource);
+ if ((aDataSource != null) && (aDataSource.editingContext() != null)) {
+ aDataSource.editingContext().removeEditor(this);
+ }
+ }
+
+ /**
+ * Returns whether the node should call fetch().
+ */
+ protected boolean isFetched() {
+ if (isFetchNeeded()) {
+ setFetchNeeded(false);
+ fetch();
+ }
+ return isFetched;
+ }
+
+ /**
+ * Sets whether the node should call fetch().
+ */
+ protected void setFetched(boolean fetched) {
//System.out.println( "DisplayGroupNode.setFetched: " + fetched + " : " + this + " : " + target );
//net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
- isFetched = fetched;
- }
-
- /**
- * Returns whether the node is in need of a refetch.
- */
- protected boolean isFetchNeeded()
- {
- return isFetchNeeded;
- }
-
- /**
- * Returns whether the node should call fetch().
- */
- protected void setFetchNeeded( boolean fetchNeeded )
- {
+ isFetched = fetched;
+ }
+
+ /**
+ * Returns whether the node is in need of a refetch.
+ */
+ protected boolean isFetchNeeded() {
+ return isFetchNeeded;
+ }
+
+ /**
+ * Returns whether the node should call fetch().
+ */
+ protected void setFetchNeeded(boolean fetchNeeded) {
//System.out.println( "DisplayGroupNode.setFetchNeeded: " + fetchNeeded + " : " + this + " : " + target );
//net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
- isFetchNeeded = fetchNeeded;
- }
-
- /**
- * Subclasses should override this method to fire an appropriate insertion event.
- */
- protected void fireNodesInserted( Object[] path, int[] indexes, Object[] objects )
- {
+ isFetchNeeded = fetchNeeded;
+ }
+
+ /**
+ * Subclasses should override this method to fire an appropriate insertion
+ * event.
+ */
+ protected void fireNodesInserted(Object[] path, int[] indexes, Object[] objects) {
//System.out.println( "fireNodesInserted: " + this );
- parentAssociation.fireTreeNodesInserted(
- this, path, indexes, objects );
- }
-
- /**
- * Subclasses should override this method to fire an appropriate change event.
- */
- protected void fireNodesChanged( Object[] path, int[] indexes, Object[] objects )
- {
+ parentAssociation.fireTreeNodesInserted(this, path, indexes, objects);
+ }
+
+ /**
+ * Subclasses should override this method to fire an appropriate change event.
+ */
+ protected void fireNodesChanged(Object[] path, int[] indexes, Object[] objects) {
//System.out.println( "fireNodesChanged: " + this );
- parentAssociation.fireTreeNodesChanged(
- this, path, indexes, objects );
- }
-
- /**
- * Subclasses should override this method to fire an appropriate deletion event.
- */
- protected void fireNodesRemoved( Object[] path, int[] indexes, Object[] objects )
- {
+ parentAssociation.fireTreeNodesChanged(this, path, indexes, objects);
+ }
+
+ /**
+ * Subclasses should override this method to fire an appropriate deletion event.
+ */
+ protected void fireNodesRemoved(Object[] path, int[] indexes, Object[] objects) {
//System.out.println( "fireNodesRemoved: " + this );
- parentAssociation.fireTreeNodesRemoved(
- this, path, indexes, objects );
- }
-
- /**
- * Subclasses should override this method to fire an appropriate event.
- */
- protected void fireStructureChanged( Object[] path, int[] indexes, Object[] objects )
- {
- parentAssociation.fireTreeStructureChanged(
- this, path, indexes, objects );
- }
-
- /**
- * Overridden to broadcast a tree event after super executes.
- */
- public void insertObjectAtIndex ( Object anObject, int anIndex )
- {
- int count = getChildCount(); // gets old count
- if ( target == null )
- {
- // if root node, forward to parent:
- // circumventing delegating data source, if any
- EODataSource dataSource = parentGroup.dataSource();
- if ( dataSource instanceof DelegatingTreeDataSource )
- {
- parentGroup.setDataSource(
- ((DelegatingTreeDataSource)dataSource).delegateDataSource );
- }
- parentGroup.insertObjectAtIndex( anObject, anIndex );
- if ( dataSource instanceof DelegatingTreeDataSource )
- {
- parentGroup.setDataSource( dataSource );
- }
- return; // prevent event from firing (?)
- }
- else // not root node
- {
- super.insertObjectAtIndex( anObject, anIndex );
- }
- }
-
- /**
- * Overridden to broadcast a tree event after super executes.
- */
- public boolean deleteObjectAtIndex ( int anIndex )
- {
- boolean result;
- Object node = getChildNodeAt( anIndex );
- if ( target == null )
- {
- // if root node, forward to parent:
- result = parentGroup.deleteObjectAtIndex( anIndex );
- }
- else // not root node
- {
- result = super.deleteObjectAtIndex( anIndex );
- }
-
- return result;
- }
-
- /**
- * Returns the child node that corresponds to the
- * specified index, creating it if necessary.
- * The index must be within bounds or an exception
- * is thrown.
- */
- public DisplayGroupNode getChildNodeAt( int anIndex )
- {
- boolean wasFetched = isFetched();
- if ( ! wasFetched ) fetch();
- Object o = displayedObjects.objectAtIndex( anIndex );
- DisplayGroupNode result = getChildNodeForObject( o );
- if ( result == null )
- {
- result = createChildNodeForObject( o );
- }
- return result;
- }
-
- /**
- * Returns a child node that corresponds to the
- * specified object, returning null if not found.
- */
- protected DisplayGroupNode getChildNodeForObject( Object anObject )
- {
- return (DisplayGroupNode)
- childNodes.objectForKey( new ReferenceKey( anObject ) );
- }
-
- /**
- * Creates a child node that corresponds to the
- * specified object.
- */
- private DisplayGroupNode createChildNodeForObject( Object anObject )
- {
- DisplayGroupNode result = parentAssociation.createNode( this, anObject );
- childNodes.setObjectForKey( result, new ReferenceKey( anObject ) );
- return result;
- }
-
- /**
- * Returns a tree path of all DisplayGroupNodes leading
- * to this node, including the root node (but excluding the
- * titles display group).
- */
- public TreePath treePath()
- {
- List path = new LinkedList();
- EODisplayGroup node = this;
- while ( node instanceof DisplayGroupNode )
- {
- // insert at head of list
- path.add( 0, node );
- node = ((DisplayGroupNode)node).parentGroup;
- }
- return new TreePath( path.toArray() );
- }
-
- /**
- * Overridden to return the parent group's
- * sort ordering if useParentOrderings is true.
- * useParentOrderings is true by default.
- */
- public NSArray sortOrderings()
- {
- if ( ( useParentOrderings )
- && ( parentGroup != null ) )
- {
- return parentGroup.sortOrderings();
- }
- return super.sortOrderings();
- }
-
- /**
- * Overridden to set useParentOrderings to false,
- * or true if aList is null.
- */
- public void setSortOrderings ( List aList )
- {
- if ( aList == null )
- {
- useParentOrderings = true;
- }
- else
- {
- useParentOrderings = false;
- super.setSortOrderings( aList );
- }
- }
-
- /**
- * Overridden to return the parent group's
- * qualifier if useParentQualifier is true.
- * useParentQualifier is true by default.
- */
- public EOQualifier qualifier()
- {
- if ( ( useParentQualifier )
- && ( parentGroup != null ) )
- {
- return parentGroup.qualifier();
- }
- return super.qualifier();
- }
-
- /**
- * Overridden to set useParentQualifier to false,
- * or true if aList is null.
- */
- public void setQualifier ( EOQualifier aQualifier )
- {
- if ( aQualifier == null )
- {
- useParentQualifier = true;
- }
- else
- {
- useParentQualifier = false;
- super.setQualifier( aQualifier );
- }
- }
-
- /**
- * Overridden to set isFetched to true.
- */
- public boolean fetch()
- {
+ parentAssociation.fireTreeNodesRemoved(this, path, indexes, objects);
+ }
+
+ /**
+ * Subclasses should override this method to fire an appropriate event.
+ */
+ protected void fireStructureChanged(Object[] path, int[] indexes, Object[] objects) {
+ parentAssociation.fireTreeStructureChanged(this, path, indexes, objects);
+ }
+
+ /**
+ * Overridden to broadcast a tree event after super executes.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ int count = getChildCount(); // gets old count
+ if (target == null) {
+ // if root node, forward to parent:
+ // circumventing delegating data source, if any
+ EODataSource dataSource = parentGroup.dataSource();
+ if (dataSource instanceof DelegatingTreeDataSource) {
+ parentGroup.setDataSource(((DelegatingTreeDataSource) dataSource).delegateDataSource);
+ }
+ parentGroup.insertObjectAtIndex(anObject, anIndex);
+ if (dataSource instanceof DelegatingTreeDataSource) {
+ parentGroup.setDataSource(dataSource);
+ }
+ return; // prevent event from firing (?)
+ } else // not root node
+ {
+ super.insertObjectAtIndex(anObject, anIndex);
+ }
+ }
+
+ /**
+ * Overridden to broadcast a tree event after super executes.
+ */
+ public boolean deleteObjectAtIndex(int anIndex) {
+ boolean result;
+ Object node = getChildNodeAt(anIndex);
+ if (target == null) {
+ // if root node, forward to parent:
+ result = parentGroup.deleteObjectAtIndex(anIndex);
+ } else // not root node
+ {
+ result = super.deleteObjectAtIndex(anIndex);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the child node that corresponds to the specified index, creating it
+ * if necessary. The index must be within bounds or an exception is thrown.
+ */
+ public DisplayGroupNode getChildNodeAt(int anIndex) {
+ boolean wasFetched = isFetched();
+ if (!wasFetched)
+ fetch();
+ Object o = displayedObjects.objectAtIndex(anIndex);
+ DisplayGroupNode result = getChildNodeForObject(o);
+ if (result == null) {
+ result = createChildNodeForObject(o);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a child node that corresponds to the specified object, returning null
+ * if not found.
+ */
+ protected DisplayGroupNode getChildNodeForObject(Object anObject) {
+ return (DisplayGroupNode) childNodes.objectForKey(new ReferenceKey(anObject));
+ }
+
+ /**
+ * Creates a child node that corresponds to the specified object.
+ */
+ private DisplayGroupNode createChildNodeForObject(Object anObject) {
+ DisplayGroupNode result = parentAssociation.createNode(this, anObject);
+ childNodes.setObjectForKey(result, new ReferenceKey(anObject));
+ return result;
+ }
+
+ /**
+ * Returns a tree path of all DisplayGroupNodes leading to this node, including
+ * the root node (but excluding the titles display group).
+ */
+ public TreePath treePath() {
+ List path = new LinkedList();
+ EODisplayGroup node = this;
+ while (node instanceof DisplayGroupNode) {
+ // insert at head of list
+ path.add(0, node);
+ node = ((DisplayGroupNode) node).parentGroup;
+ }
+ return new TreePath(path.toArray());
+ }
+
+ /**
+ * Overridden to return the parent group's sort ordering if useParentOrderings
+ * is true. useParentOrderings is true by default.
+ */
+ public NSArray sortOrderings() {
+ if ((useParentOrderings) && (parentGroup != null)) {
+ return parentGroup.sortOrderings();
+ }
+ return super.sortOrderings();
+ }
+
+ /**
+ * Overridden to set useParentOrderings to false, or true if aList is null.
+ */
+ public void setSortOrderings(List aList) {
+ if (aList == null) {
+ useParentOrderings = true;
+ } else {
+ useParentOrderings = false;
+ super.setSortOrderings(aList);
+ }
+ }
+
+ /**
+ * Overridden to return the parent group's qualifier if useParentQualifier is
+ * true. useParentQualifier is true by default.
+ */
+ public EOQualifier qualifier() {
+ if ((useParentQualifier) && (parentGroup != null)) {
+ return parentGroup.qualifier();
+ }
+ return super.qualifier();
+ }
+
+ /**
+ * Overridden to set useParentQualifier to false, or true if aList is null.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ if (aQualifier == null) {
+ useParentQualifier = true;
+ } else {
+ useParentQualifier = false;
+ super.setQualifier(aQualifier);
+ }
+ }
+
+ /**
+ * Overridden to set isFetched to true.
+ */
+ public boolean fetch() {
//System.out.println( "DisplayGroupNode.fetch: " + this + " : " );
//if ( getClass().getName().indexOf( "Activity" ) != -1 )
//{
// new net.wotonomy.ui.swing.util.StackTraceInspector( this.toString() );
//}
- // set flag
- setFetched( true );
+ // set flag
+ setFetched(true);
- // skip root node
- if ( target == null ) return true;
+ // skip root node
+ if (target == null)
+ return true;
- // requalify
- dataSource().qualifyWithRelationshipKey(
- parentAssociation.childrenKey, target );
+ // requalify
+ dataSource().qualifyWithRelationshipKey(parentAssociation.childrenKey, target);
- // call to super
- return super.fetch();
+ // call to super
+ return super.fetch();
//boolean result = super.fetch();
//System.out.println( displayedObjects() );
//return result;
- }
-
- /**
- * Returns the object at the appropriate index
- * in the parent display group.
- */
- public Object object()
- {
- // if root node
- if ( target == null )
- {
- return parentAssociation.rootLabel();
- }
- return target;
- }
-
- /**
- * Returns the string value of the title property
- * on the object in the parent display group corresponding
- * to this index. The tree renderer asks JTrees to
- * call this method to retrieve a value for display.
- */
- public String toString()
- {
- Object result = getUserObject();
- if ( result == null ) result = "[null]";
- return result.toString();
- }
-
- // parts of interface TreeNode
-
- public int getChildCount()
- {
- if ( ! isFetched() ) fetch();
+ }
+
+ /**
+ * Returns the object at the appropriate index in the parent display group.
+ */
+ public Object object() {
+ // if root node
+ if (target == null) {
+ return parentAssociation.rootLabel();
+ }
+ return target;
+ }
+
+ /**
+ * Returns the string value of the title property on the object in the parent
+ * display group corresponding to this index. The tree renderer asks JTrees to
+ * call this method to retrieve a value for display.
+ */
+ public String toString() {
+ Object result = getUserObject();
+ if (result == null)
+ result = "[null]";
+ return result.toString();
+ }
+
+ // parts of interface TreeNode
+
+ public int getChildCount() {
+ if (!isFetched())
+ fetch();
//if ( toString().indexOf("154.16406")!=-1){
//System.out.println( "getChildCount: " + displayedObjects.count() + " : " + this );
//new RuntimeException().printStackTrace();
//net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
//}
- return displayedObjects.count();
- }
-
- public int getIndex(DisplayGroupNode node)
- {
- if ( ! isFetched() ) fetch();
- return displayedObjects.indexOfObject(
- ((DisplayGroupNode)node).target );
- }
-
- public boolean getAllowsChildren()
- {
- return true;
- }
-
- public boolean isLeaf()
- {
- // if not root node and isLeaf aspect is bound
- if ( ( target != null )
- && ( parentGroup != null )
- && ( parentAssociation.leafKey != null ) )
- {
- Object value;
- if ( parentAssociation.leafDisplayGroup != null )
- {
- value = parentGroup.valueForObject(
- target, parentAssociation.leafKey );
- }
- else
- {
- value = parentAssociation.leafKey;
- }
-
- // getBoolean returns true for zero, among other things
- Object result = ValueConverter.getBoolean( value );
- if ( result != null )
- {
- return ((Boolean)result).booleanValue();
- }
- }
-
- // otherwise, we have to fetch and return count
- return ( getChildCount() == 0 );
- }
-
- public Enumeration children()
- {
- int count = getChildCount();
- Vector v = new Vector();
- for ( int i = 0; i < count; i++ )
- {
- v.add( getChildNodeAt( i ) );
- }
- return v.elements();
- }
-
- // parts of interface MutableTreeNode
-
- public void insert(DisplayGroupNode aChild, int anIndex)
- {
- insertObjectAtIndex(
- ((DisplayGroupNode)aChild).object(), anIndex );
- }
-
- public void remove(int index)
- {
- deleteObjectAtIndex( index );
- }
-
- /**
- * Removes the node at the index corresponding
- * to the index of the object.
- */
- public void remove(DisplayGroupNode node)
- {
- remove( getIndex( node ) );
- }
-
- /**
- * Removes our object from the parent display group.
- */
- public void removeFromParent()
- {
- int index = parentGroup.displayedObjects().indexOfIdenticalObject( target );
- if ( index != NSArray.NotFound )
- {
- parentGroup.deleteObjectAtIndex( index );
- }
- else
- {
- throw new WotonomyException(
- "Object not found in parent group: " + target );
- }
- }
-
- /**
- * Removes our object from the parent display group
- * and adds it to the end of the specified node's children.
- */
- public void setParent(DisplayGroupNode newParent)
- {
- removeFromParent();
- newParent.insertObjectAtIndex(
- object(), newParent.displayedObjects.size() );
- }
-
- /**
- * Returns the value of the displayed property in the parent display group
- * at the index that corresponds to the index of this node.
- */
- public Object getUserObject()
- {
- return valueForKey( parentAssociation.titlesKey );
- }
-
- /**
- * Sets the value of the displayed property in the parent display group
- * at the index that corresponds to the index of this node.
- */
- public void setUserObject( Object aValue )
- {
- setValueForKey( aValue, parentAssociation.titlesKey );
- }
-
- /**
- * Returns a value from the object in the parent display group
- * at the index that corresponds to the index of this node.
- * For the root node, if the titles key is specified, the root
- * label is returned, otherwise null is returned.
- */
- public Object valueForKey( String aKey )
- {
- // if root node
- if ( target == null )
- {
- // compare by ref is okay for strings
- if ( aKey == parentAssociation.titlesKey )
- {
- return parentAssociation.rootLabel();
- }
- return null;
- }
- return parentGroup.valueForObject( target, aKey );
- }
-
- /**
- * Sets a value on the object in the parent display group
- * at the index that corresponds to the index of this node.
- * For the root node, this method only works if aKey is the
- * titlesAspect's key, otherwise does nothing.
- */
- public void setValueForKey(Object aValue, String aKey)
- {
- // if root node, return.
- if ( target == null )
- {
- // compare by ref is okay for strings
- if ( aKey == parentAssociation.titlesKey )
- {
- parentAssociation.setRootLabel( aValue );
-
- // how to handle root node? tree event docs don't say.
- fireNodesChanged ( treePath().getPath(),
- new int[] { 0 },
- new Object[] { this } );
- }
- return;
- }
-
- parentGroup.setValueForObject(
- aValue, target, aKey );
- }
-
- /**
- * Perform any clean up in this method.
- * The node will not be reused after this method is called.
- * This implementation removes itself from the parent's
- * set of child nodes, sets target and datasource to null,
- * and then calls disposeChildNodes().
- */
- protected void dispose()
- { //System.out.println( "dispose: " + this.getClass().getName() + " : " + this );
- if ( parentGroup != null )
- {
- ((DisplayGroupNode)parentGroup).childNodes.remove(
- new ReferenceKey( target ) );
- }
- setTarget( (Object) null );
- setDataSource( null );
- disposeChildNodes();
- }
-
- /**
- * Calls dispose() on all child nodes.
- */
- protected void disposeChildNodes()
- {
- Iterator i = new LinkedList(childNodes.values()).iterator();
- while ( i.hasNext() )
- {
- ((DisplayGroupNode) i.next()).dispose();
- }
- }
-
- /**
- * Called after the target object posts a change notification.
- * This implementation re-fetches which triggers
- * updateDisplayedObjects to broadcast any tree events.
- * This method marks the parent object as changed if:
- * (1) this object is not registered in the editing context
- * of the titles display group's data source (if any), AND
- * (2) the children key is not in the list of attributes
- * of the parent object's EOClassDescription.
- */
- public void targetChanged()
- {
- // if not root node
- if ( target != null )
- {
- // if we're not root and not fetched, stop here.
- //FIXME: with this, some nodes have old values when moved.
- //FIXME: without this, nodes are unnecessarily fetched.
- //FIXME: might have parent modify isFetched of certain child nodes.
- if ( isFetched() )
- {
- fetch();
- }
- else // not fetched - just update the display
- {
- updateDisplayedObjects();
- }
-/*
-//disabling this for performance reasons:
-//might reenable later or find an alternate approach
- // check to see if we need to mark the parent object as changed
- EOEditingContext context = dataSource().editingContext();
- if ( ( context == null )
- || ( context.globalIDForObject( target ) == null ) )
- {
- DisplayGroupNode parentNode = (DisplayGroupNode) parentGroup;
- if ( parentNode.target != null )
- {
- // only notify if childrenKey is an attribute of parentDesc
- // (and therefore not a toOne or toMany relationship)
- EOClassDescription parentDesc =
- EOClassDescription.classDescriptionForClass(
- parentNode.target.getClass() );
- if ( parentDesc.attributeKeys().contains( parentAssociation.childrenKey ) )
- {
- // only notify if no context is already observing the object
- // and we are an attribute key
- EOObserverCenter.notifyObserversObjectWillChange( parentNode.target );
- }
- }
- }
-*/
- }
- else // root node
- {
- setObjectArray( parentAssociation.titlesDisplayGroup.displayedObjects() );
- }
-
- // finally, broadcast change event for this node
- // even though we're not sure if the displayed value changed.
- fireNodeChanged();
- }
-
- /**
- * Fires a change event for this node.
- */
- public void fireNodeChanged()
- {
- // if not root node
- if ( target != null )
- {
- int index = ((DisplayGroupNode)parentGroup).getIndex( this );
- if ( ( index != -1 )
- && ( treePath().getParentPath() != null ) )
- {
- fireNodesChanged (
- treePath().getParentPath().getPath(),
- new int[] { index },
- new Object[] { this } );
- }
- }
- }
-
-Object[] previouslyDisplayedObjects = new Object[0];
- /**
- * Overridden to call to super, fire any tree events, and then
- * call updateDisplayedObjects on all fetched child nodes.
- * This method compares this node's displayed objects against
- * the list of child nodes, synchronizes them, and then broadcasts
- * only the necessary events to bring the view component up to date.
- */
- public void updateDisplayedObjects()
- {
+ return displayedObjects.count();
+ }
+
+ public int getIndex(DisplayGroupNode node) {
+ if (!isFetched())
+ fetch();
+ return displayedObjects.indexOfObject(((DisplayGroupNode) node).target);
+ }
+
+ public boolean getAllowsChildren() {
+ return true;
+ }
+
+ public boolean isLeaf() {
+ // if not root node and isLeaf aspect is bound
+ if ((target != null) && (parentGroup != null) && (parentAssociation.leafKey != null)) {
+ Object value;
+ if (parentAssociation.leafDisplayGroup != null) {
+ value = parentGroup.valueForObject(target, parentAssociation.leafKey);
+ } else {
+ value = parentAssociation.leafKey;
+ }
+
+ // getBoolean returns true for zero, among other things
+ Object result = ValueConverter.getBoolean(value);
+ if (result != null) {
+ return ((Boolean) result).booleanValue();
+ }
+ }
+
+ // otherwise, we have to fetch and return count
+ return (getChildCount() == 0);
+ }
+
+ public Enumeration children() {
+ int count = getChildCount();
+ Vector v = new Vector();
+ for (int i = 0; i < count; i++) {
+ v.add(getChildNodeAt(i));
+ }
+ return v.elements();
+ }
+
+ // parts of interface MutableTreeNode
+
+ public void insert(DisplayGroupNode aChild, int anIndex) {
+ insertObjectAtIndex(((DisplayGroupNode) aChild).object(), anIndex);
+ }
+
+ public void remove(int index) {
+ deleteObjectAtIndex(index);
+ }
+
+ /**
+ * Removes the node at the index corresponding to the index of the object.
+ */
+ public void remove(DisplayGroupNode node) {
+ remove(getIndex(node));
+ }
+
+ /**
+ * Removes our object from the parent display group.
+ */
+ public void removeFromParent() {
+ int index = parentGroup.displayedObjects().indexOfIdenticalObject(target);
+ if (index != NSArray.NotFound) {
+ parentGroup.deleteObjectAtIndex(index);
+ } else {
+ throw new WotonomyException("Object not found in parent group: " + target);
+ }
+ }
+
+ /**
+ * Removes our object from the parent display group and adds it to the end of
+ * the specified node's children.
+ */
+ public void setParent(DisplayGroupNode newParent) {
+ removeFromParent();
+ newParent.insertObjectAtIndex(object(), newParent.displayedObjects.size());
+ }
+
+ /**
+ * Returns the value of the displayed property in the parent display group at
+ * the index that corresponds to the index of this node.
+ */
+ public Object getUserObject() {
+ return valueForKey(parentAssociation.titlesKey);
+ }
+
+ /**
+ * Sets the value of the displayed property in the parent display group at the
+ * index that corresponds to the index of this node.
+ */
+ public void setUserObject(Object aValue) {
+ setValueForKey(aValue, parentAssociation.titlesKey);
+ }
+
+ /**
+ * Returns a value from the object in the parent display group at the index that
+ * corresponds to the index of this node. For the root node, if the titles key
+ * is specified, the root label is returned, otherwise null is returned.
+ */
+ public Object valueForKey(String aKey) {
+ // if root node
+ if (target == null) {
+ // compare by ref is okay for strings
+ if (aKey == parentAssociation.titlesKey) {
+ return parentAssociation.rootLabel();
+ }
+ return null;
+ }
+ return parentGroup.valueForObject(target, aKey);
+ }
+
+ /**
+ * Sets a value on the object in the parent display group at the index that
+ * corresponds to the index of this node. For the root node, this method only
+ * works if aKey is the titlesAspect's key, otherwise does nothing.
+ */
+ public void setValueForKey(Object aValue, String aKey) {
+ // if root node, return.
+ if (target == null) {
+ // compare by ref is okay for strings
+ if (aKey == parentAssociation.titlesKey) {
+ parentAssociation.setRootLabel(aValue);
+
+ // how to handle root node? tree event docs don't say.
+ fireNodesChanged(treePath().getPath(), new int[] { 0 }, new Object[] { this });
+ }
+ return;
+ }
+
+ parentGroup.setValueForObject(aValue, target, aKey);
+ }
+
+ /**
+ * Perform any clean up in this method. The node will not be reused after this
+ * method is called. This implementation removes itself from the parent's set of
+ * child nodes, sets target and datasource to null, and then calls
+ * disposeChildNodes().
+ */
+ protected void dispose() { // System.out.println( "dispose: " + this.getClass().getName() + " : " + this );
+ if (parentGroup != null) {
+ ((DisplayGroupNode) parentGroup).childNodes.remove(new ReferenceKey(target));
+ }
+ setTarget((Object) null);
+ setDataSource(null);
+ disposeChildNodes();
+ }
+
+ /**
+ * Calls dispose() on all child nodes.
+ */
+ protected void disposeChildNodes() {
+ Iterator i = new LinkedList(childNodes.values()).iterator();
+ while (i.hasNext()) {
+ ((DisplayGroupNode) i.next()).dispose();
+ }
+ }
+
+ /**
+ * Called after the target object posts a change notification. This
+ * implementation re-fetches which triggers updateDisplayedObjects to broadcast
+ * any tree events. This method marks the parent object as changed if: (1) this
+ * object is not registered in the editing context of the titles display group's
+ * data source (if any), AND (2) the children key is not in the list of
+ * attributes of the parent object's EOClassDescription.
+ */
+ public void targetChanged() {
+ // if not root node
+ if (target != null) {
+ // if we're not root and not fetched, stop here.
+ // FIXME: with this, some nodes have old values when moved.
+ // FIXME: without this, nodes are unnecessarily fetched.
+ // FIXME: might have parent modify isFetched of certain child nodes.
+ if (isFetched()) {
+ fetch();
+ } else // not fetched - just update the display
+ {
+ updateDisplayedObjects();
+ }
+ /*
+ * //disabling this for performance reasons: //might reenable later or find an
+ * alternate approach // check to see if we need to mark the parent object as
+ * changed EOEditingContext context = dataSource().editingContext(); if ( (
+ * context == null ) || ( context.globalIDForObject( target ) == null ) ) {
+ * DisplayGroupNode parentNode = (DisplayGroupNode) parentGroup; if (
+ * parentNode.target != null ) { // only notify if childrenKey is an attribute
+ * of parentDesc // (and therefore not a toOne or toMany relationship)
+ * EOClassDescription parentDesc = EOClassDescription.classDescriptionForClass(
+ * parentNode.target.getClass() ); if ( parentDesc.attributeKeys().contains(
+ * parentAssociation.childrenKey ) ) { // only notify if no context is already
+ * observing the object // and we are an attribute key
+ * EOObserverCenter.notifyObserversObjectWillChange( parentNode.target ); } } }
+ */
+ } else // root node
+ {
+ setObjectArray(parentAssociation.titlesDisplayGroup.displayedObjects());
+ }
+
+ // finally, broadcast change event for this node
+ // even though we're not sure if the displayed value changed.
+ fireNodeChanged();
+ }
+
+ /**
+ * Fires a change event for this node.
+ */
+ public void fireNodeChanged() {
+ // if not root node
+ if (target != null) {
+ int index = ((DisplayGroupNode) parentGroup).getIndex(this);
+ if ((index != -1) && (treePath().getParentPath() != null)) {
+ fireNodesChanged(treePath().getParentPath().getPath(), new int[] { index }, new Object[] { this });
+ }
+ }
+ }
+
+ Object[] previouslyDisplayedObjects = new Object[0];
+
+ /**
+ * Overridden to call to super, fire any tree events, and then call
+ * updateDisplayedObjects on all fetched child nodes. This method compares this
+ * node's displayed objects against the list of child nodes, synchronizes them,
+ * and then broadcasts only the necessary events to bring the view component up
+ * to date.
+ */
+ public void updateDisplayedObjects() {
//System.out.println( "updateDisplayedObjects: " + " : " + this );
//net.wotonomy.ui.swing.util.StackTraceInspector.printShortStackTrace();
//new RuntimeException().printStackTrace();
- super.updateDisplayedObjects();
-
- // diff lists
- boolean proceed = true;
- Object[] oldObjects = previouslyDisplayedObjects;
- Object[] newObjects = displayedObjects.toArray();
- if ( oldObjects.length == newObjects.length )
- {
- proceed = false;
- for ( int i = 0; i < newObjects.length; i++ )
- {
- if ( oldObjects[i] != newObjects[i] )
- {
- proceed = true;
- break;
- }
- }
- }
-
- // this should be set before firing the change events
- // in case some clients end up calling this again.
- previouslyDisplayedObjects = newObjects;
-
- DisplayGroupNode node;
- Iterator i = childNodes.values().iterator();
- while ( i.hasNext() )
- {
- node = (DisplayGroupNode) i.next();
- if ( !node.isFetchNeeded() )
- {
- node.updateDisplayedObjects();
- }
- }
-
- if ( proceed )
- {
+ super.updateDisplayedObjects();
+
+ // diff lists
+ boolean proceed = true;
+ Object[] oldObjects = previouslyDisplayedObjects;
+ Object[] newObjects = displayedObjects.toArray();
+ if (oldObjects.length == newObjects.length) {
+ proceed = false;
+ for (int i = 0; i < newObjects.length; i++) {
+ if (oldObjects[i] != newObjects[i]) {
+ proceed = true;
+ break;
+ }
+ }
+ }
+
+ // this should be set before firing the change events
+ // in case some clients end up calling this again.
+ previouslyDisplayedObjects = newObjects;
+
+ DisplayGroupNode node;
+ Iterator i = childNodes.values().iterator();
+ while (i.hasNext()) {
+ node = (DisplayGroupNode) i.next();
+ if (!node.isFetchNeeded()) {
+ node.updateDisplayedObjects();
+ }
+ }
+
+ if (proceed) {
//System.out.println( "DisplayGroupNode.firingEventsForChanges: " );
//new RuntimeException().printStackTrace();
- fireEventsForChanges( oldObjects, newObjects );
- }
-
- }
-
- /**
- * Called by processRecentChanges to analyze the
- * differences between the lists and broadcast the
- * appropriate events.
- */
- protected void fireEventsForChanges(
- Object[] oldObjects, Object[] newObjects )
- {
- // structure changed causes havoc while
- // establishing connection in some cases
- //if ( oldObjects.length == 0 || newObjects.length == 0 )
- //{
- // fireStructureChanged( treePath().getPath(), null, null );
- // return;
- //}
-
- int insertCount = 0;
- int deleteCount = 0;
- Object[] inserts = new Object[ newObjects.length ];
- Object[] deletes = new Object[ oldObjects.length ];
-
- int i;
- int n = -1, o = -1; // last match
- int n1 = 0, o1 = 0; // current match test
- int n2 = 0, o2 = 0; // scan ahead
-
- while ( o1 < oldObjects.length && n1 < newObjects.length )
- {
- if ( newObjects[n1] == oldObjects[o1] )
- {
- // mark as match and continue
- o = o1;
- n = n1;
- }
- else
- {
- // scan ahead for the next match, if any
- o2 = o1;
- n2 = n1;
-
- while ( o2 < oldObjects.length || n2 < newObjects.length )
- {
- if ( o2 < oldObjects.length && newObjects[n1] == oldObjects[o2] )
- {
- // run o1 to o2: mark as deletes
- for ( i = o1; i < o2; i++ )
- { // System.out.println( "delete : " + i );
- deletes[i] = oldObjects[i];
- deleteCount++;
- }
- o1 = o2; // reset test
- o = o1; // set match
- n = n1; // set match
- break;
- }
- if ( n2 < newObjects.length && newObjects[n2] == oldObjects[o1] )
- {
- // run n1 to n2: mark as inserts
- for ( i = n1; i < n2; i++ )
- { // System.out.println( "insert : " + i );
- inserts[i] = newObjects[i];
- insertCount++;
- }
- n1 = n2; // reset test
- n = n1; // set match
- o = o1; // set match
- break;
- }
- o2++;
- n2++;
- }
- }
- if (n != n1)
- {
- inserts[n1] = newObjects[n1];
- insertCount++;
- deletes[o1] = oldObjects[o1];
- deleteCount++;
- //increment even though no match:
- //the new object was marked as inserted and
- //the old object was marked as deleted.
- n = n1;
- o = o1;
- }
- o1++;
- n1++;
- }
-
- // run o to end of oldObjects: mark as deletes
- for ( i = o+1; i < oldObjects.length; i++ )
- { // System.out.println( "delete : " + i );
- deletes[i] = oldObjects[i];
- deleteCount++;
- }
-
- // run n to end of newObjects: mark as inserts
- for ( i = n+1; i < newObjects.length; i++ )
- { // System.out.println( "insert : " + i );
- inserts[i] = newObjects[i];
- insertCount++;
- }
+ fireEventsForChanges(oldObjects, newObjects);
+ }
+
+ }
+
+ /**
+ * Called by processRecentChanges to analyze the differences between the lists
+ * and broadcast the appropriate events.
+ */
+ protected void fireEventsForChanges(Object[] oldObjects, Object[] newObjects) {
+ // structure changed causes havoc while
+ // establishing connection in some cases
+ // if ( oldObjects.length == 0 || newObjects.length == 0 )
+ // {
+ // fireStructureChanged( treePath().getPath(), null, null );
+ // return;
+ // }
+
+ int insertCount = 0;
+ int deleteCount = 0;
+ Object[] inserts = new Object[newObjects.length];
+ Object[] deletes = new Object[oldObjects.length];
+
+ int i;
+ int n = -1, o = -1; // last match
+ int n1 = 0, o1 = 0; // current match test
+ int n2 = 0, o2 = 0; // scan ahead
+
+ while (o1 < oldObjects.length && n1 < newObjects.length) {
+ if (newObjects[n1] == oldObjects[o1]) {
+ // mark as match and continue
+ o = o1;
+ n = n1;
+ } else {
+ // scan ahead for the next match, if any
+ o2 = o1;
+ n2 = n1;
+
+ while (o2 < oldObjects.length || n2 < newObjects.length) {
+ if (o2 < oldObjects.length && newObjects[n1] == oldObjects[o2]) {
+ // run o1 to o2: mark as deletes
+ for (i = o1; i < o2; i++) { // System.out.println( "delete : " + i );
+ deletes[i] = oldObjects[i];
+ deleteCount++;
+ }
+ o1 = o2; // reset test
+ o = o1; // set match
+ n = n1; // set match
+ break;
+ }
+ if (n2 < newObjects.length && newObjects[n2] == oldObjects[o1]) {
+ // run n1 to n2: mark as inserts
+ for (i = n1; i < n2; i++) { // System.out.println( "insert : " + i );
+ inserts[i] = newObjects[i];
+ insertCount++;
+ }
+ n1 = n2; // reset test
+ n = n1; // set match
+ o = o1; // set match
+ break;
+ }
+ o2++;
+ n2++;
+ }
+ }
+ if (n != n1) {
+ inserts[n1] = newObjects[n1];
+ insertCount++;
+ deletes[o1] = oldObjects[o1];
+ deleteCount++;
+ // increment even though no match:
+ // the new object was marked as inserted and
+ // the old object was marked as deleted.
+ n = n1;
+ o = o1;
+ }
+ o1++;
+ n1++;
+ }
+
+ // run o to end of oldObjects: mark as deletes
+ for (i = o + 1; i < oldObjects.length; i++) { // System.out.println( "delete : " + i );
+ deletes[i] = oldObjects[i];
+ deleteCount++;
+ }
+
+ // run n to end of newObjects: mark as inserts
+ for (i = n + 1; i < newObjects.length; i++) { // System.out.println( "insert : " + i );
+ inserts[i] = newObjects[i];
+ insertCount++;
+ }
//System.out.println( "done : "
//+ o + " : " + o1 + " : " + o2 + " :: " + n + " : " + n1 + " : " + n2 );
@@ -948,571 +774,481 @@ Object[] previouslyDisplayedObjects = new Object[0];
//System.out.println( new NSArray( inserts ) );
//System.out.println( new NSArray( deletes ) );
//System.out.println( new NSArray( oldObjects ) );
-
- int c;
- Object[] nodes;
- int[] indices;
-
- // broadcast delete event
- c = 0;
- nodes = new Object[ deleteCount ];
- indices = new int[ deleteCount ];
- for ( i = 0; i < deletes.length; i++ )
- {
- if ( deletes[i] != null )
- {
- indices[c] = i;
- nodes[c] = getChildNodeForObject( deletes[i] );
- c++;
- }
- }
- if ( c > 0 )
- {
+
+ int c;
+ Object[] nodes;
+ int[] indices;
+
+ // broadcast delete event
+ c = 0;
+ nodes = new Object[deleteCount];
+ indices = new int[deleteCount];
+ for (i = 0; i < deletes.length; i++) {
+ if (deletes[i] != null) {
+ indices[c] = i;
+ nodes[c] = getChildNodeForObject(deletes[i]);
+ c++;
+ }
+ }
+ if (c > 0) {
// fireNodeChanged(); // force the jtree to get the correct child count
- fireNodesRemoved( treePath().getPath(), indices, nodes );
- }
- deletes = nodes; // retain for dispose check
-
- // broadcast insert event
- c = 0;
- nodes = new Object[ insertCount ];
- indices = new int[ insertCount ];
- for ( i = 0; i < inserts.length; i++ )
- {
- if ( inserts[i] != null )
- {
- indices[c] = i;
- nodes[c] = getChildNodeForObject( inserts[i] );
- if ( nodes[c] == null )
- {
- nodes[c] = createChildNodeForObject( newObjects[i] );
- }
- c++;
- }
- }
- if ( c > 0 )
- {
- fireNodesInserted( treePath().getPath(), indices, nodes );
- }
-
- // dispose any delete nodes not on insert list
- int j;
- boolean found;
- for ( i = 0; i < deletes.length; i++ )
- {
- for ( j = 0; j < nodes.length; j++ )
- {
- if ( deletes[i] == nodes[j] ) break;
- }
-
- // did not break early, so not found, so dispose
- if ( j == nodes.length )
- {
- ((DisplayGroupNode)deletes[i]).dispose();
- }
- }
- }
-
- /**
- * Sets the target object and creates an registers a target observer.
- * If target was not previously null, the existing observer is unregistered.
- * Protected access so subclasses and TreeModelAssociation can update our target.
- */
- public void setTarget( Object aTarget )
- {
- if ( target != null )
- {
- EOObserverCenter.removeObserver( targetObserver, target );
- targetObserver.discardPendingNotification();
- }
-
- if ( aTarget != null )
- {
- target = aTarget;
- targetObserver = new TargetObserver( this );
- EOObserverCenter.addObserver( targetObserver, target );
- }
- }
-
- /**
- * Returns the parent display group, or null if parent is root.
- */
- public DisplayGroupNode getParentGroup()
- {
- if ( parentGroup instanceof DisplayGroupNode )
- {
- return (DisplayGroupNode)parentGroup;
- }
- // presumably the root node
- return null;
- }
-
- /**
- * Gets all descendants of the this node.
- */
- public List getDescendants()
- {
- return getDescendants( this, true );
- }
-
- /**
- * Gets only the descendants of the this node
- * whose children has been loaded - no fetching
- * will occur. Useful for load-on-demand trees.
- */
- public List getLoadedDescendants()
- {
- return getDescendants( this, false );
- }
-
- // breadth first traversal implementation
-
- /**
- * Returns a list of all descendants of the
- * specified node. Unfetched nodes are traversed
- * only if forceLoad is true.
- * This implementation is a breadth-first traversal
- * of the nodes starting at the specified node.
- */
- static private List getDescendants( DisplayGroupNode aNode, boolean forceLoad )
- {
- if ( !forceLoad && !aNode.isFetched ) return NSArray.EmptyArray;
-
- LinkedList result = new LinkedList();
- LinkedList queue = new LinkedList();
-
- queue.add( aNode );
- while ( ! queue.isEmpty() )
- {
- checkNode( (DisplayGroupNode) queue.removeFirst(),
- queue, result, forceLoad );
- }
-
- return result;
- }
-
- /**
- * Adds each fetched child node of the specified node to
- * the result set (optionally forcing the child node to load)
- * and adding child node to the end of the queue.
- */
- static private void checkNode( DisplayGroupNode aNode,
- LinkedList aQueue, LinkedList aResult, boolean forceLoad )
- {
- DisplayGroupNode child;
- int count = aNode.getChildCount();
-
- for ( int i = 0; i < count; i++ )
- {
- child = aNode.getChildNodeAt( i );
-
- // add to queue if node has fetched children
- if ( ( !child.isFetched ) && ( forceLoad ) )
- {
- child.fetch();
- }
- if ( child.isFetched )
- {
- aQueue.addLast( child );
- }
-
- aResult.add( child );
- }
- }
-
- /**
- * Overridden to not fetch on InvalidateAllObjectsInStoreNotification
- * unless we've already been fetched, preserving the load-on-demand
- * functionality.
- */
- public void objectsInvalidatedInEditingContext( NSNotification aNotification )
- {
- if ( EOObjectStore.InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
+ fireNodesRemoved(treePath().getPath(), indices, nodes);
+ }
+ deletes = nodes; // retain for dispose check
+
+ // broadcast insert event
+ c = 0;
+ nodes = new Object[insertCount];
+ indices = new int[insertCount];
+ for (i = 0; i < inserts.length; i++) {
+ if (inserts[i] != null) {
+ indices[c] = i;
+ nodes[c] = getChildNodeForObject(inserts[i]);
+ if (nodes[c] == null) {
+ nodes[c] = createChildNodeForObject(newObjects[i]);
+ }
+ c++;
+ }
+ }
+ if (c > 0) {
+ fireNodesInserted(treePath().getPath(), indices, nodes);
+ }
+
+ // dispose any delete nodes not on insert list
+ int j;
+ boolean found;
+ for (i = 0; i < deletes.length; i++) {
+ for (j = 0; j < nodes.length; j++) {
+ if (deletes[i] == nodes[j])
+ break;
+ }
+
+ // did not break early, so not found, so dispose
+ if (j == nodes.length) {
+ ((DisplayGroupNode) deletes[i]).dispose();
+ }
+ }
+ }
+
+ /**
+ * Sets the target object and creates an registers a target observer. If target
+ * was not previously null, the existing observer is unregistered. Protected
+ * access so subclasses and TreeModelAssociation can update our target.
+ */
+ public void setTarget(Object aTarget) {
+ if (target != null) {
+ EOObserverCenter.removeObserver(targetObserver, target);
+ targetObserver.discardPendingNotification();
+ }
+
+ if (aTarget != null) {
+ target = aTarget;
+ targetObserver = new TargetObserver(this);
+ EOObserverCenter.addObserver(targetObserver, target);
+ }
+ }
+
+ /**
+ * Returns the parent display group, or null if parent is root.
+ */
+ public DisplayGroupNode getParentGroup() {
+ if (parentGroup instanceof DisplayGroupNode) {
+ return (DisplayGroupNode) parentGroup;
+ }
+ // presumably the root node
+ return null;
+ }
+
+ /**
+ * Gets all descendants of the this node.
+ */
+ public List getDescendants() {
+ return getDescendants(this, true);
+ }
+
+ /**
+ * Gets only the descendants of the this node whose children has been loaded -
+ * no fetching will occur. Useful for load-on-demand trees.
+ */
+ public List getLoadedDescendants() {
+ return getDescendants(this, false);
+ }
+
+ // breadth first traversal implementation
+
+ /**
+ * Returns a list of all descendants of the specified node. Unfetched nodes are
+ * traversed only if forceLoad is true. This implementation is a breadth-first
+ * traversal of the nodes starting at the specified node.
+ */
+ static private List getDescendants(DisplayGroupNode aNode, boolean forceLoad) {
+ if (!forceLoad && !aNode.isFetched)
+ return NSArray.EmptyArray;
+
+ LinkedList result = new LinkedList();
+ LinkedList queue = new LinkedList();
+
+ queue.add(aNode);
+ while (!queue.isEmpty()) {
+ checkNode((DisplayGroupNode) queue.removeFirst(), queue, result, forceLoad);
+ }
+
+ return result;
+ }
+
+ /**
+ * Adds each fetched child node of the specified node to the result set
+ * (optionally forcing the child node to load) and adding child node to the end
+ * of the queue.
+ */
+ static private void checkNode(DisplayGroupNode aNode, LinkedList aQueue, LinkedList aResult, boolean forceLoad) {
+ DisplayGroupNode child;
+ int count = aNode.getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ child = aNode.getChildNodeAt(i);
+
+ // add to queue if node has fetched children
+ if ((!child.isFetched) && (forceLoad)) {
+ child.fetch();
+ }
+ if (child.isFetched) {
+ aQueue.addLast(child);
+ }
+
+ aResult.add(child);
+ }
+ }
+
+ /**
+ * Overridden to not fetch on InvalidateAllObjectsInStoreNotification unless
+ * we've already been fetched, preserving the load-on-demand functionality.
+ */
+ public void objectsInvalidatedInEditingContext(NSNotification aNotification) {
+ if (EOObjectStore.InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
//System.out.println( "DisplayGroupNode.objectsInvalidatedInEditingContext: " + aNotification.name() );
- if ( parentAssociation.isVisible( this ) && targetObserver != null )
- {
- targetObserver.objectWillChange( target ); // force ui to update
- fireNodeChanged();
- }
- else // make sure we fetch children when we do become visible
- setFetchNeeded( true );
- return;
- }
- else
- if ( ( EOEditingContext.ObjectsChangedInEditingContextNotification
- .equals( aNotification.name() ) )
- || ( EOEditingContext.EditingContextDidSaveChangesNotification
- .equals( aNotification.name() ) ) )
- {
- int index;
- Enumeration e;
- boolean didChange = false;
- NSDictionary userInfo = aNotification.userInfo();
-
- // if our target object was deleted
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- if ( deletes.indexOfIdenticalObject( target ) != NSArray.NotFound )
- {
+ if (parentAssociation.isVisible(this) && targetObserver != null) {
+ targetObserver.objectWillChange(target); // force ui to update
+ fireNodeChanged();
+ } else // make sure we fetch children when we do become visible
+ setFetchNeeded(true);
+ return;
+ } else if ((EOEditingContext.ObjectsChangedInEditingContextNotification.equals(aNotification.name()))
+ || (EOEditingContext.EditingContextDidSaveChangesNotification.equals(aNotification.name()))) {
+ int index;
+ Enumeration e;
+ boolean didChange = false;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // if our target object was deleted
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ if (deletes.indexOfIdenticalObject(target) != NSArray.NotFound) {
//System.out.println( "DisplayGroupNode.objectsInvalidatedInEditingContext: delete: " + this + " : " + aNotification.name() );
- if ( parentAssociation.isVisible( this ) && targetObserver != null )
- {
- targetObserver.objectWillChange( target ); // force ui to update
- fireNodeChanged();
- }
- else // make sure we fetch children when we do become visible
- setFetchNeeded( true );
- return;
- }
-
- // if our target object was invalidated
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- if ( invalidates != null &&
- invalidates.indexOfIdenticalObject( target ) != NSArray.NotFound )
- {
+ if (parentAssociation.isVisible(this) && targetObserver != null) {
+ targetObserver.objectWillChange(target); // force ui to update
+ fireNodeChanged();
+ } else // make sure we fetch children when we do become visible
+ setFetchNeeded(true);
+ return;
+ }
+
+ // if our target object was invalidated
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ if (invalidates != null && invalidates.indexOfIdenticalObject(target) != NSArray.NotFound) {
//System.out.println( "DisplayGroupNode.objectsInvalidatedInEditingContext: invalidate: " + this + " : " + aNotification.name() );
- if ( parentAssociation.isVisible( this ) && targetObserver != null )
- {
- targetObserver.objectWillChange( target ); // force ui to update
- fireNodeChanged();
- }
- else // make sure we fetch children when we do become visible
- setFetchNeeded( true );
- return;
- }
-
- // if our target object was updated, set fetchNeeded plus fire changed event
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- if ( updates.indexOfIdenticalObject( target ) != NSArray.NotFound )
- {
- if ( parentAssociation.isVisible( this ) && targetObserver != null )
- {
- targetObserver.objectWillChange( target ); // force ui to update
- fireNodeChanged();
- if ( object() instanceof Component ) ((Component)object()).repaint();
- }
- else // make sure we fetch children when we do become visible
- setFetchNeeded( true );
- return;
- }
- }
-
- super.objectsInvalidatedInEditingContext( aNotification );
-
- }
-
- // inner classes
-
- /**
- * Private class used to force a hashmap to
- * perform key comparisons by reference.
- */
- private class ReferenceKey
- {
- private int hashCode;
- private Object referent;
-
- public ReferenceKey( Object anObject )
- {
- referent = anObject;
- hashCode = anObject.hashCode();
- }
-
- /**
- * Returns the actual key's hash code.
- */
- public int hashCode()
- {
- return hashCode;
- }
-
- /**
- * Compares by reference.
- */
- public boolean equals( Object anObject )
- {
- if ( anObject instanceof ReferenceKey )
- {
- return ((ReferenceKey)anObject).referent == referent;
- }
- return false;
- }
- }
-
- /**
- * A private class to observe the target object of this node.
- */
- private class TargetObserver extends EODelayedObserver
- {
- Reference ref;
-
- /**
- * Pass in the display group node that will be updated
- * when the target changes.
- */
- public TargetObserver( DisplayGroupNode aDisplayGroup )
- {
- ref = new WeakReference( aDisplayGroup );
- }
-
- /**
- * Repopulate our display group, and calculate the deltas
- * so we can broadcast appropriate events.
- */
- public void subjectChanged ()
- {
- DisplayGroupNode node = (DisplayGroupNode) ref.get();
- if ( node == null ) return; // node is null if gc'd.
- //FIXME: should un-register self from observer center??
-
- node.targetChanged();
- }
- }
+ if (parentAssociation.isVisible(this) && targetObserver != null) {
+ targetObserver.objectWillChange(target); // force ui to update
+ fireNodeChanged();
+ } else // make sure we fetch children when we do become visible
+ setFetchNeeded(true);
+ return;
+ }
+
+ // if our target object was updated, set fetchNeeded plus fire changed event
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ if (updates.indexOfIdenticalObject(target) != NSArray.NotFound) {
+ if (parentAssociation.isVisible(this) && targetObserver != null) {
+ targetObserver.objectWillChange(target); // force ui to update
+ fireNodeChanged();
+ if (object() instanceof Component)
+ ((Component) object()).repaint();
+ } else // make sure we fetch children when we do become visible
+ setFetchNeeded(true);
+ return;
+ }
+ }
+
+ super.objectsInvalidatedInEditingContext(aNotification);
+
+ }
+
+ // inner classes
+
+ /**
+ * Private class used to force a hashmap to perform key comparisons by
+ * reference.
+ */
+ private class ReferenceKey {
+ private int hashCode;
+ private Object referent;
+
+ public ReferenceKey(Object anObject) {
+ referent = anObject;
+ hashCode = anObject.hashCode();
+ }
+
+ /**
+ * Returns the actual key's hash code.
+ */
+ public int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Compares by reference.
+ */
+ public boolean equals(Object anObject) {
+ if (anObject instanceof ReferenceKey) {
+ return ((ReferenceKey) anObject).referent == referent;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * A private class to observe the target object of this node.
+ */
+ private class TargetObserver extends EODelayedObserver {
+ Reference ref;
+
+ /**
+ * Pass in the display group node that will be updated when the target changes.
+ */
+ public TargetObserver(DisplayGroupNode aDisplayGroup) {
+ ref = new WeakReference(aDisplayGroup);
+ }
+
+ /**
+ * Repopulate our display group, and calculate the deltas so we can broadcast
+ * appropriate events.
+ */
+ public void subjectChanged() {
+ DisplayGroupNode node = (DisplayGroupNode) ref.get();
+ if (node == null)
+ return; // node is null if gc'd.
+ // FIXME: should un-register self from observer center??
+
+ node.targetChanged();
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.64 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.64 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.63 2003/06/06 14:20:07 mpowers
- * getLoadedDescendants was forcing a fetch of the node it was called on.
+ * Revision 1.63 2003/06/06 14:20:07 mpowers getLoadedDescendants was forcing a
+ * fetch of the node it was called on.
*
- * Revision 1.62 2003/06/03 14:48:33 mpowers
- * Clean-up of notification handling for updates/invalidation/etc.
- * Now fetching immediately on notification if the node is visible.
- * This averts the infamous IndexOutOfBoundsException that occurs
- * if fetching happens during repaint, because the BasicTreeUI is
- * caching the number of child nodes before painting begins.
+ * Revision 1.62 2003/06/03 14:48:33 mpowers Clean-up of notification handling
+ * for updates/invalidation/etc. Now fetching immediately on notification if the
+ * node is visible. This averts the infamous IndexOutOfBoundsException that
+ * occurs if fetching happens during repaint, because the BasicTreeUI is caching
+ * the number of child nodes before painting begins.
*
- * Revision 1.61 2003/01/18 23:33:29 mpowers
- * Fixing the build.
+ * Revision 1.61 2003/01/18 23:33:29 mpowers Fixing the build.
*
- * Revision 1.60 2002/05/31 15:03:10 mpowers
- * Fixes for the previous fix. Fat props to yjcheung.
+ * Revision 1.60 2002/05/31 15:03:10 mpowers Fixes for the previous fix. Fat
+ * props to yjcheung.
*
- * Revision 1.59 2002/05/28 15:31:36 mpowers
- * Fix for updateDisplayedObjects for a subtle case where a node appears in
- * the position that another node was moved from.
+ * Revision 1.59 2002/05/28 15:31:36 mpowers Fix for updateDisplayedObjects for
+ * a subtle case where a node appears in the position that another node was
+ * moved from.
*
- * Revision 1.58 2002/05/24 14:42:02 mpowers
- * Prevent repeat events from firing if firing events loops back.
+ * Revision 1.58 2002/05/24 14:42:02 mpowers Prevent repeat events from firing
+ * if firing events loops back.
*
- * Revision 1.57 2002/04/23 19:12:28 mpowers
- * Reimplemented fireEventsForChanges. Fitter and happier.
+ * Revision 1.57 2002/04/23 19:12:28 mpowers Reimplemented fireEventsForChanges.
+ * Fitter and happier.
*
- * Revision 1.56 2002/04/19 21:18:45 mpowers
- * Removed tree event coalescing, which was causing way too many problems.
- * The fireChangeEvent algorithm is way faster than before, so we should
- * still be better off than before. At least now, we don't have to track
- * whether the view component has encountered a particular node.
+ * Revision 1.56 2002/04/19 21:18:45 mpowers Removed tree event coalescing,
+ * which was causing way too many problems. The fireChangeEvent algorithm is way
+ * faster than before, so we should still be better off than before. At least
+ * now, we don't have to track whether the view component has encountered a
+ * particular node.
*
- * Revision 1.55 2002/04/19 20:53:22 mpowers
- * Now firing event fewer events in fireEventsForChanges.
+ * Revision 1.55 2002/04/19 20:53:22 mpowers Now firing event fewer events in
+ * fireEventsForChanges.
*
- * Revision 1.54 2002/04/15 21:52:50 mpowers
- * Tightening up TreeModelAssociation and DisplayGroupNode.
- * Now only firing root structure changed once.
- * Now disposing of root's children.
- * Better event coalescing.
+ * Revision 1.54 2002/04/15 21:52:50 mpowers Tightening up TreeModelAssociation
+ * and DisplayGroupNode. Now only firing root structure changed once. Now
+ * disposing of root's children. Better event coalescing.
*
- * Revision 1.53 2002/04/12 20:35:20 mpowers
- * Now correctly setting parent display group and data source on creation.
+ * Revision 1.53 2002/04/12 20:35:20 mpowers Now correctly setting parent
+ * display group and data source on creation.
*
- * Revision 1.52 2002/04/10 21:20:04 mpowers
- * Better handling for tree nodes when working with editing contexts.
- * Better handling for invalidation. No longer broadcasting events
- * when nodes have not been "registered" in the tree.
+ * Revision 1.52 2002/04/10 21:20:04 mpowers Better handling for tree nodes when
+ * working with editing contexts. Better handling for invalidation. No longer
+ * broadcasting events when nodes have not been "registered" in the tree.
*
- * Revision 1.51 2002/04/03 20:13:36 mpowers
- * Now differentiating between node instantiation caused by model expansion
- * (user initiated) and by modifications to the model.
- * Dispose now disposes all children.
+ * Revision 1.51 2002/04/03 20:13:36 mpowers Now differentiating between node
+ * instantiation caused by model expansion (user initiated) and by modifications
+ * to the model. Dispose now disposes all children.
*
- * Revision 1.50 2002/03/23 16:20:27 mpowers
- * Optimized processRecentChanges, minimized tree events.
+ * Revision 1.50 2002/03/23 16:20:27 mpowers Optimized processRecentChanges,
+ * minimized tree events.
*
- * Revision 1.49 2002/03/11 03:15:06 mpowers
- * Optimized processRecentChanges, minimize event firing, coalescing changes.
- * Still need a better diff algorithm to avoid removing nodes.
+ * Revision 1.49 2002/03/11 03:15:06 mpowers Optimized processRecentChanges,
+ * minimize event firing, coalescing changes. Still need a better diff algorithm
+ * to avoid removing nodes.
*
- * Revision 1.48 2002/03/10 00:59:39 mpowers
- * Interim version: coalesces calls to process recent changes.
- * Still does not handle rearranged nodes.
+ * Revision 1.48 2002/03/10 00:59:39 mpowers Interim version: coalesces calls to
+ * process recent changes. Still does not handle rearranged nodes.
*
- * Revision 1.47 2002/03/09 17:33:45 mpowers
- * Nodes now track their child nodes by reference, not index.
+ * Revision 1.47 2002/03/09 17:33:45 mpowers Nodes now track their child nodes
+ * by reference, not index.
*
- * Revision 1.46 2002/03/08 23:19:07 mpowers
- * Added getParentGroup to DisplayGroupNode.
+ * Revision 1.46 2002/03/08 23:19:07 mpowers Added getParentGroup to
+ * DisplayGroupNode.
*
- * Revision 1.45 2002/03/06 13:04:16 mpowers
- * Implemented cascading qualifiers in tree nodes.
+ * Revision 1.45 2002/03/06 13:04:16 mpowers Implemented cascading qualifiers in
+ * tree nodes.
*
- * Revision 1.44 2002/02/27 23:19:17 mpowers
- * Refactoring of TreeAssociation to create TreeModelAssociation parent.
+ * Revision 1.44 2002/02/27 23:19:17 mpowers Refactoring of TreeAssociation to
+ * create TreeModelAssociation parent.
*
- * Revision 1.42 2002/02/19 22:28:46 mpowers
- * DisplayGroupNodes immediately unregister themselves as editors.
+ * Revision 1.42 2002/02/19 22:28:46 mpowers DisplayGroupNodes immediately
+ * unregister themselves as editors.
*
- * Revision 1.41 2002/02/13 16:27:38 mpowers
- * Exposing setTarget.
+ * Revision 1.41 2002/02/13 16:27:38 mpowers Exposing setTarget.
*
- * Revision 1.40 2001/11/02 20:55:46 mpowers
- * Now using fixed index to send node removed events. This preserves the
- * expanded state of the nodes in the corresponding jtree.
+ * Revision 1.40 2001/11/02 20:55:46 mpowers Now using fixed index to send node
+ * removed events. This preserves the expanded state of the nodes in the
+ * corresponding jtree.
*
- * Revision 1.39 2001/09/21 21:09:25 mpowers
- * Exposed more fields as protected.
+ * Revision 1.39 2001/09/21 21:09:25 mpowers Exposed more fields as protected.
*
- * Revision 1.38 2001/09/19 15:36:08 mpowers
- * Refined behavior for isFetched after notification handling.
+ * Revision 1.38 2001/09/19 15:36:08 mpowers Refined behavior for isFetched
+ * after notification handling.
*
- * Revision 1.37 2001/09/13 14:51:18 mpowers
- * DisplayGroupNodes now dispose themselves and mark their parent for update
- * when they receive notification that their target has been deleted.
+ * Revision 1.37 2001/09/13 14:51:18 mpowers DisplayGroupNodes now dispose
+ * themselves and mark their parent for update when they receive notification
+ * that their target has been deleted.
*
- * Revision 1.36 2001/09/10 14:10:24 mpowers
- * Fix for notification handling.
+ * Revision 1.36 2001/09/10 14:10:24 mpowers Fix for notification handling.
*
- * Revision 1.35 2001/07/30 16:17:01 mpowers
- * Minor code cleanup.
+ * Revision 1.35 2001/07/30 16:17:01 mpowers Minor code cleanup.
*
- * Revision 1.34 2001/07/18 22:13:39 mpowers
- * getLoadedDescendants now works as advertised.
- * Now correctly handling invalidateAllObjects notification.
+ * Revision 1.34 2001/07/18 22:13:39 mpowers getLoadedDescendants now works as
+ * advertised. Now correctly handling invalidateAllObjects notification.
*
- * Revision 1.33 2001/07/18 13:03:32 mpowers
- * TreeNodes now refetch only on demand. Previously, once a node had
- * been fetched, it was always refetched after an invalidate, even if
- * the node was not being displayed.
+ * Revision 1.33 2001/07/18 13:03:32 mpowers TreeNodes now refetch only on
+ * demand. Previously, once a node had been fetched, it was always refetched
+ * after an invalidate, even if the node was not being displayed.
*
- * Revision 1.32 2001/06/18 14:10:28 mpowers
- * Cleaned up event firing: no longer firing insert or remove events twice.
+ * Revision 1.32 2001/06/18 14:10:28 mpowers Cleaned up event firing: no longer
+ * firing insert or remove events twice.
*
- * Revision 1.31 2001/06/09 16:15:39 mpowers
- * Revised the targetChanged scheme because oldObjects and newObjects were
- * identical after the target object is invalidated.
+ * Revision 1.31 2001/06/09 16:15:39 mpowers Revised the targetChanged scheme
+ * because oldObjects and newObjects were identical after the target object is
+ * invalidated.
*
- * Revision 1.30 2001/05/21 22:17:19 mpowers
- * Fix for tree out-of-synch problems when nodes are inserted.
+ * Revision 1.30 2001/05/21 22:17:19 mpowers Fix for tree out-of-synch problems
+ * when nodes are inserted.
*
- * Revision 1.29 2001/05/18 21:07:46 mpowers
- * Playing with refresh options.
+ * Revision 1.29 2001/05/18 21:07:46 mpowers Playing with refresh options.
*
- * Revision 1.28 2001/05/14 15:25:43 mpowers
- * DisplayGroupNodes now only respond to InvalidateAllObjectsInStore
- * if they are already fetched.
+ * Revision 1.28 2001/05/14 15:25:43 mpowers DisplayGroupNodes now only respond
+ * to InvalidateAllObjectsInStore if they are already fetched.
*
- * Revision 1.27 2001/05/08 19:55:58 mpowers
- * Fix for node children not refreshing after sibling was inserted.
+ * Revision 1.27 2001/05/08 19:55:58 mpowers Fix for node children not
+ * refreshing after sibling was inserted.
*
- * Revision 1.26 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.26 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.25 2001/05/06 22:22:55 mpowers
- * Debugging.
+ * Revision 1.25 2001/05/06 22:22:55 mpowers Debugging.
*
- * Revision 1.24 2001/05/04 14:42:58 mpowers
- * Now getting stored values in KeyValueCoding.
- * MasterDetail now marks dirty based on whether it's an attribute
- * or relation.
- * Implemented editing context marker.
+ * Revision 1.24 2001/05/04 14:42:58 mpowers Now getting stored values in
+ * KeyValueCoding. MasterDetail now marks dirty based on whether it's an
+ * attribute or relation. Implemented editing context marker.
*
- * Revision 1.23 2001/05/02 18:00:43 mpowers
- * Removed debug code.
+ * Revision 1.23 2001/05/02 18:00:43 mpowers Removed debug code.
*
- * Revision 1.22 2001/05/02 17:31:20 mpowers
- * DisplayGroupNode now does a better job determining when to mark its
- * parent dirty.
+ * Revision 1.22 2001/05/02 17:31:20 mpowers DisplayGroupNode now does a better
+ * job determining when to mark its parent dirty.
*
- * Revision 1.21 2001/05/01 00:52:32 mpowers
- * Implemented breadth-first traversal of tree for node.
+ * Revision 1.21 2001/05/01 00:52:32 mpowers Implemented breadth-first traversal
+ * of tree for node.
*
- * Revision 1.20 2001/04/26 01:15:19 mpowers
- * Major clean-up of DisplayGroupNode: fitter, happier, more productive.
+ * Revision 1.20 2001/04/26 01:15:19 mpowers Major clean-up of DisplayGroupNode:
+ * fitter, happier, more productive.
*
- * Revision 1.19 2001/04/22 23:13:35 mpowers
- * Minor bug.
+ * Revision 1.19 2001/04/22 23:13:35 mpowers Minor bug.
*
- * Revision 1.18 2001/04/22 23:05:33 mpowers
- * Totally revised DisplayGroupNode so each object gets its own node
- * (so the nodes are no longer fixed by index).
+ * Revision 1.18 2001/04/22 23:05:33 mpowers Totally revised DisplayGroupNode so
+ * each object gets its own node (so the nodes are no longer fixed by index).
*
- * Revision 1.17 2001/04/21 23:05:12 mpowers
- * A fairly major revisiting. I've decided to scrap the pass-thru approach
- * where every node simply represents an index and not an object.
- * The next update will have each node correspond to a specific object.
+ * Revision 1.17 2001/04/21 23:05:12 mpowers A fairly major revisiting. I've
+ * decided to scrap the pass-thru approach where every node simply represents an
+ * index and not an object. The next update will have each node correspond to a
+ * specific object.
*
- * Revision 1.16 2001/04/13 16:37:37 mpowers
- * Handling bounds checking.
+ * Revision 1.16 2001/04/13 16:37:37 mpowers Handling bounds checking.
*
- * Revision 1.15 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.15 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.14 2001/03/27 17:45:51 mpowers
- * More index bounds checking.
+ * Revision 1.14 2001/03/27 17:45:51 mpowers More index bounds checking.
*
- * Revision 1.13 2001/03/22 21:25:42 mpowers
- * Fixed some nasty issues with jtree's internal state and array bounds.
+ * Revision 1.13 2001/03/22 21:25:42 mpowers Fixed some nasty issues with
+ * jtree's internal state and array bounds.
*
- * Revision 1.12 2001/03/19 22:18:58 mpowers
- * Root node now mirrors contents of titles display group.
+ * Revision 1.12 2001/03/19 22:18:58 mpowers Root node now mirrors contents of
+ * titles display group.
*
- * Revision 1.11 2001/03/19 21:38:36 mpowers
- * Improved redisplay after edit. Editing nodes off root now works.
+ * Revision 1.11 2001/03/19 21:38:36 mpowers Improved redisplay after edit.
+ * Editing nodes off root now works.
*
- * Revision 1.10 2001/03/09 22:08:38 mpowers
- * Removed unused line.
+ * Revision 1.10 2001/03/09 22:08:38 mpowers Removed unused line.
*
- * Revision 1.9 2001/03/07 16:41:04 mpowers
- * Now checking size of parent displayed objects array so that we don't
- * get array out of bounds execeptions from isLeaf() or object() when
- * those messages are called after the TreeAssociation fires a
- * nodesDeleted event. I believe that JTree is mistakenly rendering
- * those nodes one last time before erasing them.
+ * Revision 1.9 2001/03/07 16:41:04 mpowers Now checking size of parent
+ * displayed objects array so that we don't get array out of bounds execeptions
+ * from isLeaf() or object() when those messages are called after the
+ * TreeAssociation fires a nodesDeleted event. I believe that JTree is
+ * mistakenly rendering those nodes one last time before erasing them.
*
- * Revision 1.8 2001/03/06 23:21:27 mpowers
- * Now only notifying parent if the object is not registered in the
- * editing context, if any.
+ * Revision 1.8 2001/03/06 23:21:27 mpowers Now only notifying parent if the
+ * object is not registered in the editing context, if any.
*
- * Revision 1.7 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.7 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.6 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.6 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.5 2001/01/31 17:59:52 mpowers
- * Fixed isLeaf aspect of TreeAssociation.
+ * Revision 1.5 2001/01/31 17:59:52 mpowers Fixed isLeaf aspect of
+ * TreeAssociation.
*
- * Revision 1.4 2001/01/25 02:16:25 mpowers
- * TreeAssociation now returns DisplayGroupNode.getUserObject.
+ * Revision 1.4 2001/01/25 02:16:25 mpowers TreeAssociation now returns
+ * DisplayGroupNode.getUserObject.
*
- * Revision 1.3 2001/01/24 18:14:40 mpowers
- * Fixed problem with leaving children aspect unspecified.
+ * Revision 1.3 2001/01/24 18:14:40 mpowers Fixed problem with leaving children
+ * aspect unspecified.
*
- * Revision 1.2 2001/01/24 16:35:37 mpowers
- * Improved documentation on TreeAssociation.
- * SortOrderings are now inherited from parent nodes.
- * Updates after sorting are still lost on TreeController.
+ * Revision 1.2 2001/01/24 16:35:37 mpowers Improved documentation on
+ * TreeAssociation. SortOrderings are now inherited from parent nodes. Updates
+ * after sorting are still lost on TreeController.
*
- * Revision 1.1 2001/01/24 14:17:12 mpowers
- * Major revision to TreeAssociation. Can now add and remove nodes.
- * DisplayGroupNode is now it's own class.
+ * Revision 1.1 2001/01/24 14:17:12 mpowers Major revision to TreeAssociation.
+ * Can now add and remove nodes. DisplayGroupNode is now it's own class.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ListAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ListAssociation.java
index ec22bfd..440765c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ListAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ListAssociation.java
@@ -34,206 +34,166 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TextAssociation binds a JList to a display group's
-* list of displayable objects. Bindings are:
-* <ul>
-* <li>titles: a property convertable to a string for
-* display in the cells of the list</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class ListAssociation extends EOAssociation
- implements ListSelectionListener,
- ListDataListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- TitlesAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "items"
- } );
-
- protected DefaultListModel model;
-
- /**
- * Constructor expecting a JList. Throws an
- * exception if it doesn't receive one.
- * Note: This sets the JList's model to a DefaultListModel.
- */
- public ListAssociation ( Object anObject )
- {
- super( anObject );
- model = new DefaultListModel();
- ((JList)anObject).setModel( model );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof JList );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return TitlesAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- addAsListener();
- super.establishConnection();
- populateFromDisplayGroup();
- selectFromDisplayGroup();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- removeAsListener();
- super.breakConnection();
- }
-
- protected void addAsListener()
- { // System.out.println( "ListAssociation.addAsListener: " + ++count );
- component().getModel().addListDataListener( this );
- component().addListSelectionListener( this );
- }
-
- protected void removeAsListener()
- { // System.out.println( "ListAssociation.removeAsListener: " + --count );
- component().getModel().removeListDataListener( this );
- component().removeListSelectionListener( this );
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ * TextAssociation binds a JList to a display group's list of displayable
+ * objects. Bindings are:
+ * <ul>
+ * <li>titles: a property convertable to a string for display in the cells of
+ * the list</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class ListAssociation extends EOAssociation implements ListSelectionListener, ListDataListener {
+ static final NSArray aspects = new NSArray(new Object[] { TitlesAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "items" });
+
+ protected DefaultListModel model;
+
+ /**
+ * Constructor expecting a JList. Throws an exception if it doesn't receive one.
+ * Note: This sets the JList's model to a DefaultListModel.
+ */
+ public ListAssociation(Object anObject) {
+ super(anObject);
+ model = new DefaultListModel();
+ ((JList) anObject).setModel(model);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof JList);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return TitlesAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ addAsListener();
+ super.establishConnection();
+ populateFromDisplayGroup();
+ selectFromDisplayGroup();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ removeAsListener();
+ super.breakConnection();
+ }
+
+ protected void addAsListener() { // System.out.println( "ListAssociation.addAsListener: " + ++count );
+ component().getModel().addListDataListener(this);
+ component().addListSelectionListener(this);
+ }
+
+ protected void removeAsListener() { // System.out.println( "ListAssociation.removeAsListener: " + --count );
+ component().getModel().removeListDataListener(this);
+ component().removeListSelectionListener(this);
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
EODisplayGroup displayGroup;
-
+
// titles aspect
- displayGroup = displayGroupForAspect( TitlesAspect );
- if ( displayGroup != null )
- {
+ displayGroup = displayGroupForAspect(TitlesAspect);
+ if (displayGroup != null) {
//System.out.println( "subjectChanged: " +
//displayGroup.contentsChanged() + " : " + displayGroup.selectionChanged()
//+ " : " + displayGroup.updatedObjectIndex() );
//new net.wotonomy.ui.swing.util.StackTraceInspector();
- if ( displayGroup.contentsChanged() )
- {
+ if (displayGroup.contentsChanged()) {
populateFromDisplayGroup();
}
- if ( displayGroup.selectionChanged() )
- {
+ if (displayGroup.selectionChanged()) {
selectFromDisplayGroup();
}
}
- }
-
- private void populateFromDisplayGroup()
- {
+ }
+
+ private void populateFromDisplayGroup() {
JList component = component();
- EODisplayGroup displayGroup = displayGroupForAspect( TitlesAspect );
- String key = displayGroupKeyForAspect( TitlesAspect );
-
+ EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect);
+ String key = displayGroupKeyForAspect(TitlesAspect);
+
removeAsListener();
-
+
// remember selection
int[] selectedIndices = component().getSelectedIndices();
-
+
// clear the model
model.removeAllElements();
@@ -241,128 +201,111 @@ public class ListAssociation extends EOAssociation
Object value;
int size = displayGroup.displayedObjects().count();
//System.out.println( "populateFromDisplayGroup: " + size );
- for ( int i = 0; i < size; i++ )
- {
- value = displayGroup.valueForObjectAtIndex( i, key );
- if ( value == null ) value = "[null]";
- model.addElement( value );
+ for (int i = 0; i < size; i++) {
+ value = displayGroup.valueForObjectAtIndex(i, key);
+ if (value == null)
+ value = "[null]";
+ model.addElement(value);
}
-
+
// select the same indexes
- for ( int i = 0; i < selectedIndices.length; i++ )
- {
- component.addSelectionInterval(
- selectedIndices[i], selectedIndices[i] ); // adds one row
+ for (int i = 0; i < selectedIndices.length; i++) {
+ component.addSelectionInterval(selectedIndices[i], selectedIndices[i]); // adds one row
}
addAsListener();
}
-
- private void selectFromDisplayGroup()
- {
+
+ private void selectFromDisplayGroup() {
JList component = component();
- EODisplayGroup displayGroup = displayGroupForAspect( TitlesAspect );
+ EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect);
removeAsListener();
-
+
int index;
component.clearSelection();
- Enumeration e =
- displayGroup.selectionIndexes().objectEnumerator();
-
- while ( e.hasMoreElements() )
- { // add selections one-by-one to support non-contiguous
- index = ((Number)e.nextElement()).intValue();
- component.addSelectionInterval(
- index, index ); // adds one row
+ Enumeration e = displayGroup.selectionIndexes().objectEnumerator();
+
+ while (e.hasMoreElements()) { // add selections one-by-one to support non-contiguous
+ index = ((Number) e.nextElement()).intValue();
+ component.addSelectionInterval(index, index); // adds one row
}
-
+
addAsListener();
}
-
+
// interface ListSelectionListener
- public void valueChanged(ListSelectionEvent e)
- {
- final EODisplayGroup displayGroup =
- displayGroupForAspect( TitlesAspect );
- if ( ( displayGroup != null ) && ( ! e.getValueIsAdjusting() ) )
- {
- int[] selectedIndices = component().getSelectedIndices();
+ public void valueChanged(ListSelectionEvent e) {
+ final EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect);
+ if ((displayGroup != null) && (!e.getValueIsAdjusting())) {
+ int[] selectedIndices = component().getSelectedIndices();
final NSMutableArray indexList = new NSMutableArray();
- for ( int i = 0; i < selectedIndices.length; i++ )
- {
- indexList.addObject( new Integer( selectedIndices[i] ) );
+ for (int i = 0; i < selectedIndices.length; i++) {
+ indexList.addObject(new Integer(selectedIndices[i]));
}
-
- // invoke later so the component is repainted before
- // any potentially lengthy second-order effects happen:
- // this improves user-perceived responsiveness of big apps
- SwingUtilities.invokeLater( new Runnable() {
- public void run()
- {
- displayGroup.setSelectionIndexes( indexList );
- }
- });
- }
- }
-
- // interface ListDataListener
-
- public void intervalAdded(ListDataEvent e)
- {
- // System.out.println( "intervalAdded" );
- contentsChanged(e);
- }
- public void intervalRemoved(ListDataEvent e)
- {
- // System.out.println( "intervalRemoved" );
- contentsChanged(e);
- }
- public void contentsChanged(ListDataEvent e)
- {
- // System.out.println( "contentsChanged" );
-
- // if we were editing a property,
+
+ // invoke later so the component is repainted before
+ // any potentially lengthy second-order effects happen:
+ // this improves user-perceived responsiveness of big apps
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ displayGroup.setSelectionIndexes(indexList);
+ }
+ });
+ }
+ }
+
+ // interface ListDataListener
+
+ public void intervalAdded(ListDataEvent e) {
+ // System.out.println( "intervalAdded" );
+ contentsChanged(e);
+ }
+
+ public void intervalRemoved(ListDataEvent e) {
+ // System.out.println( "intervalRemoved" );
+ contentsChanged(e);
+ }
+
+ public void contentsChanged(ListDataEvent e) {
+ // System.out.println( "contentsChanged" );
+
+ // if we were editing a property,
// we'd notify our display group now.
- }
-
+ }
+
// convenience
- private JList component()
- {
- return (JList) object();
- }
+ private JList component() {
+ return (JList) object();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.5 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.4 2002/05/15 14:05:55 mpowers
- * Now appropriately selectingFromDisplayGroup on establishConnection.
+ * Revision 1.4 2002/05/15 14:05:55 mpowers Now appropriately
+ * selectingFromDisplayGroup on establishConnection.
*
- * Revision 1.3 2001/09/14 13:40:26 mpowers
- * User-initiated selection changes are now handled on the next event loop
- * so that the component repaints the new selection before any potentially
- * lengthy logic is triggered by the selection change.
+ * Revision 1.3 2001/09/14 13:40:26 mpowers User-initiated selection changes are
+ * now handled on the next event loop so that the component repaints the new
+ * selection before any potentially lengthy logic is triggered by the selection
+ * change.
*
- * Revision 1.2 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.2 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.1.1.1 2000/12/21 15:48:49 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:49 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/MutableDisplayGroupNode.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/MutableDisplayGroupNode.java
index f1568ec..5293bc9 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/MutableDisplayGroupNode.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/MutableDisplayGroupNode.java
@@ -32,185 +32,143 @@ import net.wotonomy.foundation.internal.WotonomyException;
import net.wotonomy.ui.EODisplayGroup;
/**
-* A DisplayGroupNode that exposes the MutableTreeNode interface.
-* This was required so that other subclasses of DisplayGroupNode
-* could opt out of supporting MutableTreeNode (so that they can
-* implement IlvActivity, for example).
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
- public class MutableDisplayGroupNode
- extends DisplayGroupNode implements MutableTreeNode
- {
- /**
- * Constructor for all nodes.
- * Root node must have a null delegate.
- */
- public MutableDisplayGroupNode(
- TreeModelAssociation aParentAssociation,
- EODisplayGroup aParentGroup,
- Object anObject )
- {
- super( aParentAssociation, aParentGroup, anObject );
- }
-
- public int getIndex(TreeNode node)
- {
- return getIndex( (DisplayGroupNode) node );
- }
-
- public TreeNode getChildAt(int childIndex)
- {
- return (TreeNode) getChildNodeAt( childIndex );
- }
-
- public TreeNode getParent()
- {
- Object parent = getParentGroup();
- if ( parent instanceof TreeNode )
- {
- return (TreeNode) parent;
- }
- return null;
- }
-
- public void insert(MutableTreeNode aChild, int anIndex)
- {
- if ( aChild instanceof DisplayGroupNode )
- {
- insertObjectAtIndex(
- ((DisplayGroupNode)aChild).object(), anIndex );
- }
- else // not a display group node
- {
- throw new WotonomyException(
- "Cannot insert nodes of type: " + aChild );
- }
- }
-
- /**
- * Removes the node at the index corresponding
- * to the index of the object.
- */
- public void remove(MutableTreeNode node)
- {
- if ( node instanceof DisplayGroupNode )
- {
- remove((DisplayGroupNode)node);
- }
- else // not a display group node
- {
- throw new WotonomyException(
- "Cannot insert nodes of type: " + node );
- }
- }
-
- /**
- * Removes the value in the parent display group
- * at the index that corresponds to the index of this node
- * and add it to the end of the display group that corresponds
- * to the user value of the specified node.
- */
- public void setParent(MutableTreeNode newParent)
- {
- if ( newParent instanceof DisplayGroupNode )
- {
- setParent((DisplayGroupNode)newParent);
- }
- else // not a display group node
- {
- throw new WotonomyException(
- "Cannot set parent to nodes of type: " + newParent );
- }
- }
-
- /**
- * Overridden to remember expanded state for nodes
- * after nodes have been rearranged.
- */
- protected void fireEventsForChanges(
- Object[] oldObjects, Object[] newObjects )
- {
- if ( !( parentAssociation.object() instanceof JTree ) )
- {
- super.fireEventsForChanges( oldObjects, newObjects );
- return;
- }
-
- JTree tree = (JTree) parentAssociation.object();
- Map expansionMap = new HashMap();
- DisplayGroupNode node;
- TreePath path;
- for ( int i = 0; i < oldObjects.length; i++ )
- {
- node = (DisplayGroupNode)
- getChildNodeForObject( oldObjects[i] );
- if ( node != null && ! node.isLeaf() )
- {
- expansionMap.put( node, new Boolean(
- tree.isExpanded( node.treePath() ) ) );
- }
- }
-
- super.fireEventsForChanges( oldObjects, newObjects );
-
- Object value;
- Iterator iterator = new LinkedList( childNodes.values() ).iterator();
- while ( iterator.hasNext() )
- {
- node = (DisplayGroupNode) iterator.next();
- value = expansionMap.get( node );
- if ( value != null )
- {
- if ( Boolean.TRUE.equals( value ) )
- {
- tree.expandPath( node.treePath() );
- }
- else
- {
- tree.collapsePath( node.treePath() );
- }
- }
- }
- }
- }
+ * A DisplayGroupNode that exposes the MutableTreeNode interface. This was
+ * required so that other subclasses of DisplayGroupNode could opt out of
+ * supporting MutableTreeNode (so that they can implement IlvActivity, for
+ * example).
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class MutableDisplayGroupNode extends DisplayGroupNode implements MutableTreeNode {
+ /**
+ * Constructor for all nodes. Root node must have a null delegate.
+ */
+ public MutableDisplayGroupNode(TreeModelAssociation aParentAssociation, EODisplayGroup aParentGroup,
+ Object anObject) {
+ super(aParentAssociation, aParentGroup, anObject);
+ }
+
+ public int getIndex(TreeNode node) {
+ return getIndex((DisplayGroupNode) node);
+ }
+
+ public TreeNode getChildAt(int childIndex) {
+ return (TreeNode) getChildNodeAt(childIndex);
+ }
+
+ public TreeNode getParent() {
+ Object parent = getParentGroup();
+ if (parent instanceof TreeNode) {
+ return (TreeNode) parent;
+ }
+ return null;
+ }
+
+ public void insert(MutableTreeNode aChild, int anIndex) {
+ if (aChild instanceof DisplayGroupNode) {
+ insertObjectAtIndex(((DisplayGroupNode) aChild).object(), anIndex);
+ } else // not a display group node
+ {
+ throw new WotonomyException("Cannot insert nodes of type: " + aChild);
+ }
+ }
+
+ /**
+ * Removes the node at the index corresponding to the index of the object.
+ */
+ public void remove(MutableTreeNode node) {
+ if (node instanceof DisplayGroupNode) {
+ remove((DisplayGroupNode) node);
+ } else // not a display group node
+ {
+ throw new WotonomyException("Cannot insert nodes of type: " + node);
+ }
+ }
+
+ /**
+ * Removes the value in the parent display group at the index that corresponds
+ * to the index of this node and add it to the end of the display group that
+ * corresponds to the user value of the specified node.
+ */
+ public void setParent(MutableTreeNode newParent) {
+ if (newParent instanceof DisplayGroupNode) {
+ setParent((DisplayGroupNode) newParent);
+ } else // not a display group node
+ {
+ throw new WotonomyException("Cannot set parent to nodes of type: " + newParent);
+ }
+ }
+
+ /**
+ * Overridden to remember expanded state for nodes after nodes have been
+ * rearranged.
+ */
+ protected void fireEventsForChanges(Object[] oldObjects, Object[] newObjects) {
+ if (!(parentAssociation.object() instanceof JTree)) {
+ super.fireEventsForChanges(oldObjects, newObjects);
+ return;
+ }
+
+ JTree tree = (JTree) parentAssociation.object();
+ Map expansionMap = new HashMap();
+ DisplayGroupNode node;
+ TreePath path;
+ for (int i = 0; i < oldObjects.length; i++) {
+ node = (DisplayGroupNode) getChildNodeForObject(oldObjects[i]);
+ if (node != null && !node.isLeaf()) {
+ expansionMap.put(node, new Boolean(tree.isExpanded(node.treePath())));
+ }
+ }
+
+ super.fireEventsForChanges(oldObjects, newObjects);
+
+ Object value;
+ Iterator iterator = new LinkedList(childNodes.values()).iterator();
+ while (iterator.hasNext()) {
+ node = (DisplayGroupNode) iterator.next();
+ value = expansionMap.get(node);
+ if (value != null) {
+ if (Boolean.TRUE.equals(value)) {
+ tree.expandPath(node.treePath());
+ } else {
+ tree.collapsePath(node.treePath());
+ }
+ }
+ }
+ }
+}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.8 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.7 2002/04/23 19:12:28 mpowers
- * Reimplemented fireEventsForChanges. Fitter and happier.
+ * Revision 1.7 2002/04/23 19:12:28 mpowers Reimplemented fireEventsForChanges.
+ * Fitter and happier.
*
- * Revision 1.6 2002/04/10 21:20:04 mpowers
- * Better handling for tree nodes when working with editing contexts.
- * Better handling for invalidation. No longer broadcasting events
- * when nodes have not been "registered" in the tree.
+ * Revision 1.6 2002/04/10 21:20:04 mpowers Better handling for tree nodes when
+ * working with editing contexts. Better handling for invalidation. No longer
+ * broadcasting events when nodes have not been "registered" in the tree.
*
- * Revision 1.5 2002/04/03 20:01:47 mpowers
- * Now remembers expanded state.
+ * Revision 1.5 2002/04/03 20:01:47 mpowers Now remembers expanded state.
*
- * Revision 1.4 2002/03/08 23:19:07 mpowers
- * Added getParentGroup to DisplayGroupNode.
+ * Revision 1.4 2002/03/08 23:19:07 mpowers Added getParentGroup to
+ * DisplayGroupNode.
*
- * Revision 1.3 2002/02/27 23:19:17 mpowers
- * Refactoring of TreeAssociation to create TreeModelAssociation parent.
+ * Revision 1.3 2002/02/27 23:19:17 mpowers Refactoring of TreeAssociation to
+ * create TreeModelAssociation parent.
*
- * Revision 1.2 2001/04/22 23:05:33 mpowers
- * Totally revised DisplayGroupNode so each object gets its own node
- * (so the nodes are no longer fixed by index).
+ * Revision 1.2 2001/04/22 23:05:33 mpowers Totally revised DisplayGroupNode so
+ * each object gets its own node (so the nodes are no longer fixed by index).
*
- * Revision 1.1 2001/04/21 23:05:56 mpowers
- * Contributing the tree-specific concrete subclass of DisplayGroupNode.
+ * Revision 1.1 2001/04/21 23:05:56 mpowers Contributing the tree-specific
+ * concrete subclass of DisplayGroupNode.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/NotificationInspector.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/NotificationInspector.java
index d105d89..4f65672 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/NotificationInspector.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/NotificationInspector.java
@@ -49,285 +49,252 @@ import net.wotonomy.ui.swing.util.WindowUtilities;
import net.wotonomy.control.internal.Surrogate;
/**
-* The NotificationInspector displays a JFrame that
-* displays notifications as they occur. <br><br>
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
-
-public class NotificationInspector
- implements MouseListener, ActionListener
-{
- protected JTable table;
- protected JPopupMenu popupMenu;
- protected EODisplayGroup displayGroup;
-
- // key command to copy contents to clipboard
- static public final String COPY = "COPY";
-
- protected static final String CLEAR_ALL = "Clear All";
- protected static final String CLEAR_SELECTED = "Clear Selected";
-
-
-/**
-* Displays all notifications on the default notification center.
-*/
- public NotificationInspector()
- {
- this( NSNotificationCenter.defaultCenter() );
- }
-
-/**
-* Displays all notifications from the specified notification center.
-*/
- public NotificationInspector( NSNotificationCenter aCenter )
- {
- this( aCenter, null, null );
- }
-
-/**
-* Displays notifications from the default notification center
-* using the specified name and object filters.
-*/
- public NotificationInspector( String notificationName, Object anObject )
- {
- this( NSNotificationCenter.defaultCenter(),
- notificationName, anObject );
- }
+ * The NotificationInspector displays a JFrame that displays notifications as
+ * they occur. <br>
+ * <br>
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
-/**
-* Displays notifications on the specified notification center
-* using the specified name and object filters.
-*/
- public NotificationInspector( NSNotificationCenter aCenter,
- String notificationName, Object anObject )
- {
- // show stack traces
- NSNotification.showStack = true;
-
- // register for notifications
- NSSelector handleNotification =
- new NSSelector( "handleNotification",
- new Class[] { NSNotification.class } );
- aCenter.addObserver(
- this, handleNotification, notificationName, anObject );
-
- table = new JTable();
-
- popupMenu = new JPopupMenu();
- JMenuItem menuItem = popupMenu.add( CLEAR_SELECTED );
- menuItem.addActionListener( this );
- menuItem = popupMenu.add( CLEAR_ALL );
- menuItem.addActionListener( this );
-
- displayGroup = new EODisplayGroup();
-
- TableColumn column;
- TableColumnAssociation assoc;
-
- column = new TableColumn();
- column.setHeaderValue( "Time" );
- column.setCellRenderer( new FormattedCellRenderer( new SimpleDateFormat( "hh:mm:ss:SS" ) ) );
- column.setPreferredWidth( 90 );
- column.setMaxWidth( 90 );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "time" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- column = new TableColumn();
- column.setHeaderValue( "Type" );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "name" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- column = new TableColumn();
- column.setHeaderValue( "Object" );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "objectString" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- column = new TableColumn();
- column.setHeaderValue( "Info" );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "userInfoString" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- initLayout();
- }
-
- protected void initLayout()
- {
- table.addMouseListener( this ); // listen for double-clicks
-
- JPanel panel = new JPanel();
- panel.setBorder( new EmptyBorder( new Insets( 10, 10, 10, 10 ) ) );
- panel.setLayout( new BorderLayout( 10, 10 ) );
-
- JScrollPane scrollPane = new JScrollPane( table );
- //scrollPane.setPreferredSize( new Dimension( 500, 250 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
-
- JFrame window = new JFrame();
- window.setTitle( "Notification Inspector" );
- window.getContentPane().add( panel );
-
- //window.pack();
- window.setSize( 800, 400 );
- WindowUtilities.cascade( window );
-
- // size the columns.
+public class NotificationInspector implements MouseListener, ActionListener {
+ protected JTable table;
+ protected JPopupMenu popupMenu;
+ protected EODisplayGroup displayGroup;
+
+ // key command to copy contents to clipboard
+ static public final String COPY = "COPY";
+
+ protected static final String CLEAR_ALL = "Clear All";
+ protected static final String CLEAR_SELECTED = "Clear Selected";
+
+ /**
+ * Displays all notifications on the default notification center.
+ */
+ public NotificationInspector() {
+ this(NSNotificationCenter.defaultCenter());
+ }
+
+ /**
+ * Displays all notifications from the specified notification center.
+ */
+ public NotificationInspector(NSNotificationCenter aCenter) {
+ this(aCenter, null, null);
+ }
+
+ /**
+ * Displays notifications from the default notification center using the
+ * specified name and object filters.
+ */
+ public NotificationInspector(String notificationName, Object anObject) {
+ this(NSNotificationCenter.defaultCenter(), notificationName, anObject);
+ }
+
+ /**
+ * Displays notifications on the specified notification center using the
+ * specified name and object filters.
+ */
+ public NotificationInspector(NSNotificationCenter aCenter, String notificationName, Object anObject) {
+ // show stack traces
+ NSNotification.showStack = true;
+
+ // register for notifications
+ NSSelector handleNotification = new NSSelector("handleNotification", new Class[] { NSNotification.class });
+ aCenter.addObserver(this, handleNotification, notificationName, anObject);
+
+ table = new JTable();
+
+ popupMenu = new JPopupMenu();
+ JMenuItem menuItem = popupMenu.add(CLEAR_SELECTED);
+ menuItem.addActionListener(this);
+ menuItem = popupMenu.add(CLEAR_ALL);
+ menuItem.addActionListener(this);
+
+ displayGroup = new EODisplayGroup();
+
+ TableColumn column;
+ TableColumnAssociation assoc;
+
+ column = new TableColumn();
+ column.setHeaderValue("Time");
+ column.setCellRenderer(new FormattedCellRenderer(new SimpleDateFormat("hh:mm:ss:SS")));
+ column.setPreferredWidth(90);
+ column.setMaxWidth(90);
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "time");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ column = new TableColumn();
+ column.setHeaderValue("Type");
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "name");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ column = new TableColumn();
+ column.setHeaderValue("Object");
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "objectString");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ column = new TableColumn();
+ column.setHeaderValue("Info");
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "userInfoString");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ initLayout();
+ }
+
+ protected void initLayout() {
+ table.addMouseListener(this); // listen for double-clicks
+
+ JPanel panel = new JPanel();
+ panel.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
+ panel.setLayout(new BorderLayout(10, 10));
+
+ JScrollPane scrollPane = new JScrollPane(table);
+ // scrollPane.setPreferredSize( new Dimension( 500, 250 ) );
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+ JFrame window = new JFrame();
+ window.setTitle("Notification Inspector");
+ window.getContentPane().add(panel);
+
+ // window.pack();
+ window.setSize(800, 400);
+ WindowUtilities.cascade(window);
+
+ // size the columns.
// table.getColumnModel().getColumn( 0 ).setPreferredWidth( 100 );
- window.show();
- }
-
-/**
-* Handles the notification.
-*/
- public void handleNotification( NSNotification aNotification )
- {
- Surrogate s = new Surrogate( new Object[] { aNotification } );
- s.directPut( "time", new Date() );
- s.directPut( "objectString", ""+aNotification.object() ); // snapshot of state
- s.directPut( "userInfoString", ""+aNotification.userInfo() ); // snapshot of info
- displayGroup.insertObjectAtIndex( s, 0 );
- }
-
- // interface ActionListener
-
- /**
- * Method used to listen for the action event from the popup menu items.
- */
- public void actionPerformed( ActionEvent e )
- {
- if ( CLEAR_SELECTED.equals( e.getActionCommand() ) )
- {
- NSMutableArray objects = new NSMutableArray( displayGroup.allObjects() );
- objects.removeAll( displayGroup.selectedObjects() );
- displayGroup.setObjectArray( objects );
- displayGroup.updateDisplayedObjects();
- }
- else if ( CLEAR_ALL.equals( e.getActionCommand() ) )
- {
- displayGroup.setObjectArray( null );
- displayGroup.updateDisplayedObjects();
- }
- }
-
- // interface MouseListener
-
- /**
- * Double click to launch object inspector.
- */
-
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.getClickCount() > 1 )
- {
- int row = table.rowAtPoint( e.getPoint() );
- int col = table.columnAtPoint( e.getPoint() );
- col = table.convertColumnIndexToModel( col );
-
- if ( row == -1 ) return;
-
- if ( col == 0 ) // time
- {
- new StackTraceInspector( ( (NSNotification) ( (Surrogate)
- displayGroup.displayedObjects().objectAtIndex( row ) ).getDelegate() ).stackTrace() );
- }
- else
- if ( col == 2 ) // object
- {
- new ObjectInspector( ( (NSNotification) ( (Surrogate)
- displayGroup.displayedObjects().objectAtIndex( row ) ).getDelegate() ).object() );
- }
- else
- if ( col == 3 ) // info
- {
- new ObjectInspector( ( (NSNotification) ( (Surrogate)
- displayGroup.displayedObjects().objectAtIndex( row ) ).getDelegate() ).userInfo() );
- }
- else
- {
- new ObjectInspector( ( (Surrogate)
- displayGroup.displayedObjects().objectAtIndex( row ) ).getDelegate() );
- }
- }
- else
- {
- // Click count is 1 then, check for popup trigger.
- if ( e.isPopupTrigger() )
- {
- popupMenu.show( table, e.getX(), e.getY() );
- }
- }
- }
- }
-
- public void mouseReleased(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.isPopupTrigger() && ( e.getClickCount() == 1 ) )
- {
- popupMenu.show( table, e.getX(), e.getY() );
- }
- }
- }
-
- public void mousePressed(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.isPopupTrigger() && ( e.getClickCount() == 1 ) )
- {
- popupMenu.show( table, e.getX(), e.getY() );
- }
- }
- }
-
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {}
+ window.show();
+ }
+
+ /**
+ * Handles the notification.
+ */
+ public void handleNotification(NSNotification aNotification) {
+ Surrogate s = new Surrogate(new Object[] { aNotification });
+ s.directPut("time", new Date());
+ s.directPut("objectString", "" + aNotification.object()); // snapshot of state
+ s.directPut("userInfoString", "" + aNotification.userInfo()); // snapshot of info
+ displayGroup.insertObjectAtIndex(s, 0);
+ }
+
+ // interface ActionListener
+
+ /**
+ * Method used to listen for the action event from the popup menu items.
+ */
+ public void actionPerformed(ActionEvent e) {
+ if (CLEAR_SELECTED.equals(e.getActionCommand())) {
+ NSMutableArray objects = new NSMutableArray(displayGroup.allObjects());
+ objects.removeAll(displayGroup.selectedObjects());
+ displayGroup.setObjectArray(objects);
+ displayGroup.updateDisplayedObjects();
+ } else if (CLEAR_ALL.equals(e.getActionCommand())) {
+ displayGroup.setObjectArray(null);
+ displayGroup.updateDisplayedObjects();
+ }
+ }
+
+ // interface MouseListener
+
+ /**
+ * Double click to launch object inspector.
+ */
+
+ public void mouseClicked(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.getClickCount() > 1) {
+ int row = table.rowAtPoint(e.getPoint());
+ int col = table.columnAtPoint(e.getPoint());
+ col = table.convertColumnIndexToModel(col);
+
+ if (row == -1)
+ return;
+
+ if (col == 0) // time
+ {
+ new StackTraceInspector(
+ ((NSNotification) ((Surrogate) displayGroup.displayedObjects().objectAtIndex(row))
+ .getDelegate()).stackTrace());
+ } else if (col == 2) // object
+ {
+ new ObjectInspector(
+ ((NSNotification) ((Surrogate) displayGroup.displayedObjects().objectAtIndex(row))
+ .getDelegate()).object());
+ } else if (col == 3) // info
+ {
+ new ObjectInspector(
+ ((NSNotification) ((Surrogate) displayGroup.displayedObjects().objectAtIndex(row))
+ .getDelegate()).userInfo());
+ } else {
+ new ObjectInspector(((Surrogate) displayGroup.displayedObjects().objectAtIndex(row)).getDelegate());
+ }
+ } else {
+ // Click count is 1 then, check for popup trigger.
+ if (e.isPopupTrigger()) {
+ popupMenu.show(table, e.getX(), e.getY());
+ }
+ }
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.isPopupTrigger() && (e.getClickCount() == 1)) {
+ popupMenu.show(table, e.getX(), e.getY());
+ }
+ }
+ }
+
+ public void mousePressed(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.isPopupTrigger() && (e.getClickCount() == 1)) {
+ popupMenu.show(table, e.getX(), e.getY());
+ }
+ }
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ public void mouseExited(MouseEvent e) {
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:23 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:23 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.6 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.5 2002/11/18 22:11:51 mpowers
- * rglista's long-overdue enhancements: can now clear the display!
+ * Revision 1.5 2002/11/18 22:11:51 mpowers rglista's long-overdue enhancements:
+ * can now clear the display!
*
- * Revision 1.4 2002/10/24 18:19:03 mpowers
- * Now telling NSNotification to generate stack traces.
+ * Revision 1.4 2002/10/24 18:19:03 mpowers Now telling NSNotification to
+ * generate stack traces.
*
- * Revision 1.3 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.3 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.2 2001/04/09 21:40:25 mpowers
- * Numerous usability enhancements.
+ * Revision 1.2 2001/04/09 21:40:25 mpowers Numerous usability enhancements.
*
- * Revision 1.1 2001/04/08 20:58:45 mpowers
- * Contributing notification inspector.
+ * Revision 1.1 2001/04/08 20:58:45 mpowers Contributing notification inspector.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/RadioPanelAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/RadioPanelAssociation.java
index d2e51ed..b287691 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/RadioPanelAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/RadioPanelAssociation.java
@@ -28,430 +28,343 @@ import net.wotonomy.ui.EODisplayGroup;
import net.wotonomy.ui.swing.components.RadioButtonPanel;
/**
-* RadioPanelAssociation binds RadioButtonPanels to
-* display groups. It works exactly like a
-* ComboBoxAssociation. Bindings are:
-* <ul>
-*
-* <li>value: a property of the selected object in the
-* display group that will be bind to the item the user
-* selects or the text that the user enters in the field.</li>
-*
-* <li>titles: a property of the objects in the bound
-* display group that will appear in the list. If the
-* objects aspect is not bound, this property is also
-* used to populate the value binding.</li>
-*
-* <li>objects: optional - if specified, when the user
-* selects an title in the list, the property of the
-* object at the corresponding index of the bound display
-* group will be used to populate the value binding.</li>
-*
-* <li>enabled: a boolean property of the selected object in the
-* display group that determines whether
-* the user can edit the field.</li>
-*
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class RadioPanelAssociation extends EOAssociation
- implements ActionListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- TitlesAspect, ValueAspect,
- ObjectsAspect, EnabledAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "text"
- } );
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public RadioPanelAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof RadioButtonPanel );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
+ * RadioPanelAssociation binds RadioButtonPanels to display groups. It works
+ * exactly like a ComboBoxAssociation. Bindings are:
+ * <ul>
+ *
+ * <li>value: a property of the selected object in the display group that will
+ * be bind to the item the user selects or the text that the user enters in the
+ * field.</li>
+ *
+ * <li>titles: a property of the objects in the bound display group that will
+ * appear in the list. If the objects aspect is not bound, this property is also
+ * used to populate the value binding.</li>
+ *
+ * <li>objects: optional - if specified, when the user selects an title in the
+ * list, the property of the object at the corresponding index of the bound
+ * display group will be used to populate the value binding.</li>
+ *
+ * <li>enabled: a boolean property of the selected object in the display group
+ * that determines whether the user can edit the field.</li>
+ *
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class RadioPanelAssociation extends EOAssociation implements ActionListener {
+ static final NSArray aspects = new NSArray(
+ new Object[] { TitlesAspect, ValueAspect, ObjectsAspect, EnabledAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "text" });
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public RadioPanelAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof RadioButtonPanel);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
super.establishConnection();
// prepopulate titles
- EODisplayGroup displayGroup =
- displayGroupForAspect( TitlesAspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( TitlesAspect );
- populateTitles( displayGroup, key );
+ EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(TitlesAspect);
+ populateTitles(displayGroup, key);
}
- populateValue();
- addAsListener();
- }
-
- protected void addAsListener()
- {
- component().addActionListener( this );
+ populateValue();
+ addAsListener();
+ }
+
+ protected void addAsListener() {
+ component().addActionListener(this);
}
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
removeAsListener();
- super.breakConnection();
- }
+ super.breakConnection();
+ }
- protected void removeAsListener()
- {
- component().removeActionListener( this );
+ protected void removeAsListener() {
+ component().removeActionListener(this);
}
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
removeAsListener();
-
+
RadioButtonPanel component = component();
EODisplayGroup displayGroup;
String key;
-
+
// titles aspect
- displayGroup = displayGroupForAspect( TitlesAspect );
- if ( displayGroup != null )
- {
+ displayGroup = displayGroupForAspect(TitlesAspect);
+ if (displayGroup != null) {
// if backing group has changed
- if ( displayGroup.contentsChanged() )
- {
- key = displayGroupKeyForAspect( TitlesAspect );
- populateTitles( displayGroup, key );
+ if (displayGroup.contentsChanged()) {
+ key = displayGroupKeyForAspect(TitlesAspect);
+ populateTitles(displayGroup, key);
}
}
- // value aspect
- populateValue();
-
+ // value aspect
+ populateValue();
+
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( EnabledAspect );
- Object value =
- displayGroup.selectedObjectValueForKey( key );
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() != component.isEnabled() )
- {
- component.setEnabled( converted.booleanValue() );
- }
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(EnabledAspect);
+ Object value = displayGroup.selectedObjectValueForKey(key);
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != component.isEnabled()) {
+ component.setEnabled(converted.booleanValue());
+ }
}
-
+
addAsListener();
- }
-
+ }
+
/**
- * Called to repopulate the title list from the
- * specified display group.
- */
- protected void populateTitles(
- EODisplayGroup displayGroup, String key )
- {
+ * Called to repopulate the title list from the specified display group.
+ */
+ protected void populateTitles(EODisplayGroup displayGroup, String key) {
Object value;
int count = displayGroup.displayedObjects().count();
- String[] titles = new String[ count ];
- for ( int i = 0; i < count; i++ )
- {
- value = displayGroup.valueForObjectAtIndex( i, key );
- if ( value != null )
- {
+ String[] titles = new String[count];
+ for (int i = 0; i < count; i++) {
+ value = displayGroup.valueForObjectAtIndex(i, key);
+ if (value != null) {
titles[i] = value.toString();
- }
- else
- {
- titles[i] = "";
+ } else {
+ titles[i] = "";
}
}
- component().setLabels( titles );
+ component().setLabels(titles);
}
-
+
/**
- * Called to populate the value from the display group.
- */
- protected void populateValue()
- {
+ * Called to populate the value from the display group.
+ */
+ protected void populateValue() {
RadioButtonPanel component = component();
EODisplayGroup displayGroup;
String key;
// value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- component.setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
-
- Object value = displayGroup.selectedObjectValueForKey( key );
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ component.setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+
+ Object value = displayGroup.selectedObjectValueForKey(key);
// objects aspect
- EODisplayGroup objectsDisplayGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( ( objectsDisplayGroup != null ) && ( value != null ) )
- {
- String objectKey = displayGroupKeyForAspect( ObjectsAspect );
+ EODisplayGroup objectsDisplayGroup = displayGroupForAspect(ObjectsAspect);
+ if ((objectsDisplayGroup != null) && (value != null)) {
+ String objectKey = displayGroupKeyForAspect(ObjectsAspect);
Object match;
int index = NSArray.NotFound;
int count = objectsDisplayGroup.displayedObjects().count();
- for ( int i = 0; i < count; i++ )
- {
- match = objectsDisplayGroup.valueForObjectAtIndex( i, objectKey );
- if ( value.equals( match ) )
- {
+ for (int i = 0; i < count; i++) {
+ match = objectsDisplayGroup.valueForObjectAtIndex(i, objectKey);
+ if (value.equals(match)) {
index = i;
}
}
- if ( index == NSArray.NotFound )
- {
- if ( component.getValue() != null )
- {
- component.setValue( null );
+ if (index == NSArray.NotFound) {
+ if (component.getValue() != null) {
+ component.setValue(null);
}
- }
- else
- {
+ } else {
String[] titles = component().getLabels();
- component.setValue( titles[ index ] );
+ component.setValue(titles[index]);
}
- }
- else
- {
- if ( value != null ) value = value.toString();
- component.setValue( (String) value );
+ } else {
+ if (value != null)
+ value = value.toString();
+ component.setValue((String) value);
}
}
}
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
return writeValueToDisplayGroup();
- }
-
+ }
+
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
RadioButtonPanel component = component();
EODisplayGroup displayGroup;
String key;
-
+
// selected title aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
Object value = null;
// selected object aspect, if any
- EODisplayGroup objectsGroup =
- displayGroupForAspect( ObjectsAspect );
- if ( objectsGroup != null )
- {
- String objectKey = displayGroupKeyForAspect( ObjectsAspect );
- String selectedValue = component.getValue();
- if ( selectedValue != null )
- {
+ EODisplayGroup objectsGroup = displayGroupForAspect(ObjectsAspect);
+ if (objectsGroup != null) {
+ String objectKey = displayGroupKeyForAspect(ObjectsAspect);
+ String selectedValue = component.getValue();
+ if (selectedValue != null) {
String[] titles = component.getLabels();
int index = -1;
- for ( int i = 0; i < titles.length; i++ )
- {
- if ( selectedValue.equals( titles[i] ) )
- {
- index = i;
+ for (int i = 0; i < titles.length; i++) {
+ if (selectedValue.equals(titles[i])) {
+ index = i;
}
}
- if ( index != -1 )
- {
- value = objectsGroup
- .valueForObjectAtIndex( index, objectKey );
+ if (index != -1) {
+ value = objectsGroup.valueForObjectAtIndex(index, objectKey);
}
}
- }
- else // just use the selected item
+ } else // just use the selected item
{
- value = component.getValue();
+ value = component.getValue();
}
- return displayGroup.setSelectedObjectValue( value, key );
+ return displayGroup.setSelectedObjectValue(value, key);
}
-
+
return false;
}
-
- // interface ActionListener
-
+
+ // interface ActionListener
+
/**
- * Updates object on action performed.
- */
- public void actionPerformed( ActionEvent evt )
- {
+ * Updates object on action performed.
+ */
+ public void actionPerformed(ActionEvent evt) {
writeValueToDisplayGroup();
}
-
+
// convenience
- private RadioButtonPanel component()
- {
+ private RadioButtonPanel component() {
return (RadioButtonPanel) object();
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.4 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2001/02/16 17:48:07 mpowers
- * Populating titles or data not longer marks target object as changed.
+ * Revision 1.2 2001/02/16 17:48:07 mpowers Populating titles or data not longer
+ * marks target object as changed.
*
- * Revision 1.1.1.1 2000/12/21 15:48:52 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:52 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ReferenceInspector.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ReferenceInspector.java
index 7194f23..afa5909 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ReferenceInspector.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/ReferenceInspector.java
@@ -43,241 +43,220 @@ import net.wotonomy.ui.swing.components.ButtonPanel;
import net.wotonomy.ui.swing.util.WindowUtilities;
/**
-* ReferenceInspector tracks objects until they are garbage collected.
-* Use it to track objects that you suspect are not being GCed.
-* ReferenceInspector retains only weak references to the objects that
-* it tracks, so when those weak references cannot be resolved, the
-* object has been garbage collected. Note that under some GC
-* implementations, adding a weak reference to an object will delay
-* garbage collection for that object.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
+ * ReferenceInspector tracks objects until they are garbage collected. Use it to
+ * track objects that you suspect are not being GCed. ReferenceInspector retains
+ * only weak references to the objects that it tracks, so when those weak
+ * references cannot be resolved, the object has been garbage collected. Note
+ * that under some GC implementations, adding a weak reference to an object will
+ * delay garbage collection for that object.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
-public class ReferenceInspector
- implements MouseListener, ActionListener
-{
- protected JTable table;
- protected JLabel memoryLabel;
-
- static protected EODisplayGroup displayGroup;
- static protected JFrame window;
-
- /* Reference queue for cleared WeakKeys */
- private static ReferenceQueue queue = new ReferenceQueue();
-
- // key command to copy contents to clipboard
- static public final String COPY = "COPY";
+public class ReferenceInspector implements MouseListener, ActionListener {
+ protected JTable table;
+ protected JLabel memoryLabel;
-/**
-* Launches a new ReferenceInspector if one does not already exist.
-*/
- public ReferenceInspector()
- {
- if ( window == null )
- {
- table = new JTable();
- memoryLabel = new JLabel();
-
- displayGroup = new EODisplayGroup();
-
- TableColumn column;
- TableColumnAssociation assoc;
-
- column = new TableColumn();
- column.setHeaderValue( "Object" );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- column = new TableColumn();
- column.setHeaderValue( "Address" );
- column.setMaxWidth( 100 );
-
- assoc = new TableColumnAssociation( column );
- assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "identityHashCode" );
- assoc.setTable( table );
- assoc.establishConnection();
-
- initLayout();
- }
- window.show();
- }
+ static protected EODisplayGroup displayGroup;
+ static protected JFrame window;
-/**
-* Adds the specified object to the ReferenceInspector, launching
-* a new ReferenceInspector if one does not already exist.
-*/
- public ReferenceInspector( Object anObject )
- {
- this();
- displayGroup.insertObjectAtIndex( new ExtendedWeakReference( anObject, queue ), 0 );
- window.show();
- }
-
- protected void initLayout()
- {
- table.addMouseListener( this ); // listen for double-clicks
-
- JPanel panel = new JPanel();
- panel.setBorder( new EmptyBorder( new Insets( 10, 10, 10, 10 ) ) );
- panel.setLayout( new BorderLayout( 10, 10 ) );
-
- JScrollPane scrollPane = new JScrollPane( table );
- scrollPane.setPreferredSize( new Dimension( 500, 250 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
-
- ButtonPanel buttonPanel = new ButtonPanel( new String[] { "Update" } );
- buttonPanel.addActionListener( this );
-
- JPanel bottomPanel = new JPanel();
- bottomPanel.setLayout( new BorderLayout() );
- bottomPanel.add( buttonPanel, BorderLayout.EAST );
- bottomPanel.add( memoryLabel, BorderLayout.CENTER );
- panel.add( bottomPanel, BorderLayout.SOUTH );
-
- window = new JFrame();
- window.setTitle( "Reference Inspector" );
- window.getContentPane().add( panel );
+ /* Reference queue for cleared WeakKeys */
+ private static ReferenceQueue queue = new ReferenceQueue();
+
+ // key command to copy contents to clipboard
+ static public final String COPY = "COPY";
+
+ /**
+ * Launches a new ReferenceInspector if one does not already exist.
+ */
+ public ReferenceInspector() {
+ if (window == null) {
+ table = new JTable();
+ memoryLabel = new JLabel();
+
+ displayGroup = new EODisplayGroup();
+
+ TableColumn column;
+ TableColumnAssociation assoc;
+
+ column = new TableColumn();
+ column.setHeaderValue("Object");
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ column = new TableColumn();
+ column.setHeaderValue("Address");
+ column.setMaxWidth(100);
+
+ assoc = new TableColumnAssociation(column);
+ assoc.bindAspect(EOAssociation.ValueAspect, displayGroup, "identityHashCode");
+ assoc.setTable(table);
+ assoc.establishConnection();
+
+ initLayout();
+ }
+ window.show();
+ }
+
+ /**
+ * Adds the specified object to the ReferenceInspector, launching a new
+ * ReferenceInspector if one does not already exist.
+ */
+ public ReferenceInspector(Object anObject) {
+ this();
+ displayGroup.insertObjectAtIndex(new ExtendedWeakReference(anObject, queue), 0);
+ window.show();
+ }
+
+ protected void initLayout() {
+ table.addMouseListener(this); // listen for double-clicks
+
+ JPanel panel = new JPanel();
+ panel.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
+ panel.setLayout(new BorderLayout(10, 10));
+
+ JScrollPane scrollPane = new JScrollPane(table);
+ scrollPane.setPreferredSize(new Dimension(500, 250));
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+ ButtonPanel buttonPanel = new ButtonPanel(new String[] { "Update" });
+ buttonPanel.addActionListener(this);
+
+ JPanel bottomPanel = new JPanel();
+ bottomPanel.setLayout(new BorderLayout());
+ bottomPanel.add(buttonPanel, BorderLayout.EAST);
+ bottomPanel.add(memoryLabel, BorderLayout.CENTER);
+ panel.add(bottomPanel, BorderLayout.SOUTH);
+
+ window = new JFrame();
+ window.setTitle("Reference Inspector");
+ window.getContentPane().add(panel);
// javax.swing.Timer timer = new javax.swing.Timer( 10000, this );
// timer.restart();
-
- window.pack();
- WindowUtilities.cascade( window );
- window.show();
- }
-
- /* Remove all invalidated entries from the map, that is, remove all entries
- whose keys have been discarded. This method should be invoked once by
- each public mutator in this class. We don't invoke this method in
- public accessors because that can lead to surprising
- ConcurrentModificationExceptions. */
- private static void processQueue()
- {
+
+ window.pack();
+ WindowUtilities.cascade(window);
+ window.show();
+ }
+
+ /*
+ * Remove all invalidated entries from the map, that is, remove all entries
+ * whose keys have been discarded. This method should be invoked once by each
+ * public mutator in this class. We don't invoke this method in public accessors
+ * because that can lead to surprising ConcurrentModificationExceptions.
+ */
+ private static void processQueue() {
// System.out.println( "ReferenceInspector.processQueue:");
- synchronized ( displayGroup )
- {
- int idx;
- WeakReference rk;
- while ((rk = (WeakReference)queue.poll()) != null)
- {
+ synchronized (displayGroup) {
+ int idx;
+ WeakReference rk;
+ while ((rk = (WeakReference) queue.poll()) != null) {
// System.out.println( "ReferenceInspector.processQueue: removing object: " + rk );
- if ( rk != null )
- {
- idx = displayGroup.displayedObjects().indexOfIdenticalObject( rk );
- if ( idx != NSArray.NotFound )
- {
- displayGroup.deleteObjectAtIndex( idx );
- }
- }
- }
- displayGroup.updateDisplayedObjects();
- }
- }
-
- // interface ActionListener
-
- public void actionPerformed( ActionEvent evt )
- {
- Runtime runtime = Runtime.getRuntime();
- runtime.gc();
- processQueue();
-
- long totalMemory = runtime.totalMemory() / 1024;
- long freeMemory = runtime.freeMemory() / 1024;
- memoryLabel.setText(
- Long.toString( totalMemory - freeMemory ) + "K / " +
- Long.toString( totalMemory ) + "K" );
- }
-
- // interface MouseListener
-
- /**
- * Double click to launch object inspector.
- */
-
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.getClickCount() > 1 )
- {
- int row = table.rowAtPoint( e.getPoint() );
- int col = table.columnAtPoint( e.getPoint() );
- col = table.convertColumnIndexToModel( col );
-
- if ( row == -1 ) return;
-
- if ( col == 0 ) // time
- {
- }
- else
- {
- }
- }
- }
- }
-
- public void mouseReleased(MouseEvent e) {}
- public void mousePressed(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {}
-
- public class ExtendedWeakReference extends WeakReference
- {
- public ExtendedWeakReference(Object referent, ReferenceQueue q)
- {
- super( referent, q );
- }
-
- public String toString()
- {
- if ( get() != null )
- {
- return get().toString();
- }
- return null;
- }
-
- public String identityHashCode()
- {
- if ( get() != null )
- {
- return Integer.toHexString( System.identityHashCode( get() ) );
- }
- return null;
- }
-
- }
+ if (rk != null) {
+ idx = displayGroup.displayedObjects().indexOfIdenticalObject(rk);
+ if (idx != NSArray.NotFound) {
+ displayGroup.deleteObjectAtIndex(idx);
+ }
+ }
+ }
+ displayGroup.updateDisplayedObjects();
+ }
+ }
+
+ // interface ActionListener
+
+ public void actionPerformed(ActionEvent evt) {
+ Runtime runtime = Runtime.getRuntime();
+ runtime.gc();
+ processQueue();
+
+ long totalMemory = runtime.totalMemory() / 1024;
+ long freeMemory = runtime.freeMemory() / 1024;
+ memoryLabel.setText(Long.toString(totalMemory - freeMemory) + "K / " + Long.toString(totalMemory) + "K");
+ }
+
+ // interface MouseListener
+
+ /**
+ * Double click to launch object inspector.
+ */
+
+ public void mouseClicked(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.getClickCount() > 1) {
+ int row = table.rowAtPoint(e.getPoint());
+ int col = table.columnAtPoint(e.getPoint());
+ col = table.convertColumnIndexToModel(col);
+
+ if (row == -1)
+ return;
+
+ if (col == 0) // time
+ {
+ } else {
+ }
+ }
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ }
+
+ public void mousePressed(MouseEvent e) {
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ public void mouseExited(MouseEvent e) {
+ }
+
+ public class ExtendedWeakReference extends WeakReference {
+ public ExtendedWeakReference(Object referent, ReferenceQueue q) {
+ super(referent, q);
+ }
+
+ public String toString() {
+ if (get() != null) {
+ return get().toString();
+ }
+ return null;
+ }
+
+ public String identityHashCode() {
+ if (get() != null) {
+ return Integer.toHexString(System.identityHashCode(get()));
+ }
+ return null;
+ }
+
+ }
}
-
+
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.5 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.4 2002/03/22 22:39:59 mpowers
- * Now shows the window even if previously hidden.
+ * Revision 1.4 2002/03/22 22:39:59 mpowers Now shows the window even if
+ * previously hidden.
*
- * Revision 1.3 2001/10/02 14:22:39 mpowers
- * Now shows used and heap memory usage.
+ * Revision 1.3 2001/10/02 14:22:39 mpowers Now shows used and heap memory
+ * usage.
*
- * Revision 1.2 2001/07/10 16:39:32 mpowers
- * Removed printlns.
+ * Revision 1.2 2001/07/10 16:39:32 mpowers Removed printlns.
*
- * Revision 1.1 2001/07/10 16:32:50 mpowers
- * Adding the reference inspector.
+ * Revision 1.1 2001/07/10 16:32:50 mpowers Adding the reference inspector.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/SliderAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/SliderAssociation.java
index b836dcc..5a83240 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/SliderAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/SliderAssociation.java
@@ -30,390 +30,309 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* SliderAssociation binds a JSlider component to
-* a display group. Bindings are:
-* <ul>
-* <li>value: a property convertable to/from a string</li>
-* <li>enabled: a boolean property that determines whether
-* the user can select the text in the field</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class SliderAssociation extends EOAssociation
- implements ChangeListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect, VisibleAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "value"
- } );
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public SliderAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof JSlider );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * attempts to add this class as an ActionListener
- * and as a FocusListener to the specified object.
- */
- public void establishConnection ()
- {
- component().addChangeListener( this );
- super.establishConnection();
-
+ * SliderAssociation binds a JSlider component to a display group. Bindings are:
+ * <ul>
+ * <li>value: a property convertable to/from a string</li>
+ * <li>enabled: a boolean property that determines whether the user can select
+ * the text in the field</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class SliderAssociation extends EOAssociation implements ChangeListener {
+ static final NSArray aspects = new NSArray(new Object[] { ValueAspect, EnabledAspect, VisibleAspect });
+ static final NSArray aspectSignatures = new NSArray(
+ new Object[] { AttributeToOneAspectSignature, AttributeToOneAspectSignature, });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "value" });
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public SliderAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof JSlider);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation attempts to add this class as an ActionListener and as a
+ * FocusListener to the specified object.
+ */
+ public void establishConnection() {
+ component().addChangeListener(this);
+ super.establishConnection();
+
// forces update from bindings
subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- component().removeChangeListener( this );
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ component().removeChangeListener(this);
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
JSlider component = component();
EODisplayGroup displayGroup;
String key;
Object value;
-
+
// value aspect
- displayGroup = displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- key = displayGroupKeyForAspect( ValueAspect );
- component.setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
-
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- } else {
-
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking size of displayGroup
+ displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ key = displayGroupKeyForAspect(ValueAspect);
+ component.setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key));
+
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else {
+
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking size of displayGroup
// convert value to int
- value = ValueConverter.convertObjectToClass( value, Integer.class );
+ value = ValueConverter.convertObjectToClass(value, Integer.class);
int intValue;
- if ( value == null )
- {
+ if (value == null) {
intValue = 0;
+ } else {
+ intValue = ((Integer) value).intValue();
}
- else
- {
- intValue = ((Integer)value).intValue();
- }
-
- if ( component.getValue() != intValue )
- {
- component().removeChangeListener( this );
- component.setValue( intValue );
- component().addChangeListener( this );
+
+ if (component.getValue() != intValue) {
+ component().removeChangeListener(this);
+ component.setValue(intValue);
+ component().addChangeListener(this);
}
}
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- key = displayGroupKeyForAspect( EnabledAspect );
- if ( ( displayGroup != null ) || ( key != null ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ key = displayGroupKeyForAspect(EnabledAspect);
+ if ((displayGroup != null) || (key != null)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
- value = key;
+ value = key;
+ }
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (converted.booleanValue() != component.isEnabled()) {
+ component.setEnabled(converted.booleanValue());
}
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( converted.booleanValue() != component.isEnabled() )
- {
- component.setEnabled( converted.booleanValue() );
- }
}
// visible aspect
- displayGroup = displayGroupForAspect( VisibleAspect );
- key = displayGroupKeyForAspect( VisibleAspect );
- if ( ( displayGroup != null ) || ( key != null ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(VisibleAspect);
+ key = displayGroupKeyForAspect(VisibleAspect);
+ if ((displayGroup != null) || (key != null)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
- value = key;
+ value = key;
}
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() != component.isVisible() )
- {
- component.setVisible( converted.booleanValue() );
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue() != component.isVisible()) {
+ component.setVisible(converted.booleanValue());
}
- }
+ }
}
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
return writeValueToDisplayGroup();
- }
-
+ }
+
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- EODisplayGroup displayGroup =
- displayGroupForAspect( ValueAspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( ValueAspect );
- Object value = new Integer( component().getValue() );
-
- boolean returnValue = true;
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- returnValue = false;
- }
- }
- return returnValue;
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ EODisplayGroup displayGroup = displayGroupForAspect(ValueAspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(ValueAspect);
+ Object value = new Integer(component().getValue());
+
+ boolean returnValue = true;
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (!displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
}
return false;
}
- // interface ChangeListener
-
+ // interface ChangeListener
+
/**
- * Updates object on change.
- */
- public void stateChanged(ChangeEvent e)
- {
+ * Updates object on change.
+ */
+ public void stateChanged(ChangeEvent e) {
writeValueToDisplayGroup();
}
-
- private JSlider component()
- {
- return (JSlider) object();
+
+ private JSlider component() {
+ return (JSlider) object();
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.8 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.7 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2002/10/11 20:12:58 mpowers
- * Updated aspect signature.
+ * Revision 1.6 2002/10/11 20:12:58 mpowers Updated aspect signature.
*
- * Revision 1.5 2002/10/11 20:08:14 mpowers
- * Added visible aspect to slider association.
+ * Revision 1.5 2002/10/11 20:08:14 mpowers Added visible aspect to slider
+ * association.
*
- * Revision 1.4 2001/11/01 15:54:37 mpowers
- * Minor update to aspect signature.
+ * Revision 1.4 2001/11/01 15:54:37 mpowers Minor update to aspect signature.
*
- * Revision 1.3 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.3 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.2 2001/02/16 15:03:34 mpowers
- * Fixed: slider sets value in display group after selection changed.
+ * Revision 1.2 2001/02/16 15:03:34 mpowers Fixed: slider sets value in display
+ * group after selection changed.
*
- * Revision 1.1.1.1 2000/12/21 15:48:55 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:55 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java
index bc02f7d..edba674 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java
@@ -52,754 +52,619 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TableAssociation binds one or more TableColumnAssociations
-* to a display group. You should not instantiate this class
-* directly; use TableColumnAssociation.setTable() instead.
-* Note that TableAssociation inserts itself as the controlled
-* JTable's TableModel.
-*
-* Bindings are:
-* <ul>
-* <li>source: a property convertable to a string for
-* display in the cells of the table column</li>
-* <li>enabled: a property convertable to a string for
-* display in the cells of the table column.
-* Note that you can bind this aspect to a key equal to
-* "true" or "false" and leave the display group null.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TableAssociation extends EOAssociation
- implements ActionListener, ListSelectionListener, FocusListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- SourceAspect, EnabledAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "tableModel", "tableHeader"
- } );
-
- // key command to copy contents to clipboard
- static public final String COPY = "COPY";
+ * TableAssociation binds one or more TableColumnAssociations to a display
+ * group. You should not instantiate this class directly; use
+ * TableColumnAssociation.setTable() instead. Note that TableAssociation inserts
+ * itself as the controlled JTable's TableModel.
+ *
+ * Bindings are:
+ * <ul>
+ * <li>source: a property convertable to a string for display in the cells of
+ * the table column</li>
+ * <li>enabled: a property convertable to a string for display in the cells of
+ * the table column. Note that you can bind this aspect to a key equal to "true"
+ * or "false" and leave the display group null.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TableAssociation extends EOAssociation implements ActionListener, ListSelectionListener, FocusListener {
+ static final NSArray aspects = new NSArray(new Object[] { SourceAspect, EnabledAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "tableModel", "tableHeader" });
+
+ // key command to copy contents to clipboard
+ static public final String COPY = "COPY";
EODisplayGroup source;
- EODisplayGroup sortTarget; // used by TreeColumnAssociation
+ EODisplayGroup sortTarget; // used by TreeColumnAssociation
NSMutableArray columns;
- JTableHeader tableHeader;
-
- boolean pleaseIgnore;
- boolean selectionPaintedImmediately;
- boolean selectionTracking;
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Throws an exception if the object is not
- * a TableColumn. setTable() must be called before
- * establishing the connection.
- */
- public TableAssociation ( Object anObject )
- {
- super( anObject );
+ JTableHeader tableHeader;
+
+ boolean pleaseIgnore;
+ boolean selectionPaintedImmediately;
+ boolean selectionTracking;
+
+ /**
+ * Constructor specifying the object to be controlled by this association.
+ * Throws an exception if the object is not a TableColumn. setTable() must be
+ * called before establishing the connection.
+ */
+ public TableAssociation(Object anObject) {
+ super(anObject);
source = null;
columns = new NSMutableArray();
- JTable aTable = ((JTable)anObject);
- aTable.addFocusListener( this );
- aTable.setModel(
- new TableAssociationModel( this ) );
- // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
-
- // why did sun make this harder to use?
- //aTable.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put(
- // KeyStroke.getKeyStroke( KeyEvent.VK_C, java.awt.Event.CTRL_MASK ), COPY);
- //aTable.getActionMap().put(COPY, this);
-
- aTable.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
- aTable.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_X,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
- tableHeader = new SortedTableHeader();
- tableHeader.setColumnModel( aTable.getColumnModel() );
- aTable.setTableHeader( tableHeader );
- tableHeader.addMouseListener( new TableHeaderListener() );
- pleaseIgnore = false;
- selectionPaintedImmediately = false;
- selectionTracking = false;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof JTable );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( SourceAspect.equals( anAspect ) )
- {
+ JTable aTable = ((JTable) anObject);
+ aTable.addFocusListener(this);
+ aTable.setModel(new TableAssociationModel(this));
+ // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
+
+ // why did sun make this harder to use?
+ // aTable.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put(
+ // KeyStroke.getKeyStroke( KeyEvent.VK_C, java.awt.Event.CTRL_MASK ), COPY);
+ // aTable.getActionMap().put(COPY, this);
+
+ aTable.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ aTable.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ tableHeader = new SortedTableHeader();
+ tableHeader.setColumnModel(aTable.getColumnModel());
+ aTable.setTableHeader(tableHeader);
+ tableHeader.addMouseListener(new TableHeaderListener());
+ pleaseIgnore = false;
+ selectionPaintedImmediately = false;
+ selectionTracking = false;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof JTable);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (SourceAspect.equals(anAspect)) {
source = aDisplayGroup;
}
- super.bindAspect( anAspect, aDisplayGroup, aKey );
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
}
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- if ( source == null )
- {
- throw new WotonomyException( "No display group: " +
- "please ensure that the TableColumnAssociation " +
- "has a display group bound to the ValueAspect" );
- }
- super.establishConnection();
- selectFromDisplayGroup();
- addAsListener();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- removeAsListener();
- super.breakConnection();
- }
-
- protected void addAsListener()
- {
- component().getSelectionModel()
- .addListSelectionListener( this );
- }
-
- protected void removeAsListener()
- {
- component().getSelectionModel()
- .removeListSelectionListener( this );
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
- // stop any cell editing
- CellEditor editor = component().getCellEditor();
- if ( editor != null )
- {
- return editor.stopCellEditing();
- }
- return true;
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
- if ( source != null )
- {
- if ( source.contentsChanged() )
- {
- removeAsListener();
- ((TableAssociationModel)component().getModel()).
- fireTableDataChanged();
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ if (source == null) {
+ throw new WotonomyException("No display group: " + "please ensure that the TableColumnAssociation "
+ + "has a display group bound to the ValueAspect");
+ }
+ super.establishConnection();
+ selectFromDisplayGroup();
+ addAsListener();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ removeAsListener();
+ super.breakConnection();
+ }
+
+ protected void addAsListener() {
+ component().getSelectionModel().addListSelectionListener(this);
+ }
+
+ protected void removeAsListener() {
+ component().getSelectionModel().removeListSelectionListener(this);
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ // stop any cell editing
+ CellEditor editor = component().getCellEditor();
+ if (editor != null) {
+ return editor.stopCellEditing();
+ }
+ return true;
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
+ if (source != null) {
+ if (source.contentsChanged()) {
+ removeAsListener();
+ ((TableAssociationModel) component().getModel()).fireTableDataChanged();
selectFromDisplayGroup();
- addAsListener();
-
- // if we caused this change, do nothing
- if ( pleaseIgnore )
- {
- pleaseIgnore = false;
- }
- else // otherwise, update the sort indicator
- {
- tableHeader.repaint();
-
- // cancel any cell editing
- CellEditor editor = component().getCellEditor();
- if ( editor != null )
- {
- editor.cancelCellEditing();
- }
- }
- }
- else
- if ( source.selectionChanged() )
- {
- removeAsListener();
+ addAsListener();
+
+ // if we caused this change, do nothing
+ if (pleaseIgnore) {
+ pleaseIgnore = false;
+ } else // otherwise, update the sort indicator
+ {
+ tableHeader.repaint();
+
+ // cancel any cell editing
+ CellEditor editor = component().getCellEditor();
+ if (editor != null) {
+ editor.cancelCellEditing();
+ }
+ }
+ } else if (source.selectionChanged()) {
+ removeAsListener();
selectFromDisplayGroup();
- addAsListener();
+ addAsListener();
}
}
- }
+ }
- private void selectFromDisplayGroup()
- {
+ private void selectFromDisplayGroup() {
JTable component = component();
int index;
component.getSelectionModel().clearSelection();
- Enumeration e =
- source.selectionIndexes().objectEnumerator();
-
- while ( e.hasMoreElements() )
- { // add selections one-by-one to support non-contiguous
- index = ((Number)e.nextElement()).intValue();
- component.getSelectionModel().addSelectionInterval(
- index, index ); // adds one row
+ Enumeration e = source.selectionIndexes().objectEnumerator();
+
+ while (e.hasMoreElements()) { // add selections one-by-one to support non-contiguous
+ index = ((Number) e.nextElement()).intValue();
+ component.getSelectionModel().addSelectionInterval(index, index); // adds one row
}
}
// interface ListSelectionListener
- public void valueChanged(ListSelectionEvent e)
- {
- if ( source != null )
- {
- if ( selectionTracking || !e.getValueIsAdjusting() )
- {
- int[] selectedIndices = component().getSelectedRows();
- final NSMutableArray indexList = new NSMutableArray();
- for ( int i = 0; i < selectedIndices.length; i++ )
- {
- indexList.addObject( new Integer( selectedIndices[i] ) );
- }
-
- // invoke later so the component is repainted before
- // any potentially lengthy second-order effects happen:
- // this improves user-perceived responsiveness of big apps
- Runnable select = new Runnable()
- {
- public void run()
- {
- pleaseIgnore = true;
- source.setSelectionIndexes( indexList );
- }
- };
- if ( selectionPaintedImmediately )
- {
- EventQueue.invokeLater( select );
- }
- else
- {
- select.run();
- }
- }
- }
- }
-
- /**
- * Determines whether the selection should be painted
- * immediately after the user clicks and therefore
- * before the children display group is updated.
- * When the children group is bound to many associations
- * or is bound to a master-detail association, updating
- * the display group can take a perceptibly long time.
- * This property defaults to false.
- * @see #setSelectionPaintedImmediately
- */
- public boolean isSelectionPaintedImmediately()
- {
- return selectionPaintedImmediately;
- }
-
- /**
- * Sets whether the selection should be painted immediately.
- * Setting this property to true will let the table paint
- * first before the display group is updated.
- */
- public void setSelectionPaintedImmediately( boolean isImmediate )
- {
- selectionPaintedImmediately = isImmediate;
- }
-
- /**
- * Determines whether the selection is actively tracking
- * the selection as the user moves the mouse.
- * If true, selection will not be updated while the
- * list selection event returns true for isValueAdjusting().
- * This property defaults to false.
- * @see #setSelectionTracking
- */
- public boolean isSelectionTracking()
- {
- return selectionTracking;
- }
-
- /**
- * Sets whether the selection is actively tracking
- * the selection as the user moves the mouse.
- * Setting this property to true will update the display
- * group with each change to the selection.
- * This means that any tree selection listers will
- * also be notified before the display group is updated
- * and will have to invokeLater if they want to see the
- * updated display group.
- */
- public void setSelectionTracking( boolean isTracking )
- {
- selectionTracking = isTracking;
- }
-
- // convenience
- private JTable component()
- {
- return (JTable) object();
- }
+ public void valueChanged(ListSelectionEvent e) {
+ if (source != null) {
+ if (selectionTracking || !e.getValueIsAdjusting()) {
+ int[] selectedIndices = component().getSelectedRows();
+ final NSMutableArray indexList = new NSMutableArray();
+ for (int i = 0; i < selectedIndices.length; i++) {
+ indexList.addObject(new Integer(selectedIndices[i]));
+ }
+
+ // invoke later so the component is repainted before
+ // any potentially lengthy second-order effects happen:
+ // this improves user-perceived responsiveness of big apps
+ Runnable select = new Runnable() {
+ public void run() {
+ pleaseIgnore = true;
+ source.setSelectionIndexes(indexList);
+ }
+ };
+ if (selectionPaintedImmediately) {
+ EventQueue.invokeLater(select);
+ } else {
+ select.run();
+ }
+ }
+ }
+ }
/**
- * Copies the contents of the table to the clipboard as a tab-delimited string.
- */
- public void copyToClipboard()
- {
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Clipboard clipboard = toolkit.getSystemClipboard();
- StringSelection selection =
- new StringSelection( getTabDelimitedString() );
- clipboard.setContents( selection, selection );
- }
+ * Determines whether the selection should be painted immediately after the user
+ * clicks and therefore before the children display group is updated. When the
+ * children group is bound to many associations or is bound to a master-detail
+ * association, updating the display group can take a perceptibly long time.
+ * This property defaults to false.
+ *
+ * @see #setSelectionPaintedImmediately
+ */
+ public boolean isSelectionPaintedImmediately() {
+ return selectionPaintedImmediately;
+ }
/**
- * Converts the contents of the table to a tab-delimited string.
- * @return A String containing the text contents of the table.
- */
- public String getTabDelimitedString()
- {
- StringBuffer result = new StringBuffer(64);
-
- TableModel model = component().getModel();
- int cols = model.getColumnCount();
- int rows = model.getRowCount();
-
- Object o = null;
- for ( int y = 0; y < rows; y++ )
- {
- for ( int x = 0; x < cols; x++ )
- {
- o = model.getValueAt( y, x );
- if ( o == null ) o = "";
- result.append( o );
- result.append( '\t' );
- }
- result.append( '\n' );
- }
-
- return result.toString();
- }
-
- // interface ActionEventListener
-
- public void actionPerformed(ActionEvent evt)
- {
- String cmd = evt.getActionCommand();
-
- if ( COPY.equals( cmd ) )
- {
- copyToClipboard();
- return;
- }
- }
-
- /**
- * Used to render the little triangle over the sorted column(s).
- */
- class SortedTableHeader extends JTableHeader
- {
- public void paint(Graphics g)
- {
- super.paint( g );
- Rectangle r;
- TableColumnAssociation association;
- int size = columns.size();
- NSArray orderings;
- if ( sortTarget != null )
- {
- orderings = sortTarget.sortOrderings();
- }
- else
- {
- orderings = source.sortOrderings();
- }
- for ( int i = 0; i < size; i++ )
- {
- r = getHeaderRect( component().convertColumnIndexToView( i ) );
- association = (TableColumnAssociation) columns.objectAtIndex( i );
- association.drawSortIndicator( r, g, orderings );
- }
- }
- }
-
- /**
- * Used to listen for clicks on the table header.
- */
- class TableHeaderListener extends MouseAdapter
- {
- public void mouseClicked( MouseEvent evt )
- {
- EODisplayGroup displayGroup = sortTarget;
- if ( displayGroup == null ) displayGroup = source;
-
- if ( evt.getClickCount() > 0 )
- {
- int columnClicked = tableHeader.columnAtPoint( evt.getPoint() );
- if ( columnClicked != -1 )
- {
- columnClicked = component().convertColumnIndexToModel( columnClicked );
- TableColumnAssociation association = (TableColumnAssociation)
- columns.objectAtIndex( columnClicked );
- if ( association.isSortable() )
- {
- NSMutableArray newOrder =
- new NSMutableArray( displayGroup.sortOrderings() );
-
- // click once = asc, twice = desc, thrice = clear
- EOSortOrdering sortOrdering;
- int index = association.getIndexOfMatchingOrdering( newOrder );
- if ( index == -1 ) sortOrdering = null;
- else if ( index == 1 ) sortOrdering = association.getSortOrdering( false );
- else sortOrdering = association.getSortOrdering( true );
-
- pleaseIgnore = true;
- tableHeader.repaint();
-
- // stop any cell editing
- CellEditor editor = component().getCellEditor();
- if ( editor != null )
- {
- editor.stopCellEditing();
- }
-
- // remove existing key
- if ( index != 0 )
- {
- newOrder.removeObjectAtIndex( Math.abs( index ) - 1 );
- }
-
- // put new key at front of list
- if ( sortOrdering != null )
- {
- newOrder.insertObjectAtIndex( sortOrdering, 0 );
- }
-
- displayGroup.setSortOrderings( newOrder );
- displayGroup.updateDisplayedObjects();
- }
- }
- }
- }
- }
+ * Sets whether the selection should be painted immediately. Setting this
+ * property to true will let the table paint first before the display group is
+ * updated.
+ */
+ public void setSelectionPaintedImmediately(boolean isImmediate) {
+ selectionPaintedImmediately = isImmediate;
+ }
/**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
+ * Determines whether the selection is actively tracking the selection as the
+ * user moves the mouse. If true, selection will not be updated while the list
+ * selection event returns true for isValueAdjusting(). This property defaults
+ * to false.
+ *
+ * @see #setSelectionTracking
+ */
+ public boolean isSelectionTracking() {
+ return selectionTracking;
+ }
+
+ /**
+ * Sets whether the selection is actively tracking the selection as the user
+ * moves the mouse. Setting this property to true will update the display group
+ * with each change to the selection. This means that any tree selection listers
+ * will also be notified before the display group is updated and will have to
+ * invokeLater if they want to see the updated display group.
+ */
+ public void setSelectionTracking(boolean isTracking) {
+ selectionTracking = isTracking;
+ }
+
+ // convenience
+ private JTable component() {
+ return (JTable) object();
+ }
+
+ /**
+ * Copies the contents of the table to the clipboard as a tab-delimited string.
+ */
+ public void copyToClipboard() {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Clipboard clipboard = toolkit.getSystemClipboard();
+ StringSelection selection = new StringSelection(getTabDelimitedString());
+ clipboard.setContents(selection, selection);
+ }
+
+ /**
+ * Converts the contents of the table to a tab-delimited string.
+ *
+ * @return A String containing the text contents of the table.
+ */
+ public String getTabDelimitedString() {
+ StringBuffer result = new StringBuffer(64);
+
+ TableModel model = component().getModel();
+ int cols = model.getColumnCount();
+ int rows = model.getRowCount();
+
+ Object o = null;
+ for (int y = 0; y < rows; y++) {
+ for (int x = 0; x < cols; x++) {
+ o = model.getValueAt(y, x);
+ if (o == null)
+ o = "";
+ result.append(o);
+ result.append('\t');
+ }
+ result.append('\n');
+ }
+
+ return result.toString();
+ }
+
+ // interface ActionEventListener
+
+ public void actionPerformed(ActionEvent evt) {
+ String cmd = evt.getActionCommand();
+
+ if (COPY.equals(cmd)) {
+ copyToClipboard();
+ return;
+ }
+ }
+
+ /**
+ * Used to render the little triangle over the sorted column(s).
+ */
+ class SortedTableHeader extends JTableHeader {
+ public void paint(Graphics g) {
+ super.paint(g);
+ Rectangle r;
+ TableColumnAssociation association;
+ int size = columns.size();
+ NSArray orderings;
+ if (sortTarget != null) {
+ orderings = sortTarget.sortOrderings();
+ } else {
+ orderings = source.sortOrderings();
+ }
+ for (int i = 0; i < size; i++) {
+ r = getHeaderRect(component().convertColumnIndexToView(i));
+ association = (TableColumnAssociation) columns.objectAtIndex(i);
+ association.drawSortIndicator(r, g, orderings);
+ }
+ }
+ }
+
+ /**
+ * Used to listen for clicks on the table header.
+ */
+ class TableHeaderListener extends MouseAdapter {
+ public void mouseClicked(MouseEvent evt) {
+ EODisplayGroup displayGroup = sortTarget;
+ if (displayGroup == null)
+ displayGroup = source;
+
+ if (evt.getClickCount() > 0) {
+ int columnClicked = tableHeader.columnAtPoint(evt.getPoint());
+ if (columnClicked != -1) {
+ columnClicked = component().convertColumnIndexToModel(columnClicked);
+ TableColumnAssociation association = (TableColumnAssociation) columns.objectAtIndex(columnClicked);
+ if (association.isSortable()) {
+ NSMutableArray newOrder = new NSMutableArray(displayGroup.sortOrderings());
+
+ // click once = asc, twice = desc, thrice = clear
+ EOSortOrdering sortOrdering;
+ int index = association.getIndexOfMatchingOrdering(newOrder);
+ if (index == -1)
+ sortOrdering = null;
+ else if (index == 1)
+ sortOrdering = association.getSortOrdering(false);
+ else
+ sortOrdering = association.getSortOrdering(true);
+
+ pleaseIgnore = true;
+ tableHeader.repaint();
+
+ // stop any cell editing
+ CellEditor editor = component().getCellEditor();
+ if (editor != null) {
+ editor.stopCellEditing();
+ }
+
+ // remove existing key
+ if (index != 0) {
+ newOrder.removeObjectAtIndex(Math.abs(index) - 1);
+ }
+
+ // put new key at front of list
+ if (sortOrdering != null) {
+ newOrder.insertObjectAtIndex(sortOrdering, 0);
+ }
+
+ displayGroup.setSortOrderings(newOrder);
+ displayGroup.updateDisplayedObjects();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
Object o;
EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
}
}
- }
+ }
/**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( ! component().isEditing() )
- {
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
- }
- }
- }
- }
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (!component().isEditing()) {
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
+ }
+ }
+ }
+ }
/**
- * Used as the model for the controlled table.
- * Package access so TableColumnAssociation can recognize
- * it and use the addColumnAssociation() method.
- * Extends AbstractTableModel just so we get event
- * broadcasting for free.
- */
- static class TableAssociationModel extends AbstractTableModel
- {
+ * Used as the model for the controlled table. Package access so
+ * TableColumnAssociation can recognize it and use the addColumnAssociation()
+ * method. Extends AbstractTableModel just so we get event broadcasting for
+ * free.
+ */
+ static class TableAssociationModel extends AbstractTableModel {
private TableAssociation parent;
- private TableAssociationModel( TableAssociation aParent )
- {
+ private TableAssociationModel(TableAssociation aParent) {
parent = aParent;
}
-
- public TableAssociation getAssociation()
- {
- return parent;
- }
+
+ public TableAssociation getAssociation() {
+ return parent;
+ }
/**
- * Adds the column to the list of ColumnAssociations,
- * and adds the corresponding column to the table
- * at the next available index, setting the value of
- * the column's model index accordingly.
- * Establishes connection if no columns are currently
- * associated.
- */
- public void addColumnAssociation(
- TableColumnAssociation aColumnAssociation )
- {
- // establish connection if necessary
- if ( parent.columns.size() == 0 )
- {
- parent.establishConnection();
- }
-
+ * Adds the column to the list of ColumnAssociations, and adds the corresponding
+ * column to the table at the next available index, setting the value of the
+ * column's model index accordingly. Establishes connection if no columns are
+ * currently associated.
+ */
+ public void addColumnAssociation(TableColumnAssociation aColumnAssociation) {
+ // establish connection if necessary
+ if (parent.columns.size() == 0) {
+ parent.establishConnection();
+ }
+
int newIndex = parent.columns.count();
- parent.columns.add( aColumnAssociation );
+ parent.columns.add(aColumnAssociation);
// add column to table
TableColumn column = (TableColumn) aColumnAssociation.object();
- column.setModelIndex( newIndex );
- parent.component().addColumn( column );
-
+ column.setModelIndex(newIndex);
+ parent.component().addColumn(column);
+
}
/**
- * Removes the column from the list of ColumnAssociations,
- * and removes the corresponding column from the table.
- * Breaks connection if no more columns are associated.
- */
- public void removeColumnAssociation(
- TableColumnAssociation aColumnAssociation )
- {
- int index = parent.columns.indexOfIdenticalObject( aColumnAssociation );
- if ( index == NSArray.NotFound ) return;
-
- parent.columns.removeObjectAtIndex( index );
+ * Removes the column from the list of ColumnAssociations, and removes the
+ * corresponding column from the table. Breaks connection if no more columns are
+ * associated.
+ */
+ public void removeColumnAssociation(TableColumnAssociation aColumnAssociation) {
+ int index = parent.columns.indexOfIdenticalObject(aColumnAssociation);
+ if (index == NSArray.NotFound)
+ return;
+
+ parent.columns.removeObjectAtIndex(index);
// remove column from table
TableColumn column = (TableColumn) aColumnAssociation.object();
- parent.component().removeColumn( column );
-
- // break connection if necessary
- if ( parent.columns.size() == 0 )
- {
- parent.breakConnection();
- }
+ parent.component().removeColumn(column);
+
+ // break connection if necessary
+ if (parent.columns.size() == 0) {
+ parent.breakConnection();
+ }
}
- public int getRowCount()
- {
- if ( parent.source == null ) return 0;
+ public int getRowCount() {
+ if (parent.source == null)
+ return 0;
return parent.source.displayedObjects().count();
}
- public int getColumnCount()
- {
+ public int getColumnCount() {
return parent.columns.count();
}
/**
- * Attempts to retrieve the header value from the specified column,
- * or returns " " if the value is null.
- */
- public String getColumnName(int columnIndex)
- {
- TableColumnAssociation association = (TableColumnAssociation)
- parent.columns.objectAtIndex( columnIndex );
- Object value = ((TableColumn)association.object()).getHeaderValue();
- if ( value != null ) return value.toString();
- return " ";
+ * Attempts to retrieve the header value from the specified column, or returns "
+ * " if the value is null.
+ */
+ public String getColumnName(int columnIndex) {
+ TableColumnAssociation association = (TableColumnAssociation) parent.columns.objectAtIndex(columnIndex);
+ Object value = ((TableColumn) association.object()).getHeaderValue();
+ if (value != null)
+ return value.toString();
+ return " ";
}
/**
- * Returns the class of the first item in the
- * display group bound to the column.
- */
- public Class getColumnClass(int columnIndex)
- {
- Object value;
- int count = getRowCount();
- for( int i = 0; i < count; i++ )
- { //First row in column is null find one that is not.
- value = ((TableColumnAssociation)parent.columns.
- objectAtIndex( columnIndex ) ).valueAtIndex( i );
- if ( value != null ) return value.getClass();
- }
- return Object.class;
+ * Returns the class of the first item in the display group bound to the column.
+ */
+ public Class getColumnClass(int columnIndex) {
+ Object value;
+ int count = getRowCount();
+ for (int i = 0; i < count; i++) { // First row in column is null find one that is not.
+ value = ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).valueAtIndex(i);
+ if (value != null)
+ return value.getClass();
+ }
+ return Object.class;
}
- /**
- * Calls the column association's isEditableAtRow method.
- */
- public boolean isCellEditable(int rowIndex,
- int columnIndex)
- {
- return
- ((TableColumnAssociation)parent.columns.objectAtIndex(
- columnIndex ) ).isEditableAtRow( rowIndex );
+ /**
+ * Calls the column association's isEditableAtRow method.
+ */
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).isEditableAtRow(rowIndex);
}
- /**
- * Calls the column association's valueAtIndex method.
- */
- public Object getValueAt(int rowIndex,
- int columnIndex)
- {
- return
- ((TableColumnAssociation)parent.columns.objectAtIndex(
- columnIndex ) ).valueAtIndex( rowIndex );
+ /**
+ * Calls the column association's valueAtIndex method.
+ */
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ return ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).valueAtIndex(rowIndex);
}
- /**
- * Calls the column association's setValueAtIndex method.
- */
- public void setValueAt(Object aValue,
- int rowIndex,
- int columnIndex)
- {
- Object existingValue = getValueAt( rowIndex, columnIndex );
-
- // don't update display group if value is the same as before
- if ( aValue == existingValue ) return; // handles null case
- if ( existingValue != null ) // both are not null
- {
- Object newValue = aValue;
-
- // if different types
- if ( newValue.getClass() != existingValue.getClass() )
- {
- // convert to string since most editors do anyway
- newValue = newValue.toString();
- existingValue = existingValue.toString();
- }
- if ( newValue.equals( existingValue ) )
- {
- // same value - do nothing
- return;
- }
- }
-
- ((TableColumnAssociation)parent.columns.objectAtIndex(
- columnIndex ) ).setValueAtIndex( aValue, rowIndex );
+ /**
+ * Calls the column association's setValueAtIndex method.
+ */
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ Object existingValue = getValueAt(rowIndex, columnIndex);
+
+ // don't update display group if value is the same as before
+ if (aValue == existingValue)
+ return; // handles null case
+ if (existingValue != null) // both are not null
+ {
+ Object newValue = aValue;
+
+ // if different types
+ if (newValue.getClass() != existingValue.getClass()) {
+ // convert to string since most editors do anyway
+ newValue = newValue.toString();
+ existingValue = existingValue.toString();
+ }
+ if (newValue.equals(existingValue)) {
+ // same value - do nothing
+ return;
+ }
+ }
+
+ ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).setValueAtIndex(aValue, rowIndex);
}
}
@@ -807,121 +672,106 @@ public class TableAssociation extends EOAssociation
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.31 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.31 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.30 2002/11/16 16:33:31 mpowers
- * Now using platform-specific accelerator key for shortcuts.
+ * Revision 1.30 2002/11/16 16:33:31 mpowers Now using platform-specific
+ * accelerator key for shortcuts.
*
- * Revision 1.29 2002/05/24 14:41:29 mpowers
- * Throwing an exception for clarity.
+ * Revision 1.29 2002/05/24 14:41:29 mpowers Throwing an exception for clarity.
*
- * Revision 1.28 2002/04/10 21:20:04 mpowers
- * Better handling for tree nodes when working with editing contexts.
- * Better handling for invalidation. No longer broadcasting events
- * when nodes have not been "registered" in the tree.
+ * Revision 1.28 2002/04/10 21:20:04 mpowers Better handling for tree nodes when
+ * working with editing contexts. Better handling for invalidation. No longer
+ * broadcasting events when nodes have not been "registered" in the tree.
*
- * Revision 1.27 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.27 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.25 2002/03/04 22:49:53 mpowers
- * Now working with TreeColumnAssociation to delegate sorting behavior.
+ * Revision 1.25 2002/03/04 22:49:53 mpowers Now working with
+ * TreeColumnAssociation to delegate sorting behavior.
*
- * Revision 1.23 2002/03/04 03:58:17 mpowers
- * Refined table header click behavior.
+ * Revision 1.23 2002/03/04 03:58:17 mpowers Refined table header click
+ * behavior.
*
- * Revision 1.22 2002/03/01 23:41:39 mpowers
- * Added facility to get table association from model.
+ * Revision 1.22 2002/03/01 23:41:39 mpowers Added facility to get table
+ * association from model.
*
- * Revision 1.21 2002/03/01 20:41:22 mpowers
- * Cleaned up unused code.
+ * Revision 1.21 2002/03/01 20:41:22 mpowers Cleaned up unused code.
*
- * Revision 1.20 2002/03/01 15:42:00 mpowers
- * Table column headers now always show their sort indicator.
- * A third table-column click clears the sort for that column.
+ * Revision 1.20 2002/03/01 15:42:00 mpowers Table column headers now always
+ * show their sort indicator. A third table-column click clears the sort for
+ * that column.
*
- * Revision 1.19 2002/02/28 23:01:39 mpowers
- * TableColumnAssociations add and remove themselves from the TableAssociation
- * when their connection is established and broken respectively.
- * TableAssociations now break connection if they have no column associations.
+ * Revision 1.19 2002/02/28 23:01:39 mpowers TableColumnAssociations add and
+ * remove themselves from the TableAssociation when their connection is
+ * established and broken respectively. TableAssociations now break connection
+ * if they have no column associations.
*
- * Revision 1.18 2002/02/28 22:45:27 mpowers
- * Now registers as editing association when table gets focus, so that
- * endEditing can appropriate commit any table cell editors.
+ * Revision 1.18 2002/02/28 22:45:27 mpowers Now registers as editing
+ * association when table gets focus, so that endEditing can appropriate commit
+ * any table cell editors.
*
- * Revision 1.17 2001/10/26 20:01:50 mpowers
- * We're again cancelling instead of stopping editing on subjectChanged.
- * I believe that the introduction of NSRunLoop has allowed us to return
- * to the correct behavior.
+ * Revision 1.17 2001/10/26 20:01:50 mpowers We're again cancelling instead of
+ * stopping editing on subjectChanged. I believe that the introduction of
+ * NSRunLoop has allowed us to return to the correct behavior.
*
- * Revision 1.16 2001/09/14 13:40:26 mpowers
- * User-initiated selection changes are now handled on the next event loop
- * so that the component repaints the new selection before any potentially
- * lengthy logic is triggered by the selection change.
+ * Revision 1.16 2001/09/14 13:40:26 mpowers User-initiated selection changes
+ * are now handled on the next event loop so that the component repaints the new
+ * selection before any potentially lengthy logic is triggered by the selection
+ * change.
*
- * Revision 1.15 2001/07/25 15:03:01 mpowers
- * getColumnName now checks for a column header value before defaulting " ".
+ * Revision 1.15 2001/07/25 15:03:01 mpowers getColumnName now checks for a
+ * column header value before defaulting " ".
*
- * Revision 1.14 2001/06/05 19:09:25 mpowers
- * Fixed broken build.
+ * Revision 1.14 2001/06/05 19:09:25 mpowers Fixed broken build.
*
- * Revision 1.13 2001/06/05 19:08:12 mpowers
- * Better determination of column class. Previously, if the first object
- * was null, Object.class was used. Now we get the first non-null object.
+ * Revision 1.13 2001/06/05 19:08:12 mpowers Better determination of column
+ * class. Previously, if the first object was null, Object.class was used. Now
+ * we get the first non-null object.
*
- * Revision 1.12 2001/05/02 17:39:01 mpowers
- * Now selects from display group after initial population.
+ * Revision 1.12 2001/05/02 17:39:01 mpowers Now selects from display group
+ * after initial population.
*
- * Revision 1.11 2001/03/29 23:05:22 mpowers
- * Fixes for editing table cells.
+ * Revision 1.11 2001/03/29 23:05:22 mpowers Fixes for editing table cells.
*
- * Revision 1.10 2001/03/09 22:09:22 mpowers
- * Now better handling jdk1.1 for rendering the column header.
+ * Revision 1.10 2001/03/09 22:09:22 mpowers Now better handling jdk1.1 for
+ * rendering the column header.
*
- * Revision 1.9 2001/02/27 02:10:38 mpowers
- * No longer updating values to the display group if the value
- * has not changed.
+ * Revision 1.9 2001/02/27 02:10:38 mpowers No longer updating values to the
+ * display group if the value has not changed.
*
- * Revision 1.8 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.7 2001/02/16 17:47:17 mpowers
- * Now cancelling any cell editing on subjectChanged().
+ * Revision 1.7 2001/02/16 17:47:17 mpowers Now cancelling any cell editing on
+ * subjectChanged().
*
- * Revision 1.6 2001/01/12 19:11:56 mpowers
- * Fixed table column click sorting.
+ * Revision 1.6 2001/01/12 19:11:56 mpowers Fixed table column click sorting.
*
- * Revision 1.5 2001/01/12 17:20:30 mpowers
- * Moved EOSortOrdering creation to ColumnAssociation.
+ * Revision 1.5 2001/01/12 17:20:30 mpowers Moved EOSortOrdering creation to
+ * ColumnAssociation.
*
- * Revision 1.4 2001/01/11 21:55:57 mpowers
- * Implemented sort indicator for table column headers.
+ * Revision 1.4 2001/01/11 21:55:57 mpowers Implemented sort indicator for table
+ * column headers.
*
- * Revision 1.3 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.3 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.2 2001/01/08 20:40:51 mpowers
- * JTables in 1.3 clear their selection when the data model changes,
- * which sends a list selection event. We now reset the selection again
- * after the data changes so we're compatible across 1.2 and 1.3.
+ * Revision 1.2 2001/01/08 20:40:51 mpowers JTables in 1.3 clear their selection
+ * when the data model changes, which sends a list selection event. We now reset
+ * the selection again after the data changes so we're compatible across 1.2 and
+ * 1.3.
*
- * Revision 1.1.1.1 2000/12/21 15:49:00 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:49:00 mpowers Contributing wotonomy.
*
- * Revision 1.7 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.7 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableColumnAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableColumnAssociation.java
index e1c32f3..f279926 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableColumnAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableColumnAssociation.java
@@ -38,671 +38,544 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
import net.wotonomy.ui.swing.TableAssociation.TableAssociationModel;
-
/**
-* TableColumnAssociation binds a column of a JTable
-* to a property of the elements of a display group.
-* Bindings are:
-* <ul>
-* <li>value: a property convertable to a string for
-* display in the cells of the table column</li>
-* <li>editable: a property convertable to a boolean
-* that determines the editability of the corresponding
-* cells in the column.</li>
-* </ul>
-
-* Because TableColumns do not have a handle to their
-* containing JTable, setTable() must be called before
-* calling establishConnection(). This will add the
-* controlled TableColumn to the specified JTable.
-*
-* Columns appear in the table in the order in which
-* setTable is called on the corresponding association.
-* The original table model index is ignored.
-*
-* Column names appear in the table based on the value
-* of TableColumn.getHeaderValue().
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TableColumnAssociation extends EOAssociation
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EditableAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "table"
- } );
-
- static Color[] sortIndicatorColorList;
-
+ * TableColumnAssociation binds a column of a JTable to a property of the
+ * elements of a display group. Bindings are:
+ * <ul>
+ * <li>value: a property convertable to a string for display in the cells of the
+ * table column</li>
+ * <li>editable: a property convertable to a boolean that determines the
+ * editability of the corresponding cells in the column.</li>
+ * </ul>
+ *
+ * Because TableColumns do not have a handle to their containing JTable,
+ * setTable() must be called before calling establishConnection(). This will add
+ * the controlled TableColumn to the specified JTable.
+ *
+ * Columns appear in the table in the order in which setTable is called on the
+ * corresponding association. The original table model index is ignored.
+ *
+ * Column names appear in the table based on the value of
+ * TableColumn.getHeaderValue().
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TableColumnAssociation extends EOAssociation {
+ static final NSArray aspects = new NSArray(new Object[] { ValueAspect, EditableAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "table" });
+
+ static Color[] sortIndicatorColorList;
+
EODisplayGroup valueDisplayGroup, editableDisplayGroup;
String valueKey, editableKey;
- boolean sortable;
- boolean sortCaseSensitive;
- JTable table;
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Throws an exception if the object is not
- * a TableColumn. setTable() must be called before
- * establishing the connection.
- */
- public TableColumnAssociation ( Object anObject )
- {
- super( anObject );
+ boolean sortable;
+ boolean sortCaseSensitive;
+ JTable table;
+
+ /**
+ * Constructor specifying the object to be controlled by this association.
+ * Throws an exception if the object is not a TableColumn. setTable() must be
+ * called before establishing the connection.
+ */
+ public TableColumnAssociation(Object anObject) {
+ super(anObject);
valueDisplayGroup = null;
valueKey = null;
editableDisplayGroup = null;
editableKey = null;
- sortable = true;
- sortCaseSensitive = true;
- table = null;
- }
-
+ sortable = true;
+ sortCaseSensitive = true;
+ table = null;
+ }
+
/**
- * Sets the table to be used for this column association.
- * If no TableAssociation exists for the specified table,
- * one will be created automatically. The controlled
- * table column will be added to the table. Note that
- * the table column's model index is ignored: table columns
- * appear in the table in the order in which setTable is
- * called on their corresponding associations.
- */
- public void setTable( JTable aTable )
- {
- table = aTable;
- if ( table == null ) return;
-
- // creates table association if not existing
- getTableAssociation();
+ * Sets the table to be used for this column association. If no TableAssociation
+ * exists for the specified table, one will be created automatically. The
+ * controlled table column will be added to the table. Note that the table
+ * column's model index is ignored: table columns appear in the table in the
+ * order in which setTable is called on their corresponding associations.
+ */
+ public void setTable(JTable aTable) {
+ table = aTable;
+ if (table == null)
+ return;
+
+ // creates table association if not existing
+ getTableAssociation();
}
-
- /**
- * Returns the table association for this table column,
- * or null if no table has been set. This method will
- * create the association if none exists for the table.
- */
- public TableAssociation getTableAssociation()
- {
- if ( table == null ) return null;
-
- TableAssociation result;
- if ( ! ( table.getModel() instanceof TableAssociationModel ) )
- {
- result = new TableAssociation( table );
- result.bindAspect(
- SourceAspect, displayGroupForAspect( ValueAspect ), "" );
+
+ /**
+ * Returns the table association for this table column, or null if no table has
+ * been set. This method will create the association if none exists for the
+ * table.
+ */
+ public TableAssociation getTableAssociation() {
+ if (table == null)
+ return null;
+
+ TableAssociation result;
+ if (!(table.getModel() instanceof TableAssociationModel)) {
+ result = new TableAssociation(table);
+ result.bindAspect(SourceAspect, displayGroupForAspect(ValueAspect), "");
+ } else {
+ result = ((TableAssociationModel) table.getModel()).getAssociation();
}
- else
- {
- result = ((TableAssociationModel)table.getModel()).getAssociation();
- }
- return result;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof TableColumn );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( ValueAspect.equals( anAspect ) )
- {
- valueDisplayGroup = aDisplayGroup;
+ return result;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof TableColumn);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (ValueAspect.equals(anAspect)) {
+ valueDisplayGroup = aDisplayGroup;
valueKey = aKey;
}
- if ( EditableAspect.equals( anAspect ) )
- {
+ if (EditableAspect.equals(anAspect)) {
editableDisplayGroup = aDisplayGroup;
editableKey = aKey;
}
- super.bindAspect( anAspect, aDisplayGroup, aKey );
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
}
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- addAsListener();
-
- if ( table == null ) throw new WotonomyException(
- "A table must be specified by calling setTable()" );
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ addAsListener();
+
+ if (table == null)
+ throw new WotonomyException("A table must be specified by calling setTable()");
// add association to model
- TableAssociationModel model =
- (TableAssociationModel) table.getModel();
- model.addColumnAssociation( this );
-
- super.establishConnection();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- removeAsListener();
-
- if ( table == null ) throw new WotonomyException(
- "TableColumnAssociation's table may not be null" );
+ TableAssociationModel model = (TableAssociationModel) table.getModel();
+ model.addColumnAssociation(this);
+
+ super.establishConnection();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ removeAsListener();
+
+ if (table == null)
+ throw new WotonomyException("TableColumnAssociation's table may not be null");
// remove association from model
- TableAssociationModel model =
- (TableAssociationModel) table.getModel();
- model.removeColumnAssociation( this );
-
- super.breakConnection();
- }
-
- protected void addAsListener()
- {
- }
-
- protected void removeAsListener()
- {
- }
-
+ TableAssociationModel model = (TableAssociationModel) table.getModel();
+ model.removeColumnAssociation(this);
+
+ super.breakConnection();
+ }
+
+ protected void addAsListener() {
+ }
+
+ protected void removeAsListener() {
+ }
+
/**
- * Returns the value to be displayed at the specified index.
- * This method is called by the TableAssocation to populate
- * the table model.
- * This implementation simply retrieves the value from the
- * display group bound to the value aspect.
- */
- public Object valueAtIndex( int aRowIndex )
- {
- if ( valueDisplayGroup != null )
- {
- return valueDisplayGroup.valueForObjectAtIndex(
- aRowIndex, valueKey );
+ * Returns the value to be displayed at the specified index. This method is
+ * called by the TableAssocation to populate the table model. This
+ * implementation simply retrieves the value from the display group bound to the
+ * value aspect.
+ */
+ public Object valueAtIndex(int aRowIndex) {
+ if (valueDisplayGroup != null) {
+ return valueDisplayGroup.valueForObjectAtIndex(aRowIndex, valueKey);
}
return null;
}
-
+
/**
- * Sets a value for the specified index. This method is
- * called by the TableAssocation after a cell has been
- * edited.
- * This implementation simply sets the value in the
- * display group bound to the value aspect.
- */
- public void setValueAtIndex( Object aValue, int aRowIndex )
- {
- if ( valueDisplayGroup != null )
- {
- valueDisplayGroup.setValueForObjectAtIndex(
- aValue, aRowIndex, valueKey );
+ * Sets a value for the specified index. This method is called by the
+ * TableAssocation after a cell has been edited. This implementation simply sets
+ * the value in the display group bound to the value aspect.
+ */
+ public void setValueAtIndex(Object aValue, int aRowIndex) {
+ if (valueDisplayGroup != null) {
+ valueDisplayGroup.setValueForObjectAtIndex(aValue, aRowIndex, valueKey);
}
}
-
- /**
- * Returns whether this column should be sorted when the
- * user clicks on the column header. Defaults to true.
- */
- public boolean isSortable()
- {
- return sortable;
- }
-
- /**
- * Sets whether this column should be sorted when the
- * user clicks on the column header.
- */
- public void setSortable( boolean isSortable )
- {
- sortable = isSortable;
- }
-
- /**
- * Returns whether this column should be sorted
- * in a case sensitive manner. Defaults to true.
- */
- public boolean isSortCaseSensitive()
- {
- return sortCaseSensitive;
- }
-
- /**
- * Sets whether this column should be sorted when
- * in a case sensitive manner.
- * If false, the column contents should be string values.
- */
- public void setSortCaseSensitive( boolean isCaseSensitive )
- {
- sortCaseSensitive = isCaseSensitive;
- }
/**
- * Called by the TableAssociation to determine whether
- * the value at the specified row is editable.
- * This is determined by the binding of the Editable aspect,
- * looking at the value of the corresponding index in that
- * display group. Note: because the display group may
- * not have the same number if items, the selected index is
- * used if the editable display group is not the same as the
- * the value display group.
- */
- public boolean isEditableAtRow( int aRowIndex )
- {
- if ( editableKey == null ) return false;
+ * Returns whether this column should be sorted when the user clicks on the
+ * column header. Defaults to true.
+ */
+ public boolean isSortable() {
+ return sortable;
+ }
+
+ /**
+ * Sets whether this column should be sorted when the user clicks on the column
+ * header.
+ */
+ public void setSortable(boolean isSortable) {
+ sortable = isSortable;
+ }
+
+ /**
+ * Returns whether this column should be sorted in a case sensitive manner.
+ * Defaults to true.
+ */
+ public boolean isSortCaseSensitive() {
+ return sortCaseSensitive;
+ }
+
+ /**
+ * Sets whether this column should be sorted when in a case sensitive manner. If
+ * false, the column contents should be string values.
+ */
+ public void setSortCaseSensitive(boolean isCaseSensitive) {
+ sortCaseSensitive = isCaseSensitive;
+ }
+
+ /**
+ * Called by the TableAssociation to determine whether the value at the
+ * specified row is editable. This is determined by the binding of the Editable
+ * aspect, looking at the value of the corresponding index in that display
+ * group. Note: because the display group may not have the same number if items,
+ * the selected index is used if the editable display group is not the same as
+ * the the value display group.
+ */
+ public boolean isEditableAtRow(int aRowIndex) {
+ if (editableKey == null)
+ return false;
Object value = null;
- if ( editableDisplayGroup != null )
- {
+ if (editableDisplayGroup != null) {
// if using the same group for both, return the value for the index
- if ( editableDisplayGroup.equals( valueDisplayGroup ) )
- {
- value =
- editableDisplayGroup.valueForObjectAtIndex( aRowIndex, editableKey );
- }
- else // using an external display group to determine editability
+ if (editableDisplayGroup.equals(valueDisplayGroup)) {
+ value = editableDisplayGroup.valueForObjectAtIndex(aRowIndex, editableKey);
+ } else // using an external display group to determine editability
{
// ignore index and use the selected object value from display group
- value =
- editableDisplayGroup.selectedObjectValueForKey( editableKey );
+ value = editableDisplayGroup.selectedObjectValueForKey(editableKey);
}
- }
- else
- {
+ } else {
// treat bound key without display group as a value
- value = editableKey;
+ value = editableKey;
}
- if ( value == null ) return false; // null defaults to false
- Boolean result = (Boolean)
- ValueConverter.convertObjectToClass( value, Boolean.class );
- if ( result == null ) return true; // non-null defaults to true
+ if (value == null)
+ return false; // null defaults to false
+ Boolean result = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ if (result == null)
+ return true; // non-null defaults to true
return result.booleanValue();
}
-
- // convenience
-
- private TableColumn component()
- {
- return (TableColumn) object();
- }
-
- /**
- * Called by TableAssociation to get a EOSortOrdering suitable
- * for the information in this column.
- * This implementation returns a EOSortOrdering with the key
- * equal to the value aspect's key and the appropriate selector
- * for the specified ascending value and the case sensitivity
- * of this column.
- * Override to customize the sort for your column.
- */
- public EOSortOrdering getSortOrdering( boolean isAscending )
- {
- if ( isAscending )
- {
- if ( isSortCaseSensitive() )
- {
- return new EOSortOrdering(
- valueKey,
- EOSortOrdering.CompareAscending ) ;
- }
- else
- {
- return new EOSortOrdering(
- valueKey,
- EOSortOrdering.CompareCaseInsensitiveAscending ) ;
- }
- }
- else
- {
- if ( isSortCaseSensitive() )
- {
- return new EOSortOrdering(
- valueKey,
- EOSortOrdering.CompareDescending ) ;
- }
- else
- {
- return new EOSortOrdering(
- valueKey,
- EOSortOrdering.CompareCaseInsensitiveDescending ) ;
- }
- }
- }
-
- /**
- * Returns the one-based index of this assocation's sort ordering
- * in the specified list of orderings. If the sign of the returned
- * value is negative, the ordering is descending. If the return
- * value is zero, no matching ordering was found.
- */
- protected int getIndexOfMatchingOrdering( List orderings )
- {
- // find index of matching ordering
- int index = 0;
- EOSortOrdering ordering = null;
- Iterator i = orderings.iterator();
- while ( i.hasNext() )
- {
- index++;
- ordering = (EOSortOrdering) i.next();
- if ( ordering.key().equals( valueKey ) )
- {
- // determine ascending or descending
- if ( getSortOrdering( true ).equals( ordering ) )
- {
- return index;
- }
- else
- if ( getSortOrdering( false ).equals( ordering ) )
- {
- return -index;
- }
- }
- }
- return 0;
-
- }
-
- /**
- * Called by TableAssociation to draw some indicator in the
- * specified rectangle using the specified graphics to indicate
- * the specified sort state. The rectangle corresponds to the
- * bounds of the column header.
- * This implementation draws a small transparent gray triangle at
- * the right edge of the bounding rectangle.
- * Override to do something different or to do nothing at all.
- */
- protected void drawSortIndicator( Rectangle aBoundingRectangle,
- Graphics aGraphicsContext, List orderings )
- {
- int index = getIndexOfMatchingOrdering( orderings );
- if ( index == 0 ) return;
-
- boolean isAscending = ( index > 0 );
- index = Math.abs( index );
-
- // turn on anti-aliasing
- if ( aGraphicsContext instanceof Graphics2D )
- {
- ((Graphics2D)aGraphicsContext).setRenderingHint(
- RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON );
- }
-
- Rectangle r = new Rectangle( aBoundingRectangle );
-
- // resize to a right-justified square, sides equal to height
- r.setBounds( r.x + r.width - r.height, r.y, r.height, r.height );
-
- // resize to about a third smaller
- int portion = r.height / 3;
- r.grow( -portion, -portion );
-
- // transparencies cause java2d printing to rasterize,
- // resulting in excessive memory usage and print time.
- // aGraphicsContext.setColor( new Color( 0, 0, 0, 255 / (index*2) ) );
- aGraphicsContext.setColor( getSortIndicatorColor( index ) );
-
- Polygon triangle;
- if ( !isAscending )
- {
- triangle = new Polygon(
- new int[] { r.x, r.x+r.width/2, r.x+r.width },
- new int[] { r.y, r.y+r.height, r.y }, 3 );
- }
- else
- {
- triangle = new Polygon(
- new int[] { r.x, r.x+r.width/2, r.x+r.width },
- new int[] { r.y+r.height, r.y, r.y+r.height }, 3 );
- }
- aGraphicsContext.fillPolygon( triangle );
- }
-
- /**
- * Returns a color to be used by the sort indicator based on the index
- * of the sorting column. The goal of this method is to make the color
- * appear lighter and lighter, the "less" primary the sort order for this
- * column is. This can be acheives simply though a "transparent" color,
- * however, during printing of the corresponding table, java print
- * kicks into "raster" based printing when printing a component with
- * a transparent color instead of "vector" based printing. Raster
- * based printing can take up to 20-30 times longer to print than
- * vector printing and consume several times the amount of memory.
- * Raster-based printing should be avoided at all costs if the a component
- * is to be printed (as of Java 1.3.1).
- * @param index The "sort" index of the associated table column. The higher
- * the index, the lighter the color will be. An index of 0 will
- * return null.
- * @return The color to use when rendering the sort indicator.
- */
- protected static Color getSortIndicatorColor( int index )
- {
- if ( index == 0 ) return null;
-
- // Create the color list if not already created.
- if ( sortIndicatorColorList == null )
- {
- // Default size to 13 elements, it would be extremely rare that a
- // user sorts more than 12 columns at a time (although possible).
- // (Index 0 is not used.)
- sortIndicatorColorList = new Color[ 13 ];
- }
-
- // Get the color out of the color list. Use the index directly as
- // an index into an ordered list. If the color has already been
- // created for that index, then return it, otherwise create the color.
- if ( ( index < sortIndicatorColorList.length ) &&
- ( sortIndicatorColorList[ index ] != null ) )
- {
- return sortIndicatorColorList[ index ];
- }
-
- // The following logic performs the same affect as the above
- // transparent color, without actually using a transparent color.
- // Start with the table header's background color and derive a color
- // that is "darker" than that color. Any color this logic creates will
- // be between those two colors.
- Color lightColor = java.awt.SystemColor.control;
- Color darkColor = lightColor.darker().darker();
-
- // Make the light color (the upper bound) a little darker, so that even
- // the lightest triangle will still be slightly visible.
- lightColor = new Color(
- Math.max( ( int )( lightColor.getRed() * 0.9), 0 ),
- Math.max( ( int )( lightColor.getGreen() * 0.9), 0 ),
- Math.max( ( int )( lightColor.getBlue() * 0.9), 0) );
-
- // Subtract the light color from the dark color. This is the range
- // between the two colors.
- Color difference = new Color( lightColor.getRed() - darkColor.getRed(),
- lightColor.getGreen() - darkColor.getGreen(),
- lightColor.getBlue() - darkColor.getBlue() );
-
- // If the index is 1, user the dark color as is. Otherwise scale the
- // color closer and closer to the lighter color as the index gets
- // biggger and bigger.
- if ( index > 1 )
- {
- float factor = ( float )Math.pow( 0.5, ( index - 1 ) );
- darkColor = new Color(
- Math.max( lightColor.getRed() - ( int )( difference.getRed() * factor ), 0 ),
- Math.max( lightColor.getGreen() - ( int )( difference.getGreen() * factor ), 0 ),
- Math.max( lightColor.getBlue() - ( int )( difference.getBlue() * factor ), 0 ) );
- }
-
- // Cache the created color in the color list for this index.
- if ( index >= sortIndicatorColorList.length )
- {
- // The color list is too small, create a new larger list with
- // some padding for even larger indicies.
- Color[] oldList = sortIndicatorColorList;
- sortIndicatorColorList = new Color[ index + 5 ];
- System.arraycopy( oldList, 0, sortIndicatorColorList, 0, oldList.length );
- }
- sortIndicatorColorList[ index ] = darkColor;
-
- return darkColor;
- }
+
+ // convenience
+
+ private TableColumn component() {
+ return (TableColumn) object();
+ }
+
+ /**
+ * Called by TableAssociation to get a EOSortOrdering suitable for the
+ * information in this column. This implementation returns a EOSortOrdering with
+ * the key equal to the value aspect's key and the appropriate selector for the
+ * specified ascending value and the case sensitivity of this column. Override
+ * to customize the sort for your column.
+ */
+ public EOSortOrdering getSortOrdering(boolean isAscending) {
+ if (isAscending) {
+ if (isSortCaseSensitive()) {
+ return new EOSortOrdering(valueKey, EOSortOrdering.CompareAscending);
+ } else {
+ return new EOSortOrdering(valueKey, EOSortOrdering.CompareCaseInsensitiveAscending);
+ }
+ } else {
+ if (isSortCaseSensitive()) {
+ return new EOSortOrdering(valueKey, EOSortOrdering.CompareDescending);
+ } else {
+ return new EOSortOrdering(valueKey, EOSortOrdering.CompareCaseInsensitiveDescending);
+ }
+ }
+ }
+
+ /**
+ * Returns the one-based index of this assocation's sort ordering in the
+ * specified list of orderings. If the sign of the returned value is negative,
+ * the ordering is descending. If the return value is zero, no matching ordering
+ * was found.
+ */
+ protected int getIndexOfMatchingOrdering(List orderings) {
+ // find index of matching ordering
+ int index = 0;
+ EOSortOrdering ordering = null;
+ Iterator i = orderings.iterator();
+ while (i.hasNext()) {
+ index++;
+ ordering = (EOSortOrdering) i.next();
+ if (ordering.key().equals(valueKey)) {
+ // determine ascending or descending
+ if (getSortOrdering(true).equals(ordering)) {
+ return index;
+ } else if (getSortOrdering(false).equals(ordering)) {
+ return -index;
+ }
+ }
+ }
+ return 0;
+
+ }
+
+ /**
+ * Called by TableAssociation to draw some indicator in the specified rectangle
+ * using the specified graphics to indicate the specified sort state. The
+ * rectangle corresponds to the bounds of the column header. This implementation
+ * draws a small transparent gray triangle at the right edge of the bounding
+ * rectangle. Override to do something different or to do nothing at all.
+ */
+ protected void drawSortIndicator(Rectangle aBoundingRectangle, Graphics aGraphicsContext, List orderings) {
+ int index = getIndexOfMatchingOrdering(orderings);
+ if (index == 0)
+ return;
+
+ boolean isAscending = (index > 0);
+ index = Math.abs(index);
+
+ // turn on anti-aliasing
+ if (aGraphicsContext instanceof Graphics2D) {
+ ((Graphics2D) aGraphicsContext).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+
+ Rectangle r = new Rectangle(aBoundingRectangle);
+
+ // resize to a right-justified square, sides equal to height
+ r.setBounds(r.x + r.width - r.height, r.y, r.height, r.height);
+
+ // resize to about a third smaller
+ int portion = r.height / 3;
+ r.grow(-portion, -portion);
+
+ // transparencies cause java2d printing to rasterize,
+ // resulting in excessive memory usage and print time.
+ // aGraphicsContext.setColor( new Color( 0, 0, 0, 255 / (index*2) ) );
+ aGraphicsContext.setColor(getSortIndicatorColor(index));
+
+ Polygon triangle;
+ if (!isAscending) {
+ triangle = new Polygon(new int[] { r.x, r.x + r.width / 2, r.x + r.width },
+ new int[] { r.y, r.y + r.height, r.y }, 3);
+ } else {
+ triangle = new Polygon(new int[] { r.x, r.x + r.width / 2, r.x + r.width },
+ new int[] { r.y + r.height, r.y, r.y + r.height }, 3);
+ }
+ aGraphicsContext.fillPolygon(triangle);
+ }
+
+ /**
+ * Returns a color to be used by the sort indicator based on the index of the
+ * sorting column. The goal of this method is to make the color appear lighter
+ * and lighter, the "less" primary the sort order for this column is. This can
+ * be acheives simply though a "transparent" color, however, during printing of
+ * the corresponding table, java print kicks into "raster" based printing when
+ * printing a component with a transparent color instead of "vector" based
+ * printing. Raster based printing can take up to 20-30 times longer to print
+ * than vector printing and consume several times the amount of memory.
+ * Raster-based printing should be avoided at all costs if the a component is to
+ * be printed (as of Java 1.3.1).
+ *
+ * @param index The "sort" index of the associated table column. The higher the
+ * index, the lighter the color will be. An index of 0 will return
+ * null.
+ * @return The color to use when rendering the sort indicator.
+ */
+ protected static Color getSortIndicatorColor(int index) {
+ if (index == 0)
+ return null;
+
+ // Create the color list if not already created.
+ if (sortIndicatorColorList == null) {
+ // Default size to 13 elements, it would be extremely rare that a
+ // user sorts more than 12 columns at a time (although possible).
+ // (Index 0 is not used.)
+ sortIndicatorColorList = new Color[13];
+ }
+
+ // Get the color out of the color list. Use the index directly as
+ // an index into an ordered list. If the color has already been
+ // created for that index, then return it, otherwise create the color.
+ if ((index < sortIndicatorColorList.length) && (sortIndicatorColorList[index] != null)) {
+ return sortIndicatorColorList[index];
+ }
+
+ // The following logic performs the same affect as the above
+ // transparent color, without actually using a transparent color.
+ // Start with the table header's background color and derive a color
+ // that is "darker" than that color. Any color this logic creates will
+ // be between those two colors.
+ Color lightColor = java.awt.SystemColor.control;
+ Color darkColor = lightColor.darker().darker();
+
+ // Make the light color (the upper bound) a little darker, so that even
+ // the lightest triangle will still be slightly visible.
+ lightColor = new Color(Math.max((int) (lightColor.getRed() * 0.9), 0),
+ Math.max((int) (lightColor.getGreen() * 0.9), 0), Math.max((int) (lightColor.getBlue() * 0.9), 0));
+
+ // Subtract the light color from the dark color. This is the range
+ // between the two colors.
+ Color difference = new Color(lightColor.getRed() - darkColor.getRed(),
+ lightColor.getGreen() - darkColor.getGreen(), lightColor.getBlue() - darkColor.getBlue());
+
+ // If the index is 1, user the dark color as is. Otherwise scale the
+ // color closer and closer to the lighter color as the index gets
+ // biggger and bigger.
+ if (index > 1) {
+ float factor = (float) Math.pow(0.5, (index - 1));
+ darkColor = new Color(Math.max(lightColor.getRed() - (int) (difference.getRed() * factor), 0),
+ Math.max(lightColor.getGreen() - (int) (difference.getGreen() * factor), 0),
+ Math.max(lightColor.getBlue() - (int) (difference.getBlue() * factor), 0));
+ }
+
+ // Cache the created color in the color list for this index.
+ if (index >= sortIndicatorColorList.length) {
+ // The color list is too small, create a new larger list with
+ // some padding for even larger indicies.
+ Color[] oldList = sortIndicatorColorList;
+ sortIndicatorColorList = new Color[index + 5];
+ System.arraycopy(oldList, 0, sortIndicatorColorList, 0, oldList.length);
+ }
+ sortIndicatorColorList[index] = darkColor;
+
+ return darkColor;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.16 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.16 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.15 2002/08/22 15:42:49 mpowers
- * No longer using transparency to render sort indicator (see comments).
+ * Revision 1.15 2002/08/22 15:42:49 mpowers No longer using transparency to
+ * render sort indicator (see comments).
*
- * Revision 1.14 2002/04/12 21:05:57 mpowers
- * Now distinguishing changes in titles group even better.
+ * Revision 1.14 2002/04/12 21:05:57 mpowers Now distinguishing changes in
+ * titles group even better.
*
- * Revision 1.13 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.13 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.12 2002/03/04 22:11:43 mpowers
- * Darkened the sort indicator to better differentiate the first sort.
+ * Revision 1.12 2002/03/04 22:11:43 mpowers Darkened the sort indicator to
+ * better differentiate the first sort.
*
- * Revision 1.11 2002/03/04 03:58:17 mpowers
- * Refined table header click behavior.
+ * Revision 1.11 2002/03/04 03:58:17 mpowers Refined table header click
+ * behavior.
*
- * Revision 1.10 2002/03/01 15:42:00 mpowers
- * Table column headers now always show their sort indicator.
- * A third table-column click clears the sort for that column.
+ * Revision 1.10 2002/03/01 15:42:00 mpowers Table column headers now always
+ * show their sort indicator. A third table-column click clears the sort for
+ * that column.
*
- * Revision 1.9 2002/02/28 23:01:39 mpowers
- * TableColumnAssociations add and remove themselves from the TableAssociation
- * when their connection is established and broken respectively.
- * TableAssociations now break connection if they have no column associations.
+ * Revision 1.9 2002/02/28 23:01:39 mpowers TableColumnAssociations add and
+ * remove themselves from the TableAssociation when their connection is
+ * established and broken respectively. TableAssociations now break connection
+ * if they have no column associations.
*
- * Revision 1.8 2001/06/05 16:03:56 mpowers
- * Flipped the triangle to be consistent with Aqua.
+ * Revision 1.8 2001/06/05 16:03:56 mpowers Flipped the triangle to be
+ * consistent with Aqua.
*
- * Revision 1.7 2001/03/09 22:09:22 mpowers
- * Now better handling jdk1.1 for rendering the column header.
+ * Revision 1.7 2001/03/09 22:09:22 mpowers Now better handling jdk1.1 for
+ * rendering the column header.
*
- * Revision 1.6 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.6 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.5 2001/01/12 19:11:56 mpowers
- * Fixed table column click sorting.
+ * Revision 1.5 2001/01/12 19:11:56 mpowers Fixed table column click sorting.
*
- * Revision 1.4 2001/01/12 17:20:30 mpowers
- * Moved EOSortOrdering creation to ColumnAssociation.
+ * Revision 1.4 2001/01/12 17:20:30 mpowers Moved EOSortOrdering creation to
+ * ColumnAssociation.
*
- * Revision 1.3 2001/01/11 21:55:57 mpowers
- * Implemented sort indicator for table column headers.
+ * Revision 1.3 2001/01/11 21:55:57 mpowers Implemented sort indicator for table
+ * column headers.
*
- * Revision 1.2 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.2 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.1.1.1 2000/12/21 15:49:03 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:49:03 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TextAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TextAssociation.java
index 6aa27c3..ea2b47a 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TextAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TextAssociation.java
@@ -54,1159 +54,923 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TextAssociation binds JTextComponents and other objects
-* with getText() and setText() methods to a display group.
-* Note that JLabels are supported with both the Text and
-* Icon aspects.
-* Bindings are:
-* <ul>
-* <li>value: a property convertable to/from a string</li>
-* <li>editable: a boolean property that determines whether
-* the user can edit the text in the field</li>
-* <li>enabled: a boolean property that determines whether
-* the user can select the text in the field</li>
-* <li>visible: a boolean property that determines whether
-* the field is visible</li>
-* <li>label: a boolean property that determines whether
-* field should appear as a read-only, selectable label</li>
-* <li>icon: a property that returns a Swing icon, for use
-* with JLabels and other components with setIcon() methods.
-* If bound to a static string, the string will be used to
-* load an image resource from the selected object's class.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TextAssociation extends EOAssociation
- implements FocusListener, ActionListener, DocumentListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect, EditableAspect, VisibleAspect, LabelAspect, IconAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "text", "enabled", "editable", "visible"
- } );
-
- private final static NSSelector getText =
- new NSSelector( "getText" );
- private final static NSSelector setText =
- new NSSelector( "setText",
- new Class[] { String.class } );
- private final static NSSelector getDocument =
- new NSSelector( "getDocument" );
- private final static NSSelector setIcon =
- new NSSelector( "setIcon",
- new Class[] { Icon.class } );
- private final static NSSelector addActionListener =
- new NSSelector( "addActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector removeActionListener =
- new NSSelector( "removeActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector addFocusListener =
- new NSSelector( "addFocusListener",
- new Class[] { FocusListener.class } );
- private final static NSSelector removeFocusListener =
- new NSSelector( "removeFocusListener",
- new Class[] { FocusListener.class } );
-
- // null handling
- protected boolean wasNull;
- protected static final String EMPTY_STRING = "";
-
- // dirty handling
- protected boolean needsUpdate;
- protected boolean hasDocument;
- protected boolean isListening;
-
- // formatting
- protected Format format;
-
- // on-the-fly validation
- protected boolean activeUpdate;
-
- // type conversion
- protected Class lastKnownType;
-
- // cache the value aspect
- private EODisplayGroup valueDisplayGroup;
- private String valueKey;
-
- // hacky flags needed for no activeUpdate
- private boolean pleaseIgnoreNextChange = false;
- private boolean pleaseAcceptNextChange = false;
- private boolean externallyChanged = true;
-
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public TextAssociation ( Object anObject )
- {
- super( anObject );
- wasNull = false;
- needsUpdate = false;
- activeUpdate = true;
- hasDocument = false;
- isListening = true;
- valueDisplayGroup = null;
- valueKey = null;
- format = null;
- lastKnownType = null;
-
- // register for idle notifications
- NSSelector handleNotification =
- new NSSelector( "handleNotification",
- new Class[] { NSNotification.class } );
- NSNotificationCenter.defaultCenter().addObserver(
- this, handleNotification, null, this );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return setText.implementedByObject( anObject );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( ValueAspect.equals( anAspect ) )
- {
- valueDisplayGroup = aDisplayGroup;
- valueKey = aKey;
- }
- super.bindAspect( anAspect, aDisplayGroup, aKey );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * attempts to add this class as an ActionListener
- * and as a FocusListener to the specified object.
- */
- public void establishConnection ()
- {
- Object component = object();
- try
- {
- if ( addActionListener.implementedByObject( component ) )
- {
- addActionListener.invoke( component, this );
- }
- if ( addFocusListener.implementedByObject( component ) )
- {
- addFocusListener.invoke( component, this );
- }
- hasDocument = false;
- if ( getDocument.implementedByObject( component ) )
- {
- Object document = getDocument.invoke( component );
- if ( document instanceof Document )
- {
- ((Document)document).addDocumentListener( this );
- hasDocument = true;
- }
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while establishing connection", exc );
- }
-
- super.establishConnection();
-
- // forces update from bindings
- subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- Object component = object();
- try
- {
- if ( removeActionListener.implementedByObject( component ) )
- {
- removeActionListener.invoke( component, this );
- }
- if ( removeFocusListener.implementedByObject( component ) )
- {
- removeFocusListener.invoke( component, this );
- }
- if ( getDocument.implementedByObject( component ) )
- {
- Object document = getDocument.invoke( component );
- if ( document instanceof Document )
- {
- ((Document)document).removeDocumentListener( this );
- }
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while breaking connection", exc );
- }
- super.breakConnection();
- }
-
- public void objectWillChange( Object anObject )
- {
- super.objectWillChange( anObject );
- externallyChanged = true;
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged()
- {
- if ( pleaseIgnoreNextChange )
- {
- pleaseIgnoreNextChange = false;
- externallyChanged = false;
- return;
- }
-
- externallyChanged = true;
-
- Object component = object();
- EODisplayGroup displayGroup;
- String key;
- Object value;
-
- // value aspect
- displayGroup = valueDisplayGroup;
- if ( displayGroup != null )
- {
- if ( component instanceof Component )
- {
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( valueKey ) );
- }
-
- // if activeUpdate or we are not the editing association
- if ( activeUpdate || displayGroup.editingAssociation() != this || pleaseAcceptNextChange )
- {
- pleaseAcceptNextChange = false;
- key = valueKey;
-
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = previousValue;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && previousValue != null
- && !currentValue.toString().equals( previousValue.toString() ) ) {
- value = null;
- break;
- }
-
- } // end while
-
- } else {
-
- // if there's only one object selected.
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking the size of selected objects in displayGroup
-
- // null handling
- if ( value == null )
- {
- wasNull = true;
- value = EMPTY_STRING;
- lastKnownType = null;
- }
- else
- {
- wasNull = false;
- lastKnownType = value.getClass();
- if ( format() != null )
- {
- try
- {
- value = format().format( value );
- }
- catch ( IllegalArgumentException exc )
- {
- value = value.toString();
- }
- }
- }
-
-
- try
- {
- if ( needToReadValueFromDisplayGroup( value.toString(), getText ) )
- {
- // No need to listen for any events that might get fired
- // while setting the text since we are the one setting it.
- boolean wasListening = isListening;
- isListening = false;
-
- // setText is an expensive operation
- setText.invoke( component, value.toString() );
-
- isListening = wasListening;
- needsUpdate = false;
- }
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection", exc );
- }
- }
- }
-
- // icon aspect
- displayGroup = displayGroupForAspect( IconAspect );
- key = displayGroupKeyForAspect( IconAspect );
- if ( key != null )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group
- // as a resource to be loaded from the selected class.
- value = null;
- Object o = displayGroup.selectedObject();
- if ( o != null )
- {
- URL url = o.getClass().getResource( key );
- if ( url != null )
- {
- value = new ImageIcon( url );
- }
- }
- }
-
- try
- {
- setIcon.invoke( component, value );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection", exc );
- }
- }
-
- // enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- key = displayGroupKeyForAspect( EnabledAspect );
- if ( ( key != null )
- && ( component instanceof Component ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group as a value
- value = key;
- }
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( ((Component)component).isEnabled() != converted.booleanValue() )
- {
- ((Component)component).setEnabled( converted.booleanValue() );
- }
- }
-
- // editable aspect
- displayGroup = displayGroupForAspect( EditableAspect );
- key = displayGroupKeyForAspect( EditableAspect );
- if ( ( key != null )
- && ( component instanceof JTextComponent ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group as a value
- value = key;
- }
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() != ((JTextComponent)component).isEditable() )
- {
- ((JTextComponent)component).setEditable( converted.booleanValue() );
- }
- }
- }
-
- // visible aspect
- displayGroup = displayGroupForAspect( VisibleAspect );
- key = displayGroupKeyForAspect( VisibleAspect );
- if ( ( key != null )
- && ( component instanceof Component ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group as a value
- value = key;
- }
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() != ((Component)component).isVisible() )
- {
- ((Component)component).setVisible( converted.booleanValue() );
- }
- }
- }
-
- // label aspect
- displayGroup = displayGroupForAspect( LabelAspect );
- key = displayGroupKeyForAspect( LabelAspect );
-
- if ( ( key != null )
- && ( component instanceof JTextComponent ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group as a value
- value = key;
- }
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() )
- {
- if ( component instanceof JTextComponent )
- {
- if ( component instanceof JTextArea )
- {
- areaToLabel( (JTextArea) component );
- }
- else
- {
- fieldToLabel( (JTextComponent) component );
- }
- }
- }
- else
- {
- if ( component instanceof JTextComponent )
- {
- if ( component instanceof JTextArea )
- {
- labelToArea( (JTextArea) component );
- }
- else
- {
- labelToField( (JTextComponent ) component );
- }
- }
- }
- }
- }
- }
-
- private void fieldToLabel( JTextComponent aTextField )
- {
- // turn on wrapping and disable editing and highlighting
-
- aTextField.setEditable(false);
- aTextField.setOpaque(false);
-
- // Set the border, colors and font to that of a label
-
- //LookAndFeel.installBorder(aTextField, "Label.border");
- aTextField.setBorder( null );
-
- LookAndFeel.installColorsAndFont(aTextField,
- "Label.background",
- "Label.foreground",
- "Label.font");
- }
-
- private void labelToField( JTextComponent aTextField )
- {
- // turn on wrapping and disable editing and highlighting
-
- aTextField.setEditable(true);
- aTextField.setOpaque(true);
-
- // Set the border, colors and font to that of a label
-
- LookAndFeel.installBorder(aTextField, "TextField.border");
-
- LookAndFeel.installColorsAndFont(aTextField,
- "TextField.background",
- "TextField.foreground",
- "TextField.font");
- }
-
- private void areaToLabel( JTextArea aTextArea )
- {
- // turn on wrapping and disable editing and highlighting
-
- aTextArea.setLineWrap(true);
- aTextArea.setWrapStyleWord(true);
- aTextArea.setEditable(false);
-
- // Set the text area's border, colors and font to
- // that of a label
-
- //LookAndFeel.installBorder(aTextArea, "Label.border");
- aTextArea.setBorder( null );
-
- LookAndFeel.installColorsAndFont(aTextArea,
- "Label.background",
- "Label.foreground",
- "Label.font");
-
- }
-
- private void labelToArea( JTextArea aTextArea )
- {
- // turn on wrapping and disable editing and highlighting
-
- aTextArea.setEditable(true);
-
- // Set the border, colors and font to that of a label
-
- LookAndFeel.installBorder(aTextArea, "TextArea.border");
-
- LookAndFeel.installColorsAndFont(aTextArea,
- "TextArea.background",
- "TextArea.foreground",
- "TextArea.font");
- }
-
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing()
- {
- pleaseAcceptNextChange = true;
- pleaseIgnoreNextChange = false;
- return writeValueToDisplayGroup();
- }
-
- /**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- boolean returnValue = true;
- if ( hasDocument && !needsUpdate ) return true;
-
- EODisplayGroup displayGroup = valueDisplayGroup;
- if ( displayGroup != null )
- {
- String key = valueKey;
- Object component = object();
- Object value = null;
- try
- {
- //if ( getText.implementedByObject( component ) )
- //{
- value = getText.invoke( component );
- //}
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error updating display group", exc );
- }
-
- if ( ( wasNull ) && ( EMPTY_STRING.equals( value ) ) )
- {
- value = null;
- }
- else
- if ( format() != null )
- {
- try
- {
- value = format().parseObject( value.toString() );
- }
- catch ( ParseException exc )
- {
- String message = exc.getMessage();
- //"That format was not recognized.";
- if ( displayGroup.associationFailedToValidateValue(
- this, value.toString(), key, exc, message ) )
- {
- boolean wasListening = isListening;
- isListening = false;
- JOptionPane.showMessageDialog(
- (Component)component, message );
- isListening = wasListening;
- }
- needsUpdate = false;
- return false;
- }
- }
-
- if ( ( lastKnownType != null ) && ( value != null ) )
- {
- // convert back to last known type, if necessary/possible
- Class type = value.getClass();
- if ( ( type != null ) && ( type != lastKnownType ) )
- {
- Object converted =
- ValueConverter.convertObjectToClass(
- value, lastKnownType );
- if ( converted != null )
- {
- value = converted;
- }
- // else: not possible, ignore
- }
- }
-
- needsUpdate = false;
-
- // only update if the value is different from the one in the display group
- if ( ! needToWriteValueToDisplayGroup( value, displayGroup ) ) return true;
-
- // we might lose focus if display group displays a validation message
- boolean wasListening = isListening;
- isListening = false;
-
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- needsUpdate = false;
- }
- else
- {
- needsUpdate = false;
- returnValue = false;
- }
- }
- isListening = wasListening;
-
- }
- return returnValue;
- }
-
- /**
- * Called to determine whether the display group needs to be
- * updated. This implementation reads the value from the display
- * group and only returns true if the specified value is different.
- * This is done as an optimization since writes are more expensive
- * than reads. Override to customize this behavior.
- */
- protected boolean needToWriteValueToDisplayGroup(
- Object aValue, EODisplayGroup aDisplayGroup )
- {
- Object existingValue = aDisplayGroup.selectedObjectValueForKey( valueKey );
- if ( aDisplayGroup.selectedObjects().size() == 1 )
- {
- if ( existingValue == aValue ) return false;
- if ( ( existingValue != null ) && ( existingValue.equals( aValue ) ) ) return false;
- if ( ( aValue != null ) && ( aValue.equals( existingValue ) ) ) return false;
- }
- return true;
- }
-
- /**
- * Called to determine whether the controlled component needs to be
- * updated. This implementation reads the value from the selector
- * and only returns true if the specified value is different.
- * This is done as an optimization since updating the component
- * can be an expensive operation. Override to customize this behavior.
- */
- protected boolean needToReadValueFromDisplayGroup(
- Object aValue, NSSelector aSelector )
- throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
- {
- return !aValue.toString().equals( aSelector.invoke( object() ) );
- }
-
- /**
- * Sets the Format that is used to convert values from the display
- * group to and from text that is displayed in the component.
- */
- public void setFormat( Format aFormat )
- {
- format = aFormat;
- }
-
- /**
- * Gets the Format that is used to convert values from the display
- * group to and from text that is displayed in the component.
- */
- public Format format()
- {
- return format;
- }
-
- /**
- * Returns whether the text association is configured to actively
- * update the model in response to changes in the component.
- */
- public boolean isActiveUpdate()
- {
- return activeUpdate;
- }
-
- /**
- * Sets whether the text association should actively
- * update the model in response to changes in the component.
- * Default is true. False indicates that the model will be updated
- * only when the component loses focus or fires an action event.
- */
- public void setActiveUpdate( boolean isActiveUpdate )
- {
- activeUpdate = isActiveUpdate;
- }
-
- // interface ActionListener
-
- /**
- * Updates object on action performed.
- */
- public void actionPerformed( ActionEvent evt )
- {
- if ( ! isListening ) return;
- if ( needsUpdate )
- {
- pleaseAcceptNextChange = true; // needed if activeUpdate = false
- writeValueToDisplayGroup();
- }
- }
-
- // interface FocusListener
-
- /**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
- if ( ! isListening ) return;
-
- pleaseAcceptNextChange = true;
- externallyChanged = true;
-
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
- }
- }
- }
-
- /**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( ! isListening ) return;
- if ( endEditing() )
- {
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
- }
- }
- }
- else
- {
- // probably should notify of a validation error here,
- }
- }
-
- /**
- * Queues a notification to PostWhenIdle.
- */
- protected void queueUpdate(DocumentEvent e)
- {
- if ( e.getDocument() instanceof DefaultStyledDocument )
- {
- if ( e instanceof AbstractDocument.DefaultDocumentEvent )
- {
- int docLength = e.getDocument().getLength();
-
- if ( ( e.getType().equals( DocumentEvent.EventType.CHANGE ) ) )
- {
- if ( e.getOffset() == 0 && e.getLength() == docLength )
- {
- // ignore document events for the whole document
- // since default styled document broadcasts these
- // using invokeLater, and we've already received
- // notification about the actual style change.
- // see: DefaultStyledDocument.ChangeUpdateRunnable
- return;
- }
- }
- }
- }
-
- NSNotificationQueue.defaultQueue().enqueueNotification(
- new NSNotification( "TextAssociation.DocumentChanged", this,
- new NSDictionary( new Object[] { "event" }, new Object[] { e } ) ),
- NSNotificationQueue.PostWhenIdle );
- }
-
- /**
- * Handles idle notification.
- */
- public void handleNotification( NSNotification aNotification )
- {
- if ( activeUpdate )
- {
- writeValueToDisplayGroup();
- }
- }
-
- // interface DocumentListener
-
- public void insertUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate( e );
- }
-
- public void removeUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate( e );
- }
-
- public void changedUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate( e );
- }
+ * TextAssociation binds JTextComponents and other objects with getText() and
+ * setText() methods to a display group. Note that JLabels are supported with
+ * both the Text and Icon aspects. Bindings are:
+ * <ul>
+ * <li>value: a property convertable to/from a string</li>
+ * <li>editable: a boolean property that determines whether the user can edit
+ * the text in the field</li>
+ * <li>enabled: a boolean property that determines whether the user can select
+ * the text in the field</li>
+ * <li>visible: a boolean property that determines whether the field is
+ * visible</li>
+ * <li>label: a boolean property that determines whether field should appear as
+ * a read-only, selectable label</li>
+ * <li>icon: a property that returns a Swing icon, for use with JLabels and
+ * other components with setIcon() methods. If bound to a static string, the
+ * string will be used to load an image resource from the selected object's
+ * class.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TextAssociation extends EOAssociation implements FocusListener, ActionListener, DocumentListener {
+ static final NSArray aspects = new NSArray(
+ new Object[] { ValueAspect, EnabledAspect, EditableAspect, VisibleAspect, LabelAspect, IconAspect });
+ static final NSArray aspectSignatures = new NSArray(
+ new Object[] { AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "text", "enabled", "editable", "visible" });
+
+ private final static NSSelector getText = new NSSelector("getText");
+ private final static NSSelector setText = new NSSelector("setText", new Class[] { String.class });
+ private final static NSSelector getDocument = new NSSelector("getDocument");
+ private final static NSSelector setIcon = new NSSelector("setIcon", new Class[] { Icon.class });
+ private final static NSSelector addActionListener = new NSSelector("addActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector removeActionListener = new NSSelector("removeActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector addFocusListener = new NSSelector("addFocusListener",
+ new Class[] { FocusListener.class });
+ private final static NSSelector removeFocusListener = new NSSelector("removeFocusListener",
+ new Class[] { FocusListener.class });
+
+ // null handling
+ protected boolean wasNull;
+ protected static final String EMPTY_STRING = "";
+
+ // dirty handling
+ protected boolean needsUpdate;
+ protected boolean hasDocument;
+ protected boolean isListening;
+
+ // formatting
+ protected Format format;
+
+ // on-the-fly validation
+ protected boolean activeUpdate;
+
+ // type conversion
+ protected Class lastKnownType;
+
+ // cache the value aspect
+ private EODisplayGroup valueDisplayGroup;
+ private String valueKey;
+
+ // hacky flags needed for no activeUpdate
+ private boolean pleaseIgnoreNextChange = false;
+ private boolean pleaseAcceptNextChange = false;
+ private boolean externallyChanged = true;
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public TextAssociation(Object anObject) {
+ super(anObject);
+ wasNull = false;
+ needsUpdate = false;
+ activeUpdate = true;
+ hasDocument = false;
+ isListening = true;
+ valueDisplayGroup = null;
+ valueKey = null;
+ format = null;
+ lastKnownType = null;
+
+ // register for idle notifications
+ NSSelector handleNotification = new NSSelector("handleNotification", new Class[] { NSNotification.class });
+ NSNotificationCenter.defaultCenter().addObserver(this, handleNotification, null, this);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return setText.implementedByObject(anObject);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (ValueAspect.equals(anAspect)) {
+ valueDisplayGroup = aDisplayGroup;
+ valueKey = aKey;
+ }
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation attempts to add this class as an ActionListener and as a
+ * FocusListener to the specified object.
+ */
+ public void establishConnection() {
+ Object component = object();
+ try {
+ if (addActionListener.implementedByObject(component)) {
+ addActionListener.invoke(component, this);
+ }
+ if (addFocusListener.implementedByObject(component)) {
+ addFocusListener.invoke(component, this);
+ }
+ hasDocument = false;
+ if (getDocument.implementedByObject(component)) {
+ Object document = getDocument.invoke(component);
+ if (document instanceof Document) {
+ ((Document) document).addDocumentListener(this);
+ hasDocument = true;
+ }
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while establishing connection", exc);
+ }
+
+ super.establishConnection();
+
+ // forces update from bindings
+ subjectChanged();
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ Object component = object();
+ try {
+ if (removeActionListener.implementedByObject(component)) {
+ removeActionListener.invoke(component, this);
+ }
+ if (removeFocusListener.implementedByObject(component)) {
+ removeFocusListener.invoke(component, this);
+ }
+ if (getDocument.implementedByObject(component)) {
+ Object document = getDocument.invoke(component);
+ if (document instanceof Document) {
+ ((Document) document).removeDocumentListener(this);
+ }
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while breaking connection", exc);
+ }
+ super.breakConnection();
+ }
+
+ public void objectWillChange(Object anObject) {
+ super.objectWillChange(anObject);
+ externallyChanged = true;
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
+ if (pleaseIgnoreNextChange) {
+ pleaseIgnoreNextChange = false;
+ externallyChanged = false;
+ return;
+ }
+
+ externallyChanged = true;
+
+ Object component = object();
+ EODisplayGroup displayGroup;
+ String key;
+ Object value;
+
+ // value aspect
+ displayGroup = valueDisplayGroup;
+ if (displayGroup != null) {
+ if (component instanceof Component) {
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(valueKey));
+ }
+
+ // if activeUpdate or we are not the editing association
+ if (activeUpdate || displayGroup.editingAssociation() != this || pleaseAcceptNextChange) {
+ pleaseAcceptNextChange = false;
+ key = valueKey;
+
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = previousValue;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && previousValue != null
+ && !currentValue.toString().equals(previousValue.toString())) {
+ value = null;
+ break;
+ }
+
+ } // end while
+
+ } else {
+
+ // if there's only one object selected.
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking the size of selected objects in displayGroup
+
+ // null handling
+ if (value == null) {
+ wasNull = true;
+ value = EMPTY_STRING;
+ lastKnownType = null;
+ } else {
+ wasNull = false;
+ lastKnownType = value.getClass();
+ if (format() != null) {
+ try {
+ value = format().format(value);
+ } catch (IllegalArgumentException exc) {
+ value = value.toString();
+ }
+ }
+ }
+
+ try {
+ if (needToReadValueFromDisplayGroup(value.toString(), getText)) {
+ // No need to listen for any events that might get fired
+ // while setting the text since we are the one setting it.
+ boolean wasListening = isListening;
+ isListening = false;
+
+ // setText is an expensive operation
+ setText.invoke(component, value.toString());
+
+ isListening = wasListening;
+ needsUpdate = false;
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection", exc);
+ }
+ }
+ }
+
+ // icon aspect
+ displayGroup = displayGroupForAspect(IconAspect);
+ key = displayGroupKeyForAspect(IconAspect);
+ if (key != null) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group
+ // as a resource to be loaded from the selected class.
+ value = null;
+ Object o = displayGroup.selectedObject();
+ if (o != null) {
+ URL url = o.getClass().getResource(key);
+ if (url != null) {
+ value = new ImageIcon(url);
+ }
+ }
+ }
+
+ try {
+ setIcon.invoke(component, value);
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection", exc);
+ }
+ }
+
+ // enabled aspect
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ key = displayGroupKeyForAspect(EnabledAspect);
+ if ((key != null) && (component instanceof Component)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group as a value
+ value = key;
+ }
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (((Component) component).isEnabled() != converted.booleanValue()) {
+ ((Component) component).setEnabled(converted.booleanValue());
+ }
+ }
+
+ // editable aspect
+ displayGroup = displayGroupForAspect(EditableAspect);
+ key = displayGroupKeyForAspect(EditableAspect);
+ if ((key != null) && (component instanceof JTextComponent)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group as a value
+ value = key;
+ }
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue() != ((JTextComponent) component).isEditable()) {
+ ((JTextComponent) component).setEditable(converted.booleanValue());
+ }
+ }
+ }
+
+ // visible aspect
+ displayGroup = displayGroupForAspect(VisibleAspect);
+ key = displayGroupKeyForAspect(VisibleAspect);
+ if ((key != null) && (component instanceof Component)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group as a value
+ value = key;
+ }
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue() != ((Component) component).isVisible()) {
+ ((Component) component).setVisible(converted.booleanValue());
+ }
+ }
+ }
+
+ // label aspect
+ displayGroup = displayGroupForAspect(LabelAspect);
+ key = displayGroupKeyForAspect(LabelAspect);
+
+ if ((key != null) && (component instanceof JTextComponent)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group as a value
+ value = key;
+ }
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue()) {
+ if (component instanceof JTextComponent) {
+ if (component instanceof JTextArea) {
+ areaToLabel((JTextArea) component);
+ } else {
+ fieldToLabel((JTextComponent) component);
+ }
+ }
+ } else {
+ if (component instanceof JTextComponent) {
+ if (component instanceof JTextArea) {
+ labelToArea((JTextArea) component);
+ } else {
+ labelToField((JTextComponent) component);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void fieldToLabel(JTextComponent aTextField) {
+ // turn on wrapping and disable editing and highlighting
+
+ aTextField.setEditable(false);
+ aTextField.setOpaque(false);
+
+ // Set the border, colors and font to that of a label
+
+ // LookAndFeel.installBorder(aTextField, "Label.border");
+ aTextField.setBorder(null);
+
+ LookAndFeel.installColorsAndFont(aTextField, "Label.background", "Label.foreground", "Label.font");
+ }
+
+ private void labelToField(JTextComponent aTextField) {
+ // turn on wrapping and disable editing and highlighting
+
+ aTextField.setEditable(true);
+ aTextField.setOpaque(true);
+
+ // Set the border, colors and font to that of a label
+
+ LookAndFeel.installBorder(aTextField, "TextField.border");
+
+ LookAndFeel.installColorsAndFont(aTextField, "TextField.background", "TextField.foreground", "TextField.font");
+ }
+
+ private void areaToLabel(JTextArea aTextArea) {
+ // turn on wrapping and disable editing and highlighting
+
+ aTextArea.setLineWrap(true);
+ aTextArea.setWrapStyleWord(true);
+ aTextArea.setEditable(false);
+
+ // Set the text area's border, colors and font to
+ // that of a label
+
+ // LookAndFeel.installBorder(aTextArea, "Label.border");
+ aTextArea.setBorder(null);
+
+ LookAndFeel.installColorsAndFont(aTextArea, "Label.background", "Label.foreground", "Label.font");
+
+ }
+
+ private void labelToArea(JTextArea aTextArea) {
+ // turn on wrapping and disable editing and highlighting
+
+ aTextArea.setEditable(true);
+
+ // Set the border, colors and font to that of a label
+
+ LookAndFeel.installBorder(aTextArea, "TextArea.border");
+
+ LookAndFeel.installColorsAndFont(aTextArea, "TextArea.background", "TextArea.foreground", "TextArea.font");
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ pleaseAcceptNextChange = true;
+ pleaseIgnoreNextChange = false;
+ return writeValueToDisplayGroup();
+ }
+
+ /**
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ boolean returnValue = true;
+ if (hasDocument && !needsUpdate)
+ return true;
+
+ EODisplayGroup displayGroup = valueDisplayGroup;
+ if (displayGroup != null) {
+ String key = valueKey;
+ Object component = object();
+ Object value = null;
+ try {
+ // if ( getText.implementedByObject( component ) )
+ // {
+ value = getText.invoke(component);
+ // }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error updating display group", exc);
+ }
+
+ if ((wasNull) && (EMPTY_STRING.equals(value))) {
+ value = null;
+ } else if (format() != null) {
+ try {
+ value = format().parseObject(value.toString());
+ } catch (ParseException exc) {
+ String message = exc.getMessage();
+ // "That format was not recognized.";
+ if (displayGroup.associationFailedToValidateValue(this, value.toString(), key, exc, message)) {
+ boolean wasListening = isListening;
+ isListening = false;
+ JOptionPane.showMessageDialog((Component) component, message);
+ isListening = wasListening;
+ }
+ needsUpdate = false;
+ return false;
+ }
+ }
+
+ if ((lastKnownType != null) && (value != null)) {
+ // convert back to last known type, if necessary/possible
+ Class type = value.getClass();
+ if ((type != null) && (type != lastKnownType)) {
+ Object converted = ValueConverter.convertObjectToClass(value, lastKnownType);
+ if (converted != null) {
+ value = converted;
+ }
+ // else: not possible, ignore
+ }
+ }
+
+ needsUpdate = false;
+
+ // only update if the value is different from the one in the display group
+ if (!needToWriteValueToDisplayGroup(value, displayGroup))
+ return true;
+
+ // we might lose focus if display group displays a validation message
+ boolean wasListening = isListening;
+ isListening = false;
+
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ needsUpdate = false;
+ } else {
+ needsUpdate = false;
+ returnValue = false;
+ }
+ }
+ isListening = wasListening;
+
+ }
+ return returnValue;
+ }
+
+ /**
+ * Called to determine whether the display group needs to be updated. This
+ * implementation reads the value from the display group and only returns true
+ * if the specified value is different. This is done as an optimization since
+ * writes are more expensive than reads. Override to customize this behavior.
+ */
+ protected boolean needToWriteValueToDisplayGroup(Object aValue, EODisplayGroup aDisplayGroup) {
+ Object existingValue = aDisplayGroup.selectedObjectValueForKey(valueKey);
+ if (aDisplayGroup.selectedObjects().size() == 1) {
+ if (existingValue == aValue)
+ return false;
+ if ((existingValue != null) && (existingValue.equals(aValue)))
+ return false;
+ if ((aValue != null) && (aValue.equals(existingValue)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Called to determine whether the controlled component needs to be updated.
+ * This implementation reads the value from the selector and only returns true
+ * if the specified value is different. This is done as an optimization since
+ * updating the component can be an expensive operation. Override to customize
+ * this behavior.
+ */
+ protected boolean needToReadValueFromDisplayGroup(Object aValue, NSSelector aSelector)
+ throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ return !aValue.toString().equals(aSelector.invoke(object()));
+ }
+
+ /**
+ * Sets the Format that is used to convert values from the display group to and
+ * from text that is displayed in the component.
+ */
+ public void setFormat(Format aFormat) {
+ format = aFormat;
+ }
+
+ /**
+ * Gets the Format that is used to convert values from the display group to and
+ * from text that is displayed in the component.
+ */
+ public Format format() {
+ return format;
+ }
+
+ /**
+ * Returns whether the text association is configured to actively update the
+ * model in response to changes in the component.
+ */
+ public boolean isActiveUpdate() {
+ return activeUpdate;
+ }
+
+ /**
+ * Sets whether the text association should actively update the model in
+ * response to changes in the component. Default is true. False indicates that
+ * the model will be updated only when the component loses focus or fires an
+ * action event.
+ */
+ public void setActiveUpdate(boolean isActiveUpdate) {
+ activeUpdate = isActiveUpdate;
+ }
+
+ // interface ActionListener
+
+ /**
+ * Updates object on action performed.
+ */
+ public void actionPerformed(ActionEvent evt) {
+ if (!isListening)
+ return;
+ if (needsUpdate) {
+ pleaseAcceptNextChange = true; // needed if activeUpdate = false
+ writeValueToDisplayGroup();
+ }
+ }
+
+ // interface FocusListener
+
+ /**
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
+ if (!isListening)
+ return;
+
+ pleaseAcceptNextChange = true;
+ externallyChanged = true;
+
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
+ }
+ }
+ }
+
+ /**
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (!isListening)
+ return;
+ if (endEditing()) {
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
+ }
+ }
+ } else {
+ // probably should notify of a validation error here,
+ }
+ }
+
+ /**
+ * Queues a notification to PostWhenIdle.
+ */
+ protected void queueUpdate(DocumentEvent e) {
+ if (e.getDocument() instanceof DefaultStyledDocument) {
+ if (e instanceof AbstractDocument.DefaultDocumentEvent) {
+ int docLength = e.getDocument().getLength();
+
+ if ((e.getType().equals(DocumentEvent.EventType.CHANGE))) {
+ if (e.getOffset() == 0 && e.getLength() == docLength) {
+ // ignore document events for the whole document
+ // since default styled document broadcasts these
+ // using invokeLater, and we've already received
+ // notification about the actual style change.
+ // see: DefaultStyledDocument.ChangeUpdateRunnable
+ return;
+ }
+ }
+ }
+ }
+
+ NSNotificationQueue.defaultQueue().enqueueNotification(
+ new NSNotification("TextAssociation.DocumentChanged", this,
+ new NSDictionary(new Object[] { "event" }, new Object[] { e })),
+ NSNotificationQueue.PostWhenIdle);
+ }
+
+ /**
+ * Handles idle notification.
+ */
+ public void handleNotification(NSNotification aNotification) {
+ if (activeUpdate) {
+ writeValueToDisplayGroup();
+ }
+ }
+
+ // interface DocumentListener
+
+ public void insertUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate(e);
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate(e);
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate(e);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.41 2004/02/05 02:18:18 mpowers
- * Now setting border to null to new Aqua LAF behaves.
+ * Revision 1.41 2004/02/05 02:18:18 mpowers Now setting border to null to new
+ * Aqua LAF behaves.
*
- * Revision 1.40 2004/01/28 22:47:56 mpowers
- * un-activeUpdate was brokne.
+ * Revision 1.40 2004/01/28 22:47:56 mpowers un-activeUpdate was brokne.
*
- * Revision 1.39 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.39 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.38 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.38 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.37 2003/02/06 16:21:34 mpowers
- * Fix for activeUpdate: no longer bothering with editing context's changes.
+ * Revision 1.37 2003/02/06 16:21:34 mpowers Fix for activeUpdate: no longer
+ * bothering with editing context's changes.
*
- * Revision 1.36 2002/10/24 18:19:24 mpowers
- * Bug fix - thanks to dwang.
+ * Revision 1.36 2002/10/24 18:19:24 mpowers Bug fix - thanks to dwang.
*
- * Revision 1.35 2002/08/02 19:19:30 mpowers
- * Added control points for when to read or write from the display group.
- * Added flags needed to fix problems with non-activeUpdate and commit key.
+ * Revision 1.35 2002/08/02 19:19:30 mpowers Added control points for when to
+ * read or write from the display group. Added flags needed to fix problems with
+ * non-activeUpdate and commit key.
*
- * Revision 1.33 2002/03/08 23:18:01 mpowers
- * Added visible aspect.
+ * Revision 1.33 2002/03/08 23:18:01 mpowers Added visible aspect.
*
- * Revision 1.32 2002/03/06 16:13:53 mpowers
- * Yet another fix for style document changes: swing's DefaultStyledDocument
- * using an invoke later to launch a final StyleChanged event, which occurs
- * after the TextAssociation has reestablished itself as a document listener,
- * causing the item to be marked dirty. We're now handling this case.
+ * Revision 1.32 2002/03/06 16:13:53 mpowers Yet another fix for style document
+ * changes: swing's DefaultStyledDocument using an invoke later to launch a
+ * final StyleChanged event, which occurs after the TextAssociation has
+ * reestablished itself as a document listener, causing the item to be marked
+ * dirty. We're now handling this case.
*
- * Revision 1.31 2002/03/04 22:10:37 mpowers
- * Supressing active update only marks dirty when contents have changed.
+ * Revision 1.31 2002/03/04 22:10:37 mpowers Supressing active update only marks
+ * dirty when contents have changed.
*
- * Revision 1.30 2002/02/23 16:19:12 mpowers
- * Now only marking an editing context as dirty if it's not already dirty.
+ * Revision 1.30 2002/02/23 16:19:12 mpowers Now only marking an editing context
+ * as dirty if it's not already dirty.
*
- * Revision 1.29 2002/02/19 18:38:29 mpowers
- * Minor optimization: activeUpdate now checked in handleNotification.
+ * Revision 1.29 2002/02/19 18:38:29 mpowers Minor optimization: activeUpdate
+ * now checked in handleNotification.
*
- * Revision 1.28 2002/02/19 16:36:47 mpowers
- * Better support for active update: objects are now marked as changed
- * even though the model itself is not updated -- this allows editing
- * context itself to be marked as having changes to be saved.
+ * Revision 1.28 2002/02/19 16:36:47 mpowers Better support for active update:
+ * objects are now marked as changed even though the model itself is not updated
+ * -- this allows editing context itself to be marked as having changes to be
+ * saved.
*
- * Revision 1.27 2002/01/23 19:50:11 mpowers
- * Fix for a null pointer when value is null and last known type is not.
- * (from dwang)
+ * Revision 1.27 2002/01/23 19:50:11 mpowers Fix for a null pointer when value
+ * is null and last known type is not. (from dwang)
*
- * Revision 1.26 2002/01/14 19:37:22 mpowers
- * Fix for NPE when value is null and auto update is false.
+ * Revision 1.26 2002/01/14 19:37:22 mpowers Fix for NPE when value is null and
+ * auto update is false.
*
- * Revision 1.25 2001/12/10 03:16:11 mpowers
- * Fixed bug with isListening when no items are in display group.
+ * Revision 1.25 2001/12/10 03:16:11 mpowers Fixed bug with isListening when no
+ * items are in display group.
*
- * Revision 1.24 2001/11/16 19:14:51 mpowers
- * Brought back the idea of configuring whether updates occur on each change.
+ * Revision 1.24 2001/11/16 19:14:51 mpowers Brought back the idea of
+ * configuring whether updates occur on each change.
*
- * Revision 1.23 2001/11/08 20:06:06 mpowers
- * Now performing type-conversion as a convenience.
+ * Revision 1.23 2001/11/08 20:06:06 mpowers Now performing type-conversion as a
+ * convenience.
*
- * Revision 1.22 2001/11/04 18:24:20 mpowers
- * Better handling for non-string values when bulk-editing.
+ * Revision 1.22 2001/11/04 18:24:20 mpowers Better handling for non-string
+ * values when bulk-editing.
*
- * Revision 1.21 2001/11/01 15:53:34 mpowers
- * Now that NSNotificationQueue correctly implements PostWhenIdle, we can
- * finally discard our use of Swing's Timer in favor of using the queue
- * to coalesce document changed events.
+ * Revision 1.21 2001/11/01 15:53:34 mpowers Now that NSNotificationQueue
+ * correctly implements PostWhenIdle, we can finally discard our use of Swing's
+ * Timer in favor of using the queue to coalesce document changed events.
*
- * Revision 1.20 2001/10/26 19:58:06 mpowers
- * Better handling for non-string types. We were testing with equals with the
- * new value against the existing value in the component. Now we convert
- * the new value to a string before comparing. Fixes case for properties
- * of non-String types, like StringBuffer.
+ * Revision 1.20 2001/10/26 19:58:06 mpowers Better handling for non-string
+ * types. We were testing with equals with the new value against the existing
+ * value in the component. Now we convert the new value to a string before
+ * comparing. Fixes case for properties of non-String types, like StringBuffer.
*
- * Revision 1.19 2001/09/30 21:57:14 mpowers
- * Timers were not getting cleaned up if breakConnection was called
- * before the timer got a chance to fire.
+ * Revision 1.19 2001/09/30 21:57:14 mpowers Timers were not getting cleaned up
+ * if breakConnection was called before the timer got a chance to fire.
*
- * Revision 1.18 2001/08/22 15:42:26 mpowers
- * Added support for JTextComponent label-izing.
+ * Revision 1.18 2001/08/22 15:42:26 mpowers Added support for JTextComponent
+ * label-izing.
*
- * Revision 1.17 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.17 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.16 2001/07/17 19:53:37 mpowers
- * Made some private fields protected for benefit of subclassers.
+ * Revision 1.16 2001/07/17 19:53:37 mpowers Made some private fields protected
+ * for benefit of subclassers.
*
- * Revision 1.15 2001/06/30 14:59:36 mpowers
- * LabelAspect now sets the text field's opaque setting.
+ * Revision 1.15 2001/06/30 14:59:36 mpowers LabelAspect now sets the text
+ * field's opaque setting.
*
- * Revision 1.14 2001/06/29 14:54:08 mpowers
- * Another fix for timers - timers were definitely causing a memory leak.
+ * Revision 1.14 2001/06/29 14:54:08 mpowers Another fix for timers - timers
+ * were definitely causing a memory leak.
*
- * Revision 1.13 2001/06/26 21:37:19 mpowers
- * Fixed a null pointer in the new key timer scheme.
+ * Revision 1.13 2001/06/26 21:37:19 mpowers Fixed a null pointer in the new key
+ * timer scheme.
*
- * Revision 1.12 2001/06/25 14:46:03 mpowers
- * Fixed a memory leak involving the use of timers.
+ * Revision 1.12 2001/06/25 14:46:03 mpowers Fixed a memory leak involving the
+ * use of timers.
*
- * Revision 1.11 2001/06/01 19:14:59 mpowers
- * Text association's enabled aspect is now more discriminating.
+ * Revision 1.11 2001/06/01 19:14:59 mpowers Text association's enabled aspect
+ * is now more discriminating.
*
- * Revision 1.10 2001/05/18 21:07:24 mpowers
- * Changed the way we handle failure to update object value.
+ * Revision 1.10 2001/05/18 21:07:24 mpowers Changed the way we handle failure
+ * to update object value.
*
- * Revision 1.9 2001/03/13 21:39:58 mpowers
- * Improved validation handling.
+ * Revision 1.9 2001/03/13 21:39:58 mpowers Improved validation handling.
*
- * Revision 1.8 2001/03/12 12:49:10 mpowers
- * Improved validation handling.
- * Having a formatter disables auto-updating.
+ * Revision 1.8 2001/03/12 12:49:10 mpowers Improved validation handling. Having
+ * a formatter disables auto-updating.
*
- * Revision 1.7 2001/03/09 22:08:13 mpowers
- * Now handling any objects that have a valid Document.
- * No longer checking enabled before updating the enabled state.
+ * Revision 1.7 2001/03/09 22:08:13 mpowers Now handling any objects that have a
+ * valid Document. No longer checking enabled before updating the enabled state.
*
- * Revision 1.6 2001/03/07 19:57:32 mpowers
- * Fixed paste error in IconAspect.
+ * Revision 1.6 2001/03/07 19:57:32 mpowers Fixed paste error in IconAspect.
*
- * Revision 1.4 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.4 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.3 2001/01/31 19:12:33 mpowers
- * Implemented auto-updating in TextComponent.
+ * Revision 1.3 2001/01/31 19:12:33 mpowers Implemented auto-updating in
+ * TextComponent.
*
- * Revision 1.2 2001/01/10 15:53:58 mpowers
- * Preventing a null pointer exception if getText were to return null,
- * which doesn't happen for JTextFields but might happen for other objects.
+ * Revision 1.2 2001/01/10 15:53:58 mpowers Preventing a null pointer exception
+ * if getText were to return null, which doesn't happen for JTextFields but
+ * might happen for other objects.
*
- * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers Contributing wotonomy.
*
- * Revision 1.13 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.13 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java
index 49879e9..a6e993c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java
@@ -48,75 +48,51 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TimedTextAssociation works like TextAssociation,
-* but instead of using a delayed event to update the
-* model, it uses a timer so that the model is only
-* updated if the user pauses typing for some short interval.
-* This is useful when the update and/or re-read of the model
-* is a costly operation.
-* Bindings are:
-* <ul>
-* <li>value: a property convertable to/from a string</li>
-* <li>editable: a boolean property that determines whether
-* the user can edit the text in the field</li>
-* <li>enabled: a boolean property that determines whether
-* the user can select the text in the field</li>
-* <li>label: a boolean property that determines whether
-* field should appear as a read-only, selectable label</li>
-* <li>icon: a property that returns a Swing icon, for use
-* with JLabels and other components with setIcon() methods.
-* If bound to a static string, the string will be used to
-* load an image resource from the selected object's class.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TimedTextAssociation extends EOAssociation
- implements FocusListener, ActionListener, DocumentListener
-{
- //TODO: need to refactor this so that it can subclass text association.
- //This implementation is basically a branch from the v1.20 TextAssociation.
-
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EnabledAspect, EditableAspect, LabelAspect, IconAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature,
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "text", "enabled", "editable"
- } );
-
- private final static NSSelector getText =
- new NSSelector( "getText" );
- private final static NSSelector setText =
- new NSSelector( "setText",
- new Class[] { String.class } );
- private final static NSSelector getDocument =
- new NSSelector( "getDocument" );
- private final static NSSelector setIcon =
- new NSSelector( "setIcon",
- new Class[] { Icon.class } );
- private final static NSSelector addActionListener =
- new NSSelector( "addActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector removeActionListener =
- new NSSelector( "removeActionListener",
- new Class[] { ActionListener.class } );
- private final static NSSelector addFocusListener =
- new NSSelector( "addFocusListener",
- new Class[] { FocusListener.class } );
- private final static NSSelector removeFocusListener =
- new NSSelector( "removeFocusListener",
- new Class[] { FocusListener.class } );
+ * TimedTextAssociation works like TextAssociation, but instead of using a
+ * delayed event to update the model, it uses a timer so that the model is only
+ * updated if the user pauses typing for some short interval. This is useful
+ * when the update and/or re-read of the model is a costly operation. Bindings
+ * are:
+ * <ul>
+ * <li>value: a property convertable to/from a string</li>
+ * <li>editable: a boolean property that determines whether the user can edit
+ * the text in the field</li>
+ * <li>enabled: a boolean property that determines whether the user can select
+ * the text in the field</li>
+ * <li>label: a boolean property that determines whether field should appear as
+ * a read-only, selectable label</li>
+ * <li>icon: a property that returns a Swing icon, for use with JLabels and
+ * other components with setIcon() methods. If bound to a static string, the
+ * string will be used to load an image resource from the selected object's
+ * class.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TimedTextAssociation extends EOAssociation implements FocusListener, ActionListener, DocumentListener {
+ // TODO: need to refactor this so that it can subclass text association.
+ // This implementation is basically a branch from the v1.20 TextAssociation.
+
+ static final NSArray aspects = new NSArray(
+ new Object[] { ValueAspect, EnabledAspect, EditableAspect, LabelAspect, IconAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature,
+ AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "text", "enabled", "editable" });
+
+ private final static NSSelector getText = new NSSelector("getText");
+ private final static NSSelector setText = new NSSelector("setText", new Class[] { String.class });
+ private final static NSSelector getDocument = new NSSelector("getDocument");
+ private final static NSSelector setIcon = new NSSelector("setIcon", new Class[] { Icon.class });
+ private final static NSSelector addActionListener = new NSSelector("addActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector removeActionListener = new NSSelector("removeActionListener",
+ new Class[] { ActionListener.class });
+ private final static NSSelector addFocusListener = new NSSelector("addFocusListener",
+ new Class[] { FocusListener.class });
+ private final static NSSelector removeFocusListener = new NSSelector("removeFocusListener",
+ new Class[] { FocusListener.class });
// null handling
protected boolean wasNull;
@@ -125,227 +101,186 @@ public class TimedTextAssociation extends EOAssociation
// dirty handling
protected boolean needsUpdate;
protected boolean hasDocument;
- protected boolean isListening;
+ protected boolean isListening;
// formatting
protected Format format;
- // cache the value aspect
- private EODisplayGroup valueDisplayGroup;
- private String valueKey;
-
- // coalescing document events
- protected boolean autoUpdating;
- protected int interval = 400; // adjust as needed
- protected Timer keyTimer;
-
- // NOTE: a new key timer is created for each use and
- // is disposed when the timer is stopped.
- // Swing's Timer class is kept in a static list of timers
- // and each retains a strong reference to their listeners.
- // This caused a memory leak as associations typically
- // refer to their controlled component which is referred
- // to by its parents and so on until no application window
- // will ever get garbage collected. yikes.
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public TimedTextAssociation ( Object anObject )
- {
- super( anObject );
+ // cache the value aspect
+ private EODisplayGroup valueDisplayGroup;
+ private String valueKey;
+
+ // coalescing document events
+ protected boolean autoUpdating;
+ protected int interval = 400; // adjust as needed
+ protected Timer keyTimer;
+
+ // NOTE: a new key timer is created for each use and
+ // is disposed when the timer is stopped.
+ // Swing's Timer class is kept in a static list of timers
+ // and each retains a strong reference to their listeners.
+ // This caused a memory leak as associations typically
+ // refer to their controlled component which is referred
+ // to by its parents and so on until no application window
+ // will ever get garbage collected. yikes.
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public TimedTextAssociation(Object anObject) {
+ super(anObject);
wasNull = false;
needsUpdate = false;
hasDocument = false;
- isListening = true;
- valueDisplayGroup = null;
- valueKey = null;
-
- autoUpdating = true;
- keyTimer = null;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return setText.implementedByObject( anObject );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ValueAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( ValueAspect.equals( anAspect ) )
- {
+ isListening = true;
+ valueDisplayGroup = null;
+ valueKey = null;
+
+ autoUpdating = true;
+ keyTimer = null;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return setText.implementedByObject(anObject);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ValueAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (ValueAspect.equals(anAspect)) {
valueDisplayGroup = aDisplayGroup;
valueKey = aKey;
}
- super.bindAspect( anAspect, aDisplayGroup, aKey );
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
}
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * attempts to add this class as an ActionListener
- * and as a FocusListener to the specified object.
- */
- public void establishConnection ()
- {
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation attempts to add this class as an ActionListener and as a
+ * FocusListener to the specified object.
+ */
+ public void establishConnection() {
Object component = object();
- try
- {
- if ( addActionListener.implementedByObject( component ) )
- {
- addActionListener.invoke( component, this );
+ try {
+ if (addActionListener.implementedByObject(component)) {
+ addActionListener.invoke(component, this);
}
- if ( addFocusListener.implementedByObject( component ) )
- {
- addFocusListener.invoke( component, this );
+ if (addFocusListener.implementedByObject(component)) {
+ addFocusListener.invoke(component, this);
}
- hasDocument = false;
- if ( getDocument.implementedByObject( component ) )
- {
- Object document = getDocument.invoke( component );
- if ( document instanceof Document )
- {
- ((Document)document).addDocumentListener( this );
- hasDocument = true;
- }
+ hasDocument = false;
+ if (getDocument.implementedByObject(component)) {
+ Object document = getDocument.invoke(component);
+ if (document instanceof Document) {
+ ((Document) document).addDocumentListener(this);
+ hasDocument = true;
+ }
}
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while establishing connection", exc );
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while establishing connection", exc);
}
- super.establishConnection();
+ super.establishConnection();
// forces update from bindings
subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
Object component = object();
- try
- {
- if ( removeActionListener.implementedByObject( component ) )
- {
- removeActionListener.invoke( component, this );
+ try {
+ if (removeActionListener.implementedByObject(component)) {
+ removeActionListener.invoke(component, this);
}
- if ( removeFocusListener.implementedByObject( component ) )
- {
- removeFocusListener.invoke( component, this );
+ if (removeFocusListener.implementedByObject(component)) {
+ removeFocusListener.invoke(component, this);
}
- if ( getDocument.implementedByObject( component ) )
- {
- Object document = getDocument.invoke( component );
- if ( document instanceof Document )
- {
- ((Document)document).removeDocumentListener( this );
- }
+ if (getDocument.implementedByObject(component)) {
+ Object document = getDocument.invoke(component);
+ if (document instanceof Document) {
+ ((Document) document).removeDocumentListener(this);
+ }
}
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while breaking connection", exc);
}
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while breaking connection", exc );
- }
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
Object component = object();
EODisplayGroup displayGroup;
String key;
@@ -353,677 +288,538 @@ public class TimedTextAssociation extends EOAssociation
// value aspect
displayGroup = valueDisplayGroup;
- if ( displayGroup != null )
- {
- if ( component instanceof Component )
- {
- ((Component)component).setEnabled(
- displayGroup.enabledToSetSelectedObjectValueForKey( valueKey ) );
- }
-
+ if (displayGroup != null) {
+ if (component instanceof Component) {
+ ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(valueKey));
+ }
+
key = valueKey;
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- } else {
-
- // if there's only one object selected.
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking the size of selected objects in displayGroup
-
- // convert value to string
- if ( value == null )
- {
- wasNull = true;
- value = EMPTY_STRING;
- }
- else
- {
- wasNull = false;
- if ( format() != null )
- {
- try
- {
- value = format().format( value );
- }
- catch ( IllegalArgumentException exc )
- {
- value = value.toString();
- }
- }
- }
-
-
- try
- {
- if ( ! value.toString().equals( getText.invoke( component ) ) )
- {
- // No need to listen for any events that might get fired
- // while setting the text since we are the one setting it.
- boolean wasListening = isListening;
- isListening = false;
-
- // setText is an expensive operation
- setText.invoke( component, value.toString() );
-
- isListening = wasListening;
- needsUpdate = false;
- }
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else {
+
+ // if there's only one object selected.
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking the size of selected objects in displayGroup
+
+ // convert value to string
+ if (value == null) {
+ wasNull = true;
+ value = EMPTY_STRING;
+ } else {
+ wasNull = false;
+ if (format() != null) {
+ try {
+ value = format().format(value);
+ } catch (IllegalArgumentException exc) {
+ value = value.toString();
+ }
+ }
}
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection", exc );
+
+ try {
+ if (!value.toString().equals(getText.invoke(component))) {
+ // No need to listen for any events that might get fired
+ // while setting the text since we are the one setting it.
+ boolean wasListening = isListening;
+ isListening = false;
+
+ // setText is an expensive operation
+ setText.invoke(component, value.toString());
+
+ isListening = wasListening;
+ needsUpdate = false;
+ }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection", exc);
}
}
// icon aspect
- displayGroup = displayGroupForAspect( IconAspect );
- key = displayGroupKeyForAspect( IconAspect );
- if ( key != null )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
- // treat bound key without display group
- // as a resource to be loaded from the selected class.
- value = null;
- Object o = displayGroup.selectedObject();
- if ( o != null )
- {
- URL url = o.getClass().getResource( key );
- if ( url != null )
- {
- value = new ImageIcon( url );
- }
- }
+ displayGroup = displayGroupForAspect(IconAspect);
+ key = displayGroupKeyForAspect(IconAspect);
+ if (key != null) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
+ // treat bound key without display group
+ // as a resource to be loaded from the selected class.
+ value = null;
+ Object o = displayGroup.selectedObject();
+ if (o != null) {
+ URL url = o.getClass().getResource(key);
+ if (url != null) {
+ value = new ImageIcon(url);
+ }
+ }
}
- try
- {
- setIcon.invoke( component, value );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error while updating component connection", exc );
+ try {
+ setIcon.invoke(component, value);
+ } catch (Exception exc) {
+ throw new WotonomyException("Error while updating component connection", exc);
}
}
// enabled aspect
- displayGroup = displayGroupForAspect( EnabledAspect );
- key = displayGroupKeyForAspect( EnabledAspect );
- if ( ( key != null )
- && ( component instanceof Component ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(EnabledAspect);
+ key = displayGroupKeyForAspect(EnabledAspect);
+ if ((key != null) && (component instanceof Component)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
value = key;
}
- Boolean converted = null;
- if ( value != null )
- {
- converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
- }
- if ( converted == null ) converted = Boolean.FALSE;
- if ( ((Component)component).isEnabled() != converted.booleanValue() )
- {
- ((Component)component).setEnabled( converted.booleanValue() );
- }
+ Boolean converted = null;
+ if (value != null) {
+ converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+ }
+ if (converted == null)
+ converted = Boolean.FALSE;
+ if (((Component) component).isEnabled() != converted.booleanValue()) {
+ ((Component) component).setEnabled(converted.booleanValue());
+ }
}
// editable aspect
- displayGroup = displayGroupForAspect( EditableAspect );
- key = displayGroupKeyForAspect( EditableAspect );
- if ( ( key != null )
- && ( component instanceof JTextComponent ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(EditableAspect);
+ key = displayGroupKeyForAspect(EditableAspect);
+ if ((key != null) && (component instanceof JTextComponent)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
value = key;
}
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() != ((JTextComponent)component).isEditable() )
- {
- ((JTextComponent)component).setEditable( converted.booleanValue() );
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue() != ((JTextComponent) component).isEditable()) {
+ ((JTextComponent) component).setEditable(converted.booleanValue());
}
}
}
// label aspect
- displayGroup = displayGroupForAspect( LabelAspect );
- key = displayGroupKeyForAspect( LabelAspect );
-
- if ( ( key != null )
- && ( component instanceof JTextComponent ) )
- {
- if ( displayGroup != null )
- {
- value =
- displayGroup.selectedObjectValueForKey( key );
- }
- else
- {
+ displayGroup = displayGroupForAspect(LabelAspect);
+ key = displayGroupKeyForAspect(LabelAspect);
+
+ if ((key != null) && (component instanceof JTextComponent)) {
+ if (displayGroup != null) {
+ value = displayGroup.selectedObjectValueForKey(key);
+ } else {
// treat bound key without display group as a value
value = key;
}
- Boolean converted = (Boolean)
- ValueConverter.convertObjectToClass(
- value, Boolean.class );
-
- if ( converted != null )
- {
- if ( converted.booleanValue() )
- {
- if ( component instanceof JTextComponent )
- {
- if ( component instanceof JTextArea )
- {
- areaToLabel( (JTextArea) component );
- }
- else
- {
- fieldToLabel( (JTextComponent) component );
- }
- }
+ Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class);
+
+ if (converted != null) {
+ if (converted.booleanValue()) {
+ if (component instanceof JTextComponent) {
+ if (component instanceof JTextArea) {
+ areaToLabel((JTextArea) component);
+ } else {
+ fieldToLabel((JTextComponent) component);
+ }
+ }
+ } else {
+ if (component instanceof JTextComponent) {
+ if (component instanceof JTextArea) {
+ labelToArea((JTextArea) component);
+ } else {
+ labelToField((JTextComponent) component);
+ }
+ }
}
- else
- {
- if ( component instanceof JTextComponent )
- {
- if ( component instanceof JTextArea )
- {
- labelToArea( (JTextArea) component );
- }
- else
- {
- labelToField( (JTextComponent ) component );
- }
- }
- }
}
}
- }
+ }
- private void fieldToLabel( JTextComponent aTextField )
- {
- // turn on wrapping and disable editing and highlighting
+ private void fieldToLabel(JTextComponent aTextField) {
+ // turn on wrapping and disable editing and highlighting
- aTextField.setEditable(false);
- aTextField.setOpaque(false);
+ aTextField.setEditable(false);
+ aTextField.setOpaque(false);
- // Set the border, colors and font to that of a label
+ // Set the border, colors and font to that of a label
- LookAndFeel.installBorder(aTextField, "Label.border");
+ LookAndFeel.installBorder(aTextField, "Label.border");
- LookAndFeel.installColorsAndFont(aTextField,
- "Label.background",
- "Label.foreground",
- "Label.font");
- }
+ LookAndFeel.installColorsAndFont(aTextField, "Label.background", "Label.foreground", "Label.font");
+ }
- private void labelToField( JTextComponent aTextField )
- {
- // turn on wrapping and disable editing and highlighting
+ private void labelToField(JTextComponent aTextField) {
+ // turn on wrapping and disable editing and highlighting
- aTextField.setEditable(true);
- aTextField.setOpaque(true);
+ aTextField.setEditable(true);
+ aTextField.setOpaque(true);
- // Set the border, colors and font to that of a label
+ // Set the border, colors and font to that of a label
- LookAndFeel.installBorder(aTextField, "TextField.border");
+ LookAndFeel.installBorder(aTextField, "TextField.border");
- LookAndFeel.installColorsAndFont(aTextField,
- "TextField.background",
- "TextField.foreground",
- "TextField.font");
- }
+ LookAndFeel.installColorsAndFont(aTextField, "TextField.background", "TextField.foreground", "TextField.font");
+ }
- private void areaToLabel( JTextArea aTextArea )
- {
- // turn on wrapping and disable editing and highlighting
+ private void areaToLabel(JTextArea aTextArea) {
+ // turn on wrapping and disable editing and highlighting
- aTextArea.setLineWrap(true);
- aTextArea.setWrapStyleWord(true);
- aTextArea.setEditable(false);
+ aTextArea.setLineWrap(true);
+ aTextArea.setWrapStyleWord(true);
+ aTextArea.setEditable(false);
- // Set the text area's border, colors and font to
- // that of a label
+ // Set the text area's border, colors and font to
+ // that of a label
- LookAndFeel.installBorder(aTextArea, "Label.border");
+ LookAndFeel.installBorder(aTextArea, "Label.border");
- LookAndFeel.installColorsAndFont(aTextArea,
- "Label.background",
- "Label.foreground",
- "Label.font");
+ LookAndFeel.installColorsAndFont(aTextArea, "Label.background", "Label.foreground", "Label.font");
}
- private void labelToArea( JTextArea aTextArea )
- {
- // turn on wrapping and disable editing and highlighting
+ private void labelToArea(JTextArea aTextArea) {
+ // turn on wrapping and disable editing and highlighting
- aTextArea.setEditable(true);
+ aTextArea.setEditable(true);
- // Set the border, colors and font to that of a label
+ // Set the border, colors and font to that of a label
- LookAndFeel.installBorder(aTextArea, "TextArea.border");
+ LookAndFeel.installBorder(aTextArea, "TextArea.border");
- LookAndFeel.installColorsAndFont(aTextArea,
- "TextArea.background",
- "TextArea.foreground",
- "TextArea.font");
+ LookAndFeel.installColorsAndFont(aTextArea, "TextArea.background", "TextArea.foreground", "TextArea.font");
}
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
- if ( keyTimer != null )
- {
- keyTimer.stop();
- keyTimer.removeActionListener( this );
- keyTimer = null;
- }
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ if (keyTimer != null) {
+ keyTimer.stop();
+ keyTimer.removeActionListener(this);
+ keyTimer = null;
+ }
return writeValueToDisplayGroup();
- }
+ }
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueToDisplayGroup()
- {
- boolean returnValue = true;
- if ( hasDocument && !needsUpdate ) return true;
-
- EODisplayGroup displayGroup = valueDisplayGroup;
- if ( displayGroup != null )
- {
- String key = valueKey;
- Object component = object();
- Object value = null;
- try
- {
- //if ( getText.implementedByObject( component ) )
- //{
- value = getText.invoke( component );
- //}
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Error updating display group", exc );
- }
-
- if ( ( wasNull ) && ( EMPTY_STRING.equals( value ) ) )
- {
- value = null;
- }
- else
- if ( format() != null )
- {
- try
- {
- value = format().parseObject( value.toString() );
- }
- catch ( ParseException exc )
- {
- String message = exc.getMessage();
- //"That format was not recognized.";
- if ( displayGroup.associationFailedToValidateValue(
- this, value.toString(), key, exc, message ) )
- {
- boolean wasListening = isListening;
- isListening = false;
- JOptionPane.showMessageDialog(
- (Component)component, message );
- isListening = wasListening;
- }
- needsUpdate = false;
- return false;
- }
- }
-
- needsUpdate = false;
-
- // only update if the value is different from the one in the display group
- Object existingValue = displayGroup.selectedObjectValueForKey( key );
- if ( displayGroup.selectedObjects().size() == 1 )
- {
- if ( existingValue == value ) return true;
- if ( ( existingValue != null ) && ( existingValue.equals( value ) ) ) return true;
- if ( ( value != null ) && ( value.equals( existingValue ) ) ) return true;
- }
-
- // we might lose focus if display group displays a validation message
- boolean wasListening = isListening;
- isListening = false;
-
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- isListening = wasListening;
- needsUpdate = false;
- }
- else
- {
- isListening = wasListening;
- needsUpdate = false;
- returnValue = false;
- }
- }
-
- }
- return returnValue;
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueToDisplayGroup() {
+ boolean returnValue = true;
+ if (hasDocument && !needsUpdate)
+ return true;
+
+ EODisplayGroup displayGroup = valueDisplayGroup;
+ if (displayGroup != null) {
+ String key = valueKey;
+ Object component = object();
+ Object value = null;
+ try {
+ // if ( getText.implementedByObject( component ) )
+ // {
+ value = getText.invoke(component);
+ // }
+ } catch (Exception exc) {
+ throw new WotonomyException("Error updating display group", exc);
+ }
+
+ if ((wasNull) && (EMPTY_STRING.equals(value))) {
+ value = null;
+ } else if (format() != null) {
+ try {
+ value = format().parseObject(value.toString());
+ } catch (ParseException exc) {
+ String message = exc.getMessage();
+ // "That format was not recognized.";
+ if (displayGroup.associationFailedToValidateValue(this, value.toString(), key, exc, message)) {
+ boolean wasListening = isListening;
+ isListening = false;
+ JOptionPane.showMessageDialog((Component) component, message);
+ isListening = wasListening;
+ }
+ needsUpdate = false;
+ return false;
+ }
+ }
+
+ needsUpdate = false;
+
+ // only update if the value is different from the one in the display group
+ Object existingValue = displayGroup.selectedObjectValueForKey(key);
+ if (displayGroup.selectedObjects().size() == 1) {
+ if (existingValue == value)
+ return true;
+ if ((existingValue != null) && (existingValue.equals(value)))
+ return true;
+ if ((value != null) && (value.equals(existingValue)))
+ return true;
+ }
+
+ // we might lose focus if display group displays a validation message
+ boolean wasListening = isListening;
+ isListening = false;
+
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ isListening = wasListening;
+ needsUpdate = false;
+ } else {
+ isListening = wasListening;
+ needsUpdate = false;
+ returnValue = false;
+ }
+ }
+
+ }
+ return returnValue;
}
/**
- * Sets the Format that is used to convert values from the display
- * group to and from text that is displayed in the component.
- * Having a formatter disables auto-updating.
- */
- public void setFormat( Format aFormat )
- {
+ * Sets the Format that is used to convert values from the display group to and
+ * from text that is displayed in the component. Having a formatter disables
+ * auto-updating.
+ */
+ public void setFormat(Format aFormat) {
format = aFormat;
}
/**
- * Gets the Format that is used to convert values from the display
- * group to and from text that is displayed in the component.
- */
- public Format format()
- {
+ * Gets the Format that is used to convert values from the display group to and
+ * from text that is displayed in the component.
+ */
+ public Format format() {
return format;
}
- // interface ActionListener
+ // interface ActionListener
/**
- * Updates object on action performed.
- */
- public void actionPerformed( ActionEvent evt )
- {
- if ( keyTimer != null )
- {
- keyTimer.stop();
- keyTimer.removeActionListener( this );
- keyTimer = null;
- }
- if ( ! isListening ) return;
- if ( needsUpdate )
- {
- writeValueToDisplayGroup();
- }
+ * Updates object on action performed.
+ */
+ public void actionPerformed(ActionEvent evt) {
+ if (keyTimer != null) {
+ keyTimer.stop();
+ keyTimer.removeActionListener(this);
+ keyTimer = null;
+ }
+ if (!isListening)
+ return;
+ if (needsUpdate) {
+ writeValueToDisplayGroup();
+ }
}
- // interface FocusListener
+ // interface FocusListener
/**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
- if ( ! isListening ) return;
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
+ if (!isListening)
+ return;
Object o;
EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
}
}
- }
+ }
/**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( ! isListening ) return;
- if ( endEditing() )
- {
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (!isListening)
+ return;
+ if (endEditing()) {
Object o;
EODisplayGroup displayGroup;
Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
}
}
- }
- else
- {
+ } else {
// probably should notify of a validation error here,
}
- }
-
- /**
- * Returns whether the data model is updated for every change
- * in the controlled component. If false, the data is only
- * updated on focus lost or the enter key. Default is true.
- */
- public boolean isAutoUpdating()
- {
- if ( format() != null ) return false;
- return autoUpdating;
- }
-
- /**
- * Sets whether the data model is updated for every change
- * in the controlled component.
- */
- public void setAutoUpdating( boolean isAutoUpdating )
- {
- autoUpdating = isAutoUpdating;
- }
-
- /**
- * Triggers the key timer to start.
- */
- protected void queueUpdate()
- {
- if ( isAutoUpdating() )
- {
- if ( keyTimer == null )
- {
- keyTimer = new Timer( interval, this );
- }
- keyTimer.restart();
- }
- }
-
- // interface DocumentListener
-
- public void insertUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate();
- }
-
- public void removeUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate();
- }
-
- public void changedUpdate(DocumentEvent e)
- {
- if ( ! isListening ) return;
- needsUpdate = true;
- queueUpdate();
- }
+ }
+
+ /**
+ * Returns whether the data model is updated for every change in the controlled
+ * component. If false, the data is only updated on focus lost or the enter key.
+ * Default is true.
+ */
+ public boolean isAutoUpdating() {
+ if (format() != null)
+ return false;
+ return autoUpdating;
+ }
+
+ /**
+ * Sets whether the data model is updated for every change in the controlled
+ * component.
+ */
+ public void setAutoUpdating(boolean isAutoUpdating) {
+ autoUpdating = isAutoUpdating;
+ }
+
+ /**
+ * Triggers the key timer to start.
+ */
+ protected void queueUpdate() {
+ if (isAutoUpdating()) {
+ if (keyTimer == null) {
+ keyTimer = new Timer(interval, this);
+ }
+ keyTimer.restart();
+ }
+ }
+
+ // interface DocumentListener
+
+ public void insertUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate();
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate();
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ if (!isListening)
+ return;
+ needsUpdate = true;
+ queueUpdate();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2004/01/28 18:34:57 mpowers
- * Better handling for enabling.
- * Now respecting enabledToSetSelectedObjectValueForKey from display group.
+ * Revision 1.3 2004/01/28 18:34:57 mpowers Better handling for enabling. Now
+ * respecting enabledToSetSelectedObjectValueForKey from display group.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2001/12/20 18:57:24 mpowers
- * (Re-)Contributing TimedTextAssociation. Just like TA, except uses timers.
+ * Revision 1.1 2001/12/20 18:57:24 mpowers (Re-)Contributing
+ * TimedTextAssociation. Just like TA, except uses timers.
*
- * Revision 1.20 2001/10/26 19:58:06 mpowers
- * Better handling for non-string types. We were testing with equals with the
- * new value against the existing value in the component. Now we convert
- * the new value to a string before comparing. Fixes case for properties
- * of non-String types, like StringBuffer.
+ * Revision 1.20 2001/10/26 19:58:06 mpowers Better handling for non-string
+ * types. We were testing with equals with the new value against the existing
+ * value in the component. Now we convert the new value to a string before
+ * comparing. Fixes case for properties of non-String types, like StringBuffer.
*
- * Revision 1.19 2001/09/30 21:57:14 mpowers
- * Timers were not getting cleaned up if breakConnection was called
- * before the timer got a chance to fire.
+ * Revision 1.19 2001/09/30 21:57:14 mpowers Timers were not getting cleaned up
+ * if breakConnection was called before the timer got a chance to fire.
*
- * Revision 1.18 2001/08/22 15:42:26 mpowers
- * Added support for JTextComponent label-izing.
+ * Revision 1.18 2001/08/22 15:42:26 mpowers Added support for JTextComponent
+ * label-izing.
*
- * Revision 1.17 2001/07/30 16:32:55 mpowers
- * Implemented support for bulk-editing. Detail associations will now
- * apply changes to all selected objects.
+ * Revision 1.17 2001/07/30 16:32:55 mpowers Implemented support for
+ * bulk-editing. Detail associations will now apply changes to all selected
+ * objects.
*
- * Revision 1.16 2001/07/17 19:53:37 mpowers
- * Made some private fields protected for benefit of subclassers.
+ * Revision 1.16 2001/07/17 19:53:37 mpowers Made some private fields protected
+ * for benefit of subclassers.
*
- * Revision 1.15 2001/06/30 14:59:36 mpowers
- * LabelAspect now sets the text field's opaque setting.
+ * Revision 1.15 2001/06/30 14:59:36 mpowers LabelAspect now sets the text
+ * field's opaque setting.
*
- * Revision 1.14 2001/06/29 14:54:08 mpowers
- * Another fix for timers - timers were definitely causing a memory leak.
+ * Revision 1.14 2001/06/29 14:54:08 mpowers Another fix for timers - timers
+ * were definitely causing a memory leak.
*
- * Revision 1.13 2001/06/26 21:37:19 mpowers
- * Fixed a null pointer in the new key timer scheme.
+ * Revision 1.13 2001/06/26 21:37:19 mpowers Fixed a null pointer in the new key
+ * timer scheme.
*
- * Revision 1.12 2001/06/25 14:46:03 mpowers
- * Fixed a memory leak involving the use of timers.
+ * Revision 1.12 2001/06/25 14:46:03 mpowers Fixed a memory leak involving the
+ * use of timers.
*
- * Revision 1.11 2001/06/01 19:14:59 mpowers
- * Text association's enabled aspect is now more discriminating.
+ * Revision 1.11 2001/06/01 19:14:59 mpowers Text association's enabled aspect
+ * is now more discriminating.
*
- * Revision 1.10 2001/05/18 21:07:24 mpowers
- * Changed the way we handle failure to update object value.
+ * Revision 1.10 2001/05/18 21:07:24 mpowers Changed the way we handle failure
+ * to update object value.
*
- * Revision 1.9 2001/03/13 21:39:58 mpowers
- * Improved validation handling.
+ * Revision 1.9 2001/03/13 21:39:58 mpowers Improved validation handling.
*
- * Revision 1.8 2001/03/12 12:49:10 mpowers
- * Improved validation handling.
- * Having a formatter disables auto-updating.
+ * Revision 1.8 2001/03/12 12:49:10 mpowers Improved validation handling. Having
+ * a formatter disables auto-updating.
*
- * Revision 1.7 2001/03/09 22:08:13 mpowers
- * Now handling any objects that have a valid Document.
- * No longer checking enabled before updating the enabled state.
+ * Revision 1.7 2001/03/09 22:08:13 mpowers Now handling any objects that have a
+ * valid Document. No longer checking enabled before updating the enabled state.
*
- * Revision 1.6 2001/03/07 19:57:32 mpowers
- * Fixed paste error in IconAspect.
+ * Revision 1.6 2001/03/07 19:57:32 mpowers Fixed paste error in IconAspect.
*
- * Revision 1.4 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.4 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.3 2001/01/31 19:12:33 mpowers
- * Implemented auto-updating in TextComponent.
+ * Revision 1.3 2001/01/31 19:12:33 mpowers Implemented auto-updating in
+ * TextComponent.
*
- * Revision 1.2 2001/01/10 15:53:58 mpowers
- * Preventing a null pointer exception if getText were to return null,
- * which doesn't happen for JTextFields but might happen for other objects.
+ * Revision 1.2 2001/01/10 15:53:58 mpowers Preventing a null pointer exception
+ * if getText were to return null, which doesn't happen for JTextFields but
+ * might happen for other objects.
*
- * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers Contributing wotonomy.
*
- * Revision 1.13 2000/12/20 16:25:41 michael
- * Added log to all files.
+ * Revision 1.13 2000/12/20 16:25:41 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeAssociation.java
index 728643b..b0e3b09 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeAssociation.java
@@ -39,172 +39,144 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TreeAssociation is a TreeModelAssociation further
-* customized for JTrees. It binds a JTree to a display group's
-* list of displayable objects, each of which may have
-* a list of child objects managed by another display
-* group, and so on. TreeAssociation works exactly
-* like a ListAssociation, with the additional capability
-* to specify a "Children" aspect, that will allow child
-* objects to be retrieved from a parent display group.
-* Note that the children aspect requires the bound
-* display group to have a DataSource that can vend a
-* DataSource appropriate for the bound key That data
-* source is then used to create data sources for
-* child nodes, and so on.
-*
-* <ul>
-*
-* <li>titles: a property convertable to a string for
-* display in the nodes of the tree. The objects in
-* the bound display group will be used to populate the
-* initial root nodes of the tree (more accurately,
-* children of the offscreen root node in the tree).</li>
-*
-* <li>children: a property of a node value that returns
-* zero, one or many objects, each of which will correspond
-* to a child node for the corresponding node in the tree.
-* The data source of the bound display group is replaced
-* a data source that populates the display group with
-* the visible nodes in the tree component as determined by
-* calling fetchObjectsIntoChildrenGroup.
-* If this aspect is not bound, the tree behaves like a list.
-* <br><br>
-* Binding this aspect with a null display group is the same
-* as binding it with the titles display group.
-* In this configuration the contents of the titles
-* display group will be replaced with the visible nodes in the
-* tree component, as specified above, replacing the existing
-* data source.
-* <br><br>
-* In that case, the display groups for the nodes in
-* the tree will still use the original data source
-* for resolving their children key, and programmatically
-* setting the contents of the display group will still
-* repopulate the root nodes of the tree.
-* </li>
-*
-* <li>isLeaf: a property of a node value that returns
-* a value convertable to a boolean value (aside from
-* an actual boolean value, zeroes evaluate to true,
-* as does any String containing "yes" or "true" or that
-* is convertable to a number equal to zero; other values
-* evaluate to false).
-* <br><br>
-* If the isLeaf aspect is not bound,
-* the tree must force nodes to load their children to
-* determine whether they are leaf nodes (in effect
-* loading the grandchildren for any expanded node).
-* If bound, child loading is deferred until the node
-* is actually expanded.
-* <br><br>
-* For example, binding this value to a null
-* display group and the key "false" will result in a
-* deferred-loading tree that works much like Windows
-* Explorer's network volume browser - all nodes appear
-* with "pluses" until they are expanded.
-* <br><br>
-* Note that the display group is ignored: the property
-* will be applied directly to the object corresponding
-* to the node.</li>
-*
-* </ul>
-*
-* All other usage is as TreeModelAssociation.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * TreeAssociation is a TreeModelAssociation further customized for JTrees. It
+ * binds a JTree to a display group's list of displayable objects, each of which
+ * may have a list of child objects managed by another display group, and so on.
+ * TreeAssociation works exactly like a ListAssociation, with the additional
+ * capability to specify a "Children" aspect, that will allow child objects to
+ * be retrieved from a parent display group. Note that the children aspect
+ * requires the bound display group to have a DataSource that can vend a
+ * DataSource appropriate for the bound key That data source is then used to
+ * create data sources for child nodes, and so on.
+ *
+ * <ul>
+ *
+ * <li>titles: a property convertable to a string for display in the nodes of
+ * the tree. The objects in the bound display group will be used to populate the
+ * initial root nodes of the tree (more accurately, children of the offscreen
+ * root node in the tree).</li>
+ *
+ * <li>children: a property of a node value that returns zero, one or many
+ * objects, each of which will correspond to a child node for the corresponding
+ * node in the tree. The data source of the bound display group is replaced a
+ * data source that populates the display group with the visible nodes in the
+ * tree component as determined by calling fetchObjectsIntoChildrenGroup. If
+ * this aspect is not bound, the tree behaves like a list. <br>
+ * <br>
+ * Binding this aspect with a null display group is the same as binding it with
+ * the titles display group. In this configuration the contents of the titles
+ * display group will be replaced with the visible nodes in the tree component,
+ * as specified above, replacing the existing data source. <br>
+ * <br>
+ * In that case, the display groups for the nodes in the tree will still use the
+ * original data source for resolving their children key, and programmatically
+ * setting the contents of the display group will still repopulate the root
+ * nodes of the tree.</li>
+ *
+ * <li>isLeaf: a property of a node value that returns a value convertable to a
+ * boolean value (aside from an actual boolean value, zeroes evaluate to true,
+ * as does any String containing "yes" or "true" or that is convertable to a
+ * number equal to zero; other values evaluate to false). <br>
+ * <br>
+ * If the isLeaf aspect is not bound, the tree must force nodes to load their
+ * children to determine whether they are leaf nodes (in effect loading the
+ * grandchildren for any expanded node). If bound, child loading is deferred
+ * until the node is actually expanded. <br>
+ * <br>
+ * For example, binding this value to a null display group and the key "false"
+ * will result in a deferred-loading tree that works much like Windows
+ * Explorer's network volume browser - all nodes appear with "pluses" until they
+ * are expanded. <br>
+ * <br>
+ * Note that the display group is ignored: the property will be applied directly
+ * to the object corresponding to the node.</li>
+ *
+ * </ul>
+ *
+ * All other usage is as TreeModelAssociation.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class TreeAssociation extends TreeModelAssociation
- implements FocusListener, TreeExpansionListener, TreeWillExpandListener, Runnable
-{
- private boolean isExpanding;
- private Vector nodeQueue;
- private Vector structureQueue;
- private boolean isRunning;
-
- /**
- * Constructor expecting a JTree.
- */
- public TreeAssociation ( Object anObject )
- {
- super( anObject );
- init();
- }
-
- /**
- * Constructor expecting a JTree or similar component
- * and specifying a label for the root node.
- */
- public TreeAssociation( Object anObject, Object aRootLabel )
- {
- super( anObject );
- init();
- rootLabel = aRootLabel;
- rootNode.setUserObject( aRootLabel );
- }
-
- // convenience
- private JTree component()
- {
- return (JTree) object();
- }
-
- /**
- * Called by both constructors.
- */
- protected void init()
- {
- isExpanding = false;
- isRunning = false;
- nodeQueue = new Vector();
- structureQueue = new Vector();
- component().addFocusListener( this );
- component().addTreeExpansionListener( this );
- component().addTreeWillExpandListener( this );
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof JTree );
- }
-
- /**
- * Overridden to not fire events during initial population.
- */
- public void establishConnection ()
- {
- isExpanding = true;
- super.establishConnection();
- isExpanding = false;
- }
-
- // interface TreeSelectionListener
-
- public void valueChanged(TreeSelectionEvent e)
- {
- if ( ! isListening ) return;
+ implements FocusListener, TreeExpansionListener, TreeWillExpandListener, Runnable {
+ private boolean isExpanding;
+ private Vector nodeQueue;
+ private Vector structureQueue;
+ private boolean isRunning;
+
+ /**
+ * Constructor expecting a JTree.
+ */
+ public TreeAssociation(Object anObject) {
+ super(anObject);
+ init();
+ }
+
+ /**
+ * Constructor expecting a JTree or similar component and specifying a label for
+ * the root node.
+ */
+ public TreeAssociation(Object anObject, Object aRootLabel) {
+ super(anObject);
+ init();
+ rootLabel = aRootLabel;
+ rootNode.setUserObject(aRootLabel);
+ }
+
+ // convenience
+ private JTree component() {
+ return (JTree) object();
+ }
+
+ /**
+ * Called by both constructors.
+ */
+ protected void init() {
+ isExpanding = false;
+ isRunning = false;
+ nodeQueue = new Vector();
+ structureQueue = new Vector();
+ component().addFocusListener(this);
+ component().addTreeExpansionListener(this);
+ component().addTreeWillExpandListener(this);
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof JTree);
+ }
+
+ /**
+ * Overridden to not fire events during initial population.
+ */
+ public void establishConnection() {
+ isExpanding = true;
+ super.establishConnection();
+ isExpanding = false;
+ }
+
+ // interface TreeSelectionListener
+
+ public void valueChanged(TreeSelectionEvent e) {
+ if (!isListening)
+ return;
// NOTE: This approach causes focus rectangle to perceptibly trail
// the selection rectangle, presumably because we're called after the
// new selection has been processed but before the focus is processed.
// Users don't like it, so we're going with a preference to use
// invokeLater.
-/*
- // paint immediately before updating the display group and
- // before any potentially lengthy second-order effects happen:
- // this improves user-perceived responsiveness of big apps
- if ( object() instanceof javax.swing.JComponent )
- {
- javax.swing.JComponent component = (javax.swing.JComponent)object();
- component.paintImmediately( component.getBounds() );
- }
- selectFromSelectionModel();
-*/
+ /*
+ * // paint immediately before updating the display group and // before any
+ * potentially lengthy second-order effects happen: // this improves
+ * user-perceived responsiveness of big apps if ( object() instanceof
+ * javax.swing.JComponent ) { javax.swing.JComponent component =
+ * (javax.swing.JComponent)object(); component.paintImmediately(
+ * component.getBounds() ); } selectFromSelectionModel();
+ */
// NOTE: This approach uses invoke later to cause the update of
// the display group (which could be lengthly if that in turn
@@ -214,369 +186,291 @@ public class TreeAssociation extends TreeModelAssociation
// will have to do a similar invoke later if they check the display
// group.
- Runnable select = new Runnable()
- {
- public void run()
- {
- selectFromSelectionModel();
- }
- };
-
- if ( selectionPaintedImmediately )
- {
- if ( object() instanceof java.awt.Component )
- {
- ((java.awt.Component)object()).repaint();
- }
- EventQueue.invokeLater( select );
- }
- else
- {
- select.run();
- }
- }
-
- /**
- * Overridden to check whether the node is visible
- * in the tree on screen. Offscreen in a scrollpane
- * does not count.
- */
- public boolean isVisible(Object node)
- {
- JTree tree = (JTree) object();
- TreePath path = ((DisplayGroupNode)node).treePath();
- if ( tree.isVisible( path ) )
- {
- Rectangle rowRect = tree.getPathBounds( path );
- if ( rowRect != null )
- {
- Rectangle visible = tree.getVisibleRect();
- if ( visible != null )
- {
+ Runnable select = new Runnable() {
+ public void run() {
+ selectFromSelectionModel();
+ }
+ };
+
+ if (selectionPaintedImmediately) {
+ if (object() instanceof java.awt.Component) {
+ ((java.awt.Component) object()).repaint();
+ }
+ EventQueue.invokeLater(select);
+ } else {
+ select.run();
+ }
+ }
+
+ /**
+ * Overridden to check whether the node is visible in the tree on screen.
+ * Offscreen in a scrollpane does not count.
+ */
+ public boolean isVisible(Object node) {
+ JTree tree = (JTree) object();
+ TreePath path = ((DisplayGroupNode) node).treePath();
+ if (tree.isVisible(path)) {
+ Rectangle rowRect = tree.getPathBounds(path);
+ if (rowRect != null) {
+ Rectangle visible = tree.getVisibleRect();
+ if (visible != null) {
//System.out.println( "isVisible: intersects: " + visible.intersects( rowRect ) );
- return visible.intersects( rowRect );
- }
- }
- }
+ return visible.intersects(rowRect);
+ }
+ }
+ }
//System.out.println( "isVisible: false" );
- return false;
- }
-
- /**
- * Fires a tree nodes changed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesChanged(final Object source,
- final Object[] path,
- final int[] childIndices,
- final Object[] children)
- {
- if ( !isExpanding )
- {
- for ( int i = 0; i < children.length; i++ )
- {
- nodeQueue.add( children[i] );
- }
- if ( !isRunning )
- {
- isRunning = true;
- EventQueue.invokeLater( this );
- }
- }
- }
-
- /**
- * Fires a tree nodes inserted event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesInserted(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
- if ( !isExpanding )
- {
- super.fireTreeNodesInserted( source, path, childIndices, children );
- EventQueue.invokeLater( this );
- }
- }
-
- /**
- * Fires a tree nodes removed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesRemoved(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
- if ( !isExpanding )
- {
- super.fireTreeNodesRemoved( source, path, childIndices, children );
- EventQueue.invokeLater( this );
- }
- }
-
- /**
- * Fires a tree structure changed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeStructureChanged(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
- if ( !isExpanding )
- {
- structureQueue.add( path[path.length-1] );
- if ( !isRunning )
- {
- isRunning = true;
- EventQueue.invokeLater( this );
- }
- }
- }
-
- /**
- * Overridden to return all visible rows in the tree.
- */
- public NSArray objectsFetchedIntoChildrenGroup()
- {
- JTree tree = (JTree) object();
- NSMutableArray objectList = new NSMutableArray();
-
- int count = tree.getRowCount();
- for ( int i = 0; i < count; i++ )
- {
- objectList.add(
- ((DisplayGroupNode) tree.getPathForRow( i ).getLastPathComponent()).object() );
- }
+ return false;
+ }
+
+ /**
+ * Fires a tree nodes changed event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesChanged(final Object source, final Object[] path, final int[] childIndices,
+ final Object[] children) {
+ if (!isExpanding) {
+ for (int i = 0; i < children.length; i++) {
+ nodeQueue.add(children[i]);
+ }
+ if (!isRunning) {
+ isRunning = true;
+ EventQueue.invokeLater(this);
+ }
+ }
+ }
+
+ /**
+ * Fires a tree nodes inserted event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) {
+ if (!isExpanding) {
+ super.fireTreeNodesInserted(source, path, childIndices, children);
+ EventQueue.invokeLater(this);
+ }
+ }
+
+ /**
+ * Fires a tree nodes removed event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) {
+ if (!isExpanding) {
+ super.fireTreeNodesRemoved(source, path, childIndices, children);
+ EventQueue.invokeLater(this);
+ }
+ }
+
+ /**
+ * Fires a tree structure changed event to all listeners. Provided as a
+ * convenience if you need to make manual changes to the tree model.
+ */
+ public void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
+ if (!isExpanding) {
+ structureQueue.add(path[path.length - 1]);
+ if (!isRunning) {
+ isRunning = true;
+ EventQueue.invokeLater(this);
+ }
+ }
+ }
+
+ /**
+ * Overridden to return all visible rows in the tree.
+ */
+ public NSArray objectsFetchedIntoChildrenGroup() {
+ JTree tree = (JTree) object();
+ NSMutableArray objectList = new NSMutableArray();
+
+ int count = tree.getRowCount();
+ for (int i = 0; i < count; i++) {
+ objectList.add(((DisplayGroupNode) tree.getPathForRow(i).getLastPathComponent()).object());
+ }
//new net.wotonomy.ui.swing.util.StackTraceInspector( Integer.toString( objectList.size() ) );
- return objectList;
- }
+ return objectList;
+ }
+
+ // interface FocusListener
- // interface FocusListener
-
/**
- * Notifies of beginning of edit.
- */
- public void focusGained(FocusEvent evt)
- {
+ * Notifies of beginning of edit.
+ */
+ public void focusGained(FocusEvent evt) {
Object o;
EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidBeginEditing( this );
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidBeginEditing(this);
}
}
- }
+ }
/**
- * Updates object on focus lost and notifies of end of edit.
- */
- public void focusLost(FocusEvent evt)
- {
- if ( ! component().isEditing() )
- {
- Object o;
- EODisplayGroup displayGroup;
- Enumeration e = aspects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- displayGroup =
- displayGroupForAspect( e.nextElement().toString() );
- if ( displayGroup != null )
- {
- displayGroup.associationDidEndEditing( this );
- }
- }
- }
- }
-
- // interface TreeWillExpandListener
-
- public void treeWillExpand(TreeExpansionEvent event)
- throws ExpandVetoException
- {
- isExpanding = true;
- }
-
- public void treeWillCollapse(TreeExpansionEvent event)
- throws ExpandVetoException
- {
- // do nothing
- }
-
- // interface TreeExpansionListener
-
- /**
- * Updates the children display group, if any.
- */
- public void treeExpanded(TreeExpansionEvent event)
- { //System.out.println( "treeExpanded: " + event.getPath().getLastPathComponent() );
- isExpanding = false;
- if ( childrenDisplayGroup != null )
- {
- removeAsListener(); // prevent data source refetch: see fetchObjects()
- childrenDisplayGroup.fetch();
- addAsListener();
- }
- }
-
- /**
- * Updates the children display group, if any.
- */
- public void treeCollapsed(TreeExpansionEvent event)
- {
- if ( childrenDisplayGroup != null )
- {
- removeAsListener(); // prevent data source refetch: see fetchObjects()
- childrenDisplayGroup.fetch();
- addAsListener();
- }
- }
-
- // interface Runnable
-
- /**
- * Fires any queued node changed and structure changed events.
- * Typically invoked on a delayed event loop.
- */
- public void run()
- {
- DisplayGroupNode node;
- int index;
- Iterator i;
-
- i = nodeQueue.iterator();
- while ( i.hasNext() )
- {
- node = (DisplayGroupNode) i.next();
- index = ((DisplayGroupNode)node.parentGroup).getIndex( node );
- if ( ( index != -1 )
- && ( node.treePath().getParentPath() != null ) )
- {
- super.fireTreeNodesChanged(
- node,
- node.treePath().getParentPath().getPath(),
- new int[] { index },
- new Object[] { node } );
- }
- }
- nodeQueue.clear();
-
- i = structureQueue.iterator();
- while ( i.hasNext() )
- {
- node = (DisplayGroupNode) i.next();
- super.fireTreeStructureChanged(
- node,
- node.treePath().getPath(),
- null,
- null );
- }
- structureQueue.clear();
-
- isRunning = false;
-/*
- EventQueue.invokeLater( new Runnable() { public void run() {
- ((JTree)object()).treeDidChange();
- ((JTree)object()).getParent().invalidate();
- ((JTree)object()).getParent().validate();
- ((JTree)object()).getParent().update( ((JTree)object()).getGraphics() );
-
-// ((JTree)object()).getParent().doLayout();
-// ((JTree)object()).getParent().repaint();
-// ((JTree)object()).repaint();
-// ((JTree)object()).updateUI();
- } } );
-*/
- }
+ * Updates object on focus lost and notifies of end of edit.
+ */
+ public void focusLost(FocusEvent evt) {
+ if (!component().isEditing()) {
+ Object o;
+ EODisplayGroup displayGroup;
+ Enumeration e = aspects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ displayGroup = displayGroupForAspect(e.nextElement().toString());
+ if (displayGroup != null) {
+ displayGroup.associationDidEndEditing(this);
+ }
+ }
+ }
+ }
+
+ // interface TreeWillExpandListener
+
+ public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+ isExpanding = true;
+ }
+
+ public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+ // do nothing
+ }
+
+ // interface TreeExpansionListener
+
+ /**
+ * Updates the children display group, if any.
+ */
+ public void treeExpanded(TreeExpansionEvent event) { // System.out.println( "treeExpanded: " +
+ // event.getPath().getLastPathComponent() );
+ isExpanding = false;
+ if (childrenDisplayGroup != null) {
+ removeAsListener(); // prevent data source refetch: see fetchObjects()
+ childrenDisplayGroup.fetch();
+ addAsListener();
+ }
+ }
+
+ /**
+ * Updates the children display group, if any.
+ */
+ public void treeCollapsed(TreeExpansionEvent event) {
+ if (childrenDisplayGroup != null) {
+ removeAsListener(); // prevent data source refetch: see fetchObjects()
+ childrenDisplayGroup.fetch();
+ addAsListener();
+ }
+ }
+
+ // interface Runnable
+
+ /**
+ * Fires any queued node changed and structure changed events. Typically invoked
+ * on a delayed event loop.
+ */
+ public void run() {
+ DisplayGroupNode node;
+ int index;
+ Iterator i;
+
+ i = nodeQueue.iterator();
+ while (i.hasNext()) {
+ node = (DisplayGroupNode) i.next();
+ index = ((DisplayGroupNode) node.parentGroup).getIndex(node);
+ if ((index != -1) && (node.treePath().getParentPath() != null)) {
+ super.fireTreeNodesChanged(node, node.treePath().getParentPath().getPath(), new int[] { index },
+ new Object[] { node });
+ }
+ }
+ nodeQueue.clear();
+
+ i = structureQueue.iterator();
+ while (i.hasNext()) {
+ node = (DisplayGroupNode) i.next();
+ super.fireTreeStructureChanged(node, node.treePath().getPath(), null, null);
+ }
+ structureQueue.clear();
+
+ isRunning = false;
+ /*
+ * EventQueue.invokeLater( new Runnable() { public void run() {
+ * ((JTree)object()).treeDidChange();
+ * ((JTree)object()).getParent().invalidate();
+ * ((JTree)object()).getParent().validate();
+ * ((JTree)object()).getParent().update( ((JTree)object()).getGraphics() );
+ *
+ * // ((JTree)object()).getParent().doLayout(); //
+ * ((JTree)object()).getParent().repaint(); // ((JTree)object()).repaint(); //
+ * ((JTree)object()).updateUI(); } } );
+ */
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.55 2004/02/05 02:18:50 mpowers
- * Super was calling back into this class before init() was called.
+ * Revision 1.55 2004/02/05 02:18:50 mpowers Super was calling back into this
+ * class before init() was called.
*
- * Revision 1.54 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.54 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.53 2003/06/03 14:49:48 mpowers
- * Now correctly calculating isVisible based on the component visible rect.
- * Now deferring node changed events to a later event queue to allow repaints
- * to happen after all changes have taken effect.
+ * Revision 1.53 2003/06/03 14:49:48 mpowers Now correctly calculating isVisible
+ * based on the component visible rect. Now deferring node changed events to a
+ * later event queue to allow repaints to happen after all changes have taken
+ * effect.
*
- * Revision 1.52 2002/05/03 21:41:18 mpowers
- * No longer clearing the selection model when updating from display group:
- * we now only modify if a change needs to be made.
- * No longer listening for selection change during firing of delete events:
- * delete events cause JTree's to update their selection model.
- * Fix for paintsSelectionImmediately: TreeAssociation.processRecentChanges()
- * must happen after the screen is painted, or the selection is not displayed.
+ * Revision 1.52 2002/05/03 21:41:18 mpowers No longer clearing the selection
+ * model when updating from display group: we now only modify if a change needs
+ * to be made. No longer listening for selection change during firing of delete
+ * events: delete events cause JTree's to update their selection model. Fix for
+ * paintsSelectionImmediately: TreeAssociation.processRecentChanges() must
+ * happen after the screen is painted, or the selection is not displayed.
*
- * Revision 1.51 2002/04/19 21:18:45 mpowers
- * Removed tree event coalescing, which was causing way too many problems.
- * The fireChangeEvent algorithm is way faster than before, so we should
- * still be better off than before. At least now, we don't have to track
- * whether the view component has encountered a particular node.
+ * Revision 1.51 2002/04/19 21:18:45 mpowers Removed tree event coalescing,
+ * which was causing way too many problems. The fireChangeEvent algorithm is way
+ * faster than before, so we should still be better off than before. At least
+ * now, we don't have to track whether the view component has encountered a
+ * particular node.
*
- * Revision 1.49 2002/04/12 21:05:58 mpowers
- * Now distinguishing changes in titles group even better.
+ * Revision 1.49 2002/04/12 21:05:58 mpowers Now distinguishing changes in
+ * titles group even better.
*
- * Revision 1.48 2002/04/12 20:36:31 mpowers
- * Now distinguishing between changes made on titles group by tree expansion
- * versus external changes which should cause us to repopulate root nodes.
+ * Revision 1.48 2002/04/12 20:36:31 mpowers Now distinguishing between changes
+ * made on titles group by tree expansion versus external changes which should
+ * cause us to repopulate root nodes.
*
- * Revision 1.47 2002/04/10 21:20:04 mpowers
- * Better handling for tree nodes when working with editing contexts.
- * Better handling for invalidation. No longer broadcasting events
- * when nodes have not been "registered" in the tree.
+ * Revision 1.47 2002/04/10 21:20:04 mpowers Better handling for tree nodes when
+ * working with editing contexts. Better handling for invalidation. No longer
+ * broadcasting events when nodes have not been "registered" in the tree.
*
- * Revision 1.46 2002/03/27 20:44:53 mpowers
- * Added isVisible test for node.
+ * Revision 1.46 2002/03/27 20:44:53 mpowers Added isVisible test for node.
*
- * Revision 1.45 2002/03/08 23:19:57 mpowers
- * Refactoring of DelegatingTreeDataSource to facilitate binding of titles
- * and children aspects to the same display group.
+ * Revision 1.45 2002/03/08 23:19:57 mpowers Refactoring of
+ * DelegatingTreeDataSource to facilitate binding of titles and children aspects
+ * to the same display group.
*
- * Revision 1.44 2002/03/07 23:04:36 mpowers
- * Refining TreeColumnAssociation.
+ * Revision 1.44 2002/03/07 23:04:36 mpowers Refining TreeColumnAssociation.
*
- * Revision 1.43 2002/03/06 13:04:15 mpowers
- * Implemented cascading qualifiers in tree nodes.
+ * Revision 1.43 2002/03/06 13:04:15 mpowers Implemented cascading qualifiers in
+ * tree nodes.
*
- * Revision 1.42 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.42 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.41 2002/03/01 23:42:08 mpowers
- * Implemented TreeColumnAssociation, and updated documentation.
+ * Revision 1.41 2002/03/01 23:42:08 mpowers Implemented TreeColumnAssociation,
+ * and updated documentation.
*
- * Revision 1.40 2002/03/01 20:41:39 mpowers
- * Now a focus listener and an expansion listener.
+ * Revision 1.40 2002/03/01 20:41:39 mpowers Now a focus listener and an
+ * expansion listener.
*
- * Revision 1.39 2002/02/27 23:19:17 mpowers
- * Refactoring of TreeAssociation to create TreeModelAssociation parent.
+ * Revision 1.39 2002/02/27 23:19:17 mpowers Refactoring of TreeAssociation to
+ * create TreeModelAssociation parent.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeColumnAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeColumnAssociation.java
index f6c90d0..26f2eda 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeColumnAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeColumnAssociation.java
@@ -26,306 +26,254 @@ import net.wotonomy.ui.EODisplayGroup;
import net.wotonomy.ui.swing.components.TreeTableCellRenderer;
/**
-* TreeColumnAssociation is a TableColumnAssocation
-* that works like a TreeAssociation, allowing any
-* table to display hierarchical data in a tabular format.
-* This class is mainly a convenience for connecting a
-* TreeAssociation to a JTree to a TreeTableCellRenderer
-* to a TableColumn.<br><br>
-*
-* Like TableColumnAssociation, you must call setTable()
-* to specify the JTable to be used. (The corresponding
-* table association will direct all column header sorting
-* to the root node of the tree association.)
-*
-* You may also optionally call setTree() to specify a
-* customized JTree to be used. If not specified, a
-* slightly customized JTree will be used (see createTree()
-* and configureColumn()).
-*
-* TreeColumnAssociation supports the following bindings,
-* just as TableColumnAssociation does:
-* <ul>
-* <li>value: a property convertable to a string for
-* display in the cells of the table column. This
-* binding is equivalent to the titles binding of
-* TreeAssociation.</li>
-*
-* <li>editable: a property convertable to a boolean
-* that determines the editability of the corresponding
-* cells in the column.</li>
-* </ul>
-*
-* TreeColumnAssociation additionally supports the following
-* bindings, just as TreeAssociation does, except that the
-* value binding is used instead of the titles binding.
-* <ul>
-* <li>children: a property of a node value that returns
-* zero, one or many objects, each of which will correspond
-* to a child node for the corresponding node in the tree.
-* If this aspect is not bound, the tree behaves like a list.</li>
-*
-* <li>isLeaf: a property of a node value that returns
-* a value convertable to a boolean value.
-* If the isLeaf aspect is not bound, the tree will force
-* nodes to load their children to determine whether they
-* are leaf nodes (in effect loading the grandchildren for
-* any expanded node).
-* </li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TreeColumnAssociation extends TableColumnAssociation
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ValueAspect, EditableAspect, ChildrenAspect, IsLeafAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "table"
- } );
-
+ * TreeColumnAssociation is a TableColumnAssocation that works like a
+ * TreeAssociation, allowing any table to display hierarchical data in a tabular
+ * format. This class is mainly a convenience for connecting a TreeAssociation
+ * to a JTree to a TreeTableCellRenderer to a TableColumn.<br>
+ * <br>
+ *
+ * Like TableColumnAssociation, you must call setTable() to specify the JTable
+ * to be used. (The corresponding table association will direct all column
+ * header sorting to the root node of the tree association.)
+ *
+ * You may also optionally call setTree() to specify a customized JTree to be
+ * used. If not specified, a slightly customized JTree will be used (see
+ * createTree() and configureColumn()).
+ *
+ * TreeColumnAssociation supports the following bindings, just as
+ * TableColumnAssociation does:
+ * <ul>
+ * <li>value: a property convertable to a string for display in the cells of the
+ * table column. This binding is equivalent to the titles binding of
+ * TreeAssociation.</li>
+ *
+ * <li>editable: a property convertable to a boolean that determines the
+ * editability of the corresponding cells in the column.</li>
+ * </ul>
+ *
+ * TreeColumnAssociation additionally supports the following bindings, just as
+ * TreeAssociation does, except that the value binding is used instead of the
+ * titles binding.
+ * <ul>
+ * <li>children: a property of a node value that returns zero, one or many
+ * objects, each of which will correspond to a child node for the corresponding
+ * node in the tree. If this aspect is not bound, the tree behaves like a
+ * list.</li>
+ *
+ * <li>isLeaf: a property of a node value that returns a value convertable to a
+ * boolean value. If the isLeaf aspect is not bound, the tree will force nodes
+ * to load their children to determine whether they are leaf nodes (in effect
+ * loading the grandchildren for any expanded node).</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TreeColumnAssociation extends TableColumnAssociation {
+ static final NSArray aspects = new NSArray(
+ new Object[] { ValueAspect, EditableAspect, ChildrenAspect, IsLeafAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "table" });
+
EODisplayGroup childrenDisplayGroup, leafDisplayGroup;
String childrenKey, leafKey;
-
- TreeModelAssociation treeAssociation;
- JTree tree;
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Throws an exception if the object is not
- * a TableColumn.
- */
- public TreeColumnAssociation ( Object anObject )
- {
- super( anObject );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( ChildrenAspect.equals( anAspect ) )
- {
- childrenDisplayGroup = aDisplayGroup;
+
+ TreeModelAssociation treeAssociation;
+ JTree tree;
+
+ /**
+ * Constructor specifying the object to be controlled by this association.
+ * Throws an exception if the object is not a TableColumn.
+ */
+ public TreeColumnAssociation(Object anObject) {
+ super(anObject);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (ChildrenAspect.equals(anAspect)) {
+ childrenDisplayGroup = aDisplayGroup;
childrenKey = aKey;
}
- if ( IsLeafAspect.equals( anAspect ) )
- {
+ if (IsLeafAspect.equals(anAspect)) {
leafDisplayGroup = aDisplayGroup;
leafKey = aKey;
}
- super.bindAspect( anAspect, aDisplayGroup, aKey );
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
}
-
- /**
- * Overridden to call createTree if necessary,
- * call configureColumn, call createTreeAssociation
- * if necessary, and then call to super.
- */
- public void establishConnection ()
- {
- if ( tree == null )
- {
- tree = createTree();
- }
-
- configureColumn( (TableColumn) object() );
-
- if ( treeAssociation == null )
- {
- treeAssociation = createTreeAssociation( tree );
- }
-
- treeAssociation.bindAspect( TitlesAspect, valueDisplayGroup, valueKey );
- if ( childrenKey != null )
- {
- treeAssociation.bindAspect( ChildrenAspect, childrenDisplayGroup, childrenKey );
- }
- if ( leafKey != null )
- {
- treeAssociation.bindAspect( IsLeafAspect, leafDisplayGroup, leafKey );
- }
-
- // ensure table association's source is tree asssociation's child group
- getTableAssociation().bindAspect(
- SourceAspect, treeAssociation.childrenDisplayGroup, "" );
-
- treeAssociation.establishConnection();
-
- table.setRowHeight( tree.getRowHeight() );
-
- super.establishConnection();
-
- // cause sort ordering to apply to root node of tree
- if ( childrenKey != null )
- {
- getTableAssociation().sortTarget =
- (EODisplayGroup) treeAssociation.getRoot();
- }
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- super.breakConnection();
- treeAssociation.breakConnection();
-
- // restore original source display group
- getTableAssociation().sortTarget = null;
- }
-
- /**
- * Called by establishConnection if setTree was not called.
- * This implementation returns a stock JTree. Override
- * to provide your own customized JTree. Note that
- * TreeTableCellRenderer will further customize this tree
- * when configureColumn is called.
- */
- protected JTree createTree()
- {
- return new JTree();
- }
-
- /**
- * Called by establishConnection to create a tree association
- * only if no tree association has already been created.
- * This implementation returns a stock TreeAssociation.
- * Override to return your own customized TreeAssociation.
- */
- protected TreeModelAssociation createTreeAssociation( JTree aTree )
- {
- return new TreeAssociation( aTree );
- }
-
- /**
- * Called by establishConnection to configure the column
- * with a TreeTableCellRenderer using the current JTree.
- * Override to further customize the column, or customize
- * your column yourself after the call to establishConnection.
- */
- protected void configureColumn( TableColumn aColumn )
- {
- aColumn.setCellRenderer( new TreeTableCellRenderer( tree ) );
- }
-
+
/**
- * Gets the JTree currently used for the column renderer.
- * If not specified, returns null.
- */
- public JTree getTree()
- {
- return tree;
+ * Overridden to call createTree if necessary, call configureColumn, call
+ * createTreeAssociation if necessary, and then call to super.
+ */
+ public void establishConnection() {
+ if (tree == null) {
+ tree = createTree();
+ }
+
+ configureColumn((TableColumn) object());
+
+ if (treeAssociation == null) {
+ treeAssociation = createTreeAssociation(tree);
+ }
+
+ treeAssociation.bindAspect(TitlesAspect, valueDisplayGroup, valueKey);
+ if (childrenKey != null) {
+ treeAssociation.bindAspect(ChildrenAspect, childrenDisplayGroup, childrenKey);
+ }
+ if (leafKey != null) {
+ treeAssociation.bindAspect(IsLeafAspect, leafDisplayGroup, leafKey);
+ }
+
+ // ensure table association's source is tree asssociation's child group
+ getTableAssociation().bindAspect(SourceAspect, treeAssociation.childrenDisplayGroup, "");
+
+ treeAssociation.establishConnection();
+
+ table.setRowHeight(tree.getRowHeight());
+
+ super.establishConnection();
+
+ // cause sort ordering to apply to root node of tree
+ if (childrenKey != null) {
+ getTableAssociation().sortTarget = (EODisplayGroup) treeAssociation.getRoot();
+ }
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ super.breakConnection();
+ treeAssociation.breakConnection();
+
+ // restore original source display group
+ getTableAssociation().sortTarget = null;
}
/**
- * Gets the TreeModelAssociation currently used for the tree.
- * If not tree is not specified, returns null.
- */
- public TreeModelAssociation getTreeModelAssociation()
- {
- if ( tree == null ) return null;
- if (!( tree.getModel() instanceof TreeModelAssociation )) return null;
- return (TreeModelAssociation) tree.getModel();
+ * Called by establishConnection if setTree was not called. This implementation
+ * returns a stock JTree. Override to provide your own customized JTree. Note
+ * that TreeTableCellRenderer will further customize this tree when
+ * configureColumn is called.
+ */
+ protected JTree createTree() {
+ return new JTree();
}
/**
- * Sets the JTree to be used for the column renderer.
- * If not specified, createTree() will be called to create a JTree.
- */
- public void setTree( JTree aTree )
- {
- tree = aTree;
+ * Called by establishConnection to create a tree association only if no tree
+ * association has already been created. This implementation returns a stock
+ * TreeAssociation. Override to return your own customized TreeAssociation.
+ */
+ protected TreeModelAssociation createTreeAssociation(JTree aTree) {
+ return new TreeAssociation(aTree);
+ }
+
+ /**
+ * Called by establishConnection to configure the column with a
+ * TreeTableCellRenderer using the current JTree. Override to further customize
+ * the column, or customize your column yourself after the call to
+ * establishConnection.
+ */
+ protected void configureColumn(TableColumn aColumn) {
+ aColumn.setCellRenderer(new TreeTableCellRenderer(tree));
+ }
+
+ /**
+ * Gets the JTree currently used for the column renderer. If not specified,
+ * returns null.
+ */
+ public JTree getTree() {
+ return tree;
+ }
+
+ /**
+ * Gets the TreeModelAssociation currently used for the tree. If not tree is not
+ * specified, returns null.
+ */
+ public TreeModelAssociation getTreeModelAssociation() {
+ if (tree == null)
+ return null;
+ if (!(tree.getModel() instanceof TreeModelAssociation))
+ return null;
+ return (TreeModelAssociation) tree.getModel();
+ }
+
+ /**
+ * Sets the JTree to be used for the column renderer. If not specified,
+ * createTree() will be called to create a JTree.
+ */
+ public void setTree(JTree aTree) {
+ tree = aTree;
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.9 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.9 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.8 2002/05/03 21:31:50 mpowers
- * Actually works better without selectionPaintedImmediately.
+ * Revision 1.8 2002/05/03 21:31:50 mpowers Actually works better without
+ * selectionPaintedImmediately.
*
- * Revision 1.7 2002/04/12 21:05:58 mpowers
- * Now distinguishing changes in titles group even better.
+ * Revision 1.7 2002/04/12 21:05:58 mpowers Now distinguishing changes in titles
+ * group even better.
*
- * Revision 1.6 2002/03/08 23:18:48 mpowers
- * Added accessor for tree association.
+ * Revision 1.6 2002/03/08 23:18:48 mpowers Added accessor for tree association.
*
- * Revision 1.5 2002/03/07 23:04:36 mpowers
- * Refining TreeColumnAssociation.
+ * Revision 1.5 2002/03/07 23:04:36 mpowers Refining TreeColumnAssociation.
*
- * Revision 1.4 2002/03/06 13:04:16 mpowers
- * Implemented cascading qualifiers in tree nodes.
+ * Revision 1.4 2002/03/06 13:04:16 mpowers Implemented cascading qualifiers in
+ * tree nodes.
*
- * Revision 1.3 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.3 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.2 2002/03/04 22:48:22 mpowers
- * Now working with table association to sort the root node.
+ * Revision 1.2 2002/03/04 22:48:22 mpowers Now working with table association
+ * to sort the root node.
*
- * Revision 1.1 2002/03/01 23:42:09 mpowers
- * Implemented TreeColumnAssociation, and updated documentation.
+ * Revision 1.1 2002/03/01 23:42:09 mpowers Implemented TreeColumnAssociation,
+ * and updated documentation.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeModelAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeModelAssociation.java
index 86bfa69..b0070d4 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeModelAssociation.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TreeModelAssociation.java
@@ -48,1704 +48,1396 @@ import net.wotonomy.ui.EOAssociation;
import net.wotonomy.ui.EODisplayGroup;
/**
-* TreeModelAssociation binds a JTree or similar component
-* that uses a TreeModel to a display group's
-* list of displayable objects, each of which may have
-* a list of child objects managed by another display
-* group, and so on. TreeModelAssociation works exactly
-* like a ListAssociation, with the additional capability
-* to specify a "Children" aspect, that will allow child
-* objects to be retrieved from a parent display group.
-*
-* <ul>
-*
-* <li>titles: a property convertable to a string for
-* display in the nodes of the tree. The objects in
-* the bound display group will be used to populate the
-* initial root nodes of the tree (more accurately,
-* children of the offscreen root node in the tree).</li>
-*
-* <li>children: a property of a node value that returns
-* zero, one or many objects, each of which will correspond
-* to a child node for the corresponding node in the tree.
-* The data source of the bound display group is replaced
-* a data source that populates the display group with
-* the selection in the tree component as determined by
-* calling fetchObjectsIntoChildrenGroup.
-* If this aspect is not bound, the tree behaves like a list.
-* <br><br>
-* Binding this aspect with a null display group is the same
-* as binding it with the titles display group.
-* In this configuration the contents of the titles
-* display group will be replaced with the selection in the
-* tree component, as specified above, replacing the existing
-* data source.
-* <br><br>
-* In that case, the display groups for the nodes in
-* the tree will still use the original data source
-* for resolving their children key, and programmatically
-* setting the contents of the display group will still
-* repopulate the root nodes of the tree.
-* </li>
-*
-* <li>isLeaf: a property of a node value that returns
-* a value convertable to a boolean value (aside from
-* an actual boolean value, zeroes evaluate to true,
-* as does any String containing "yes" or "true" or that
-* is convertable to a number equal to zero; other values
-* evaluate to false).
-* <br><br>
-* If the isLeaf aspect is not bound,
-* the tree must force nodes to load their children to
-* determine whether they are leaf nodes (in effect
-* loading the grandchildren for any expanded node).
-* If bound, child loading is deferred until the node
-* is actually expanded.
-* <br><br>
-* For example, binding this value to a null
-* display group and the key "false" will result in a
-* deferred-loading tree that works much like Windows
-* Explorer's network volume browser - all nodes appear
-* with "pluses" until they are expanded.
-* <br><br>
-* Note that the display group is ignored: the property
-* will be applied directly to the object corresponding
-* to the node.</li>
-*
-* </ul>
-*
-* This class acts as the TreeModel for the controlled
-* component: calling yourcomponent.getModel() will
-* return this association. The tree model methods on
-* this class are public and may be used to affect changes
-* on the controlled components.<br><br>
-*
-* The titles display group's contents are inserted
-* into a new display group that acts as the root node.
-* After that point, changes in the titles display group
-* will cause the tree model to reset itself, creating
-* a new display group for the root node.
-* <br><br>
-*
-* If a separate display group is bound to the children
-* aspect, it will
-* be used to hold the selected objects and their siblings
-* and selection will be maintained there, and the titles
-* display group selection will not be updated.
-* Any editing or detail associations should in that case
-* be attached to the children display group, not the titles
-* group. <br><br>
-*
-* Each node in the tree is an EODisplayGroup that
-* contains the child objects of the object it represents
-* in the tree. These objects can be programmatically
-* inserted, updated, or removed using DisplayGroup
-* methods. Each node's takes its parent group's
-* sortOrderings until a sort ordering is explicitly
-* specified - setting a sort ordering to null will resume
-* using the parent group's sort ordering.<br><br>
-*
-* Each node in the tree also implements MutableTreeNode.
-* The value that a node represents is the titles property
-* value of the object in the parent's displayed objects
-* list at the index corresponding to the index of the node.
-* Calling toString on a node returns the string representation
-* of the titles property value, and setUserObject will update
-* that value directly in the corresponding object.
-* Moving a node from one parent to another will remove the
-* actual object in the parent display group and insert it
-* into the destination display group.<br><br>
-*
-* In short, any nodes obtained from this class'
-* implementation of TreeModel may be cast as either
-* EODisplayGroup or MutableTreeNode and maybe be
-* programmatically manipulated in either manner.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TreeModelAssociation extends EOAssociation
- implements TreeModel, TreeSelectionListener
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- TitlesAspect, ChildrenAspect, IsLeafAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "model"
- } );
-
- private final static NSSelector getSelectionModel =
- new NSSelector( "getSelectionModel" );
- private final static NSSelector setModel =
- new NSSelector( "setModel",
- new Class[] { TreeModel.class } );
-
- EODisplayGroup titlesDisplayGroup, childrenDisplayGroup, leafDisplayGroup;
- String titlesKey, childrenKey, leafKey;
- DisplayGroupNode rootNode;
- Vector listeners;
- Object rootLabel;
-
- TreeSelectionModel selectionModel;
- boolean selectionPaintedImmediately;
-
- boolean insertingChild;
- boolean insertingAfter;
-
- EOObserverProxy recentChangesObserver;
-
- private boolean pleaseSelectRootNode;
-
- /**
- * Constructor expecting a JTree or any other object
- * that has void setModel(TreeModel) and TreeModel getSelectionModel()
- * methods. This tree association will be used for the TreeModel.
- * The root node will be labeled "Root". <br><br>
- *
- * As an alternate way to use a TreeModelAssociation, you may pass a
- * TreeSelectionModel to the constructor and then manually set your
- * component to use this class as its TreeModel.
- */
- public TreeModelAssociation ( Object anObject )
- {
- super( anObject );
-
- titlesDisplayGroup = null;
- titlesKey = null;
- childrenDisplayGroup = null;
- childrenKey = null;
- leafDisplayGroup = null;
- leafKey = null;
- listeners = new Vector();
-
- selectionPaintedImmediately = false;
-
- // after display group nodes process recent changes
- recentChangesObserver = new EOObserverProxy(
- this, new NSSelector( "processRecentChanges" ),
- EODelayedObserver.ObserverPrioritySixth );
- EOObserverCenter.addObserver( recentChangesObserver, this );
-
- insertingChild = true;
- insertingAfter = true;
-
- pleaseSelectRootNode = false;
-
- rootLabel = "Root";
- rootNode = createNode( null, null );
- }
-
- /**
- * Constructor expecting a JTree or similar component
- * and specifying a label for the root node.
- */
- public TreeModelAssociation( Object anObject, Object aRootLabel )
- {
- this( anObject );
- rootLabel = aRootLabel;
- rootNode.setUserObject( aRootLabel );
- }
-
- /**
- * Gets the current root label.
- */
- public Object rootLabel()
- {
- return rootLabel;
- }
-
- /**
- * Gets the current root label.
- */
- public Object getRootLabel()
- {
- return rootLabel();
- }
-
- /**
- * Sets the root label.
- */
- public void setRootLabel( Object aLabel )
- {
- rootLabel = aLabel;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return setModel.implementedByObject( anObject );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return TitlesAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
- if ( TitlesAspect.equals( anAspect ) )
- {
- titlesDisplayGroup = aDisplayGroup;
- titlesKey = aKey;
- }
- if ( ChildrenAspect.equals( anAspect ) )
- {
- childrenDisplayGroup = aDisplayGroup;
- childrenKey = aKey;
- }
- if ( IsLeafAspect.equals( anAspect ) )
- {
- leafDisplayGroup = aDisplayGroup;
- leafKey = aKey;
- }
- if ( childrenDisplayGroup == null )
- {
- childrenDisplayGroup = titlesDisplayGroup;
- }
- super.bindAspect( anAspect, aDisplayGroup, aKey );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- if ( titlesDisplayGroup == null )
- {
- throw new WotonomyException(
- "TreeModelAssociation: Titles aspect must be bound" );
- }
-
- // populate the root node
- rootNode = createNode( titlesDisplayGroup, null );
- rootNode.setObjectArray( titlesDisplayGroup.displayedObjects() );
- rootNode.setSortOrderings( titlesDisplayGroup.sortOrderings() );
-
- EODataSource dataSource = childrenDisplayGroup.dataSource();
- if ( dataSource == null ) dataSource = titlesDisplayGroup.dataSource();
- while ( dataSource instanceof DelegatingTreeDataSource )
- { // unwrap any existing delegating data sources
- dataSource = ((DelegatingTreeDataSource)dataSource).delegateDataSource;
- }
- // create a new delegating data source
- childrenDisplayGroup.setDataSource(
- new DelegatingTreeDataSource( this, dataSource ) );
-
- //TODO: find out why omitting this line causes weird selection behavior
- childrenDisplayGroup.setSortOrderings( new NSArray() );
-
- // check for alternate usage
- if ( object() instanceof TreeSelectionModel )
- {
- selectionModel = (TreeSelectionModel) object();
- }
- else // use specified object
- {
- try
- {
- setModel.invoke( object(), new Object[] { this } );
- selectionModel = (TreeSelectionModel)
- getSelectionModel.invoke( object(), new Object[] {} );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
- addAsListener();
- super.establishConnection();
-/*
- fireRootStructureChanged();
-
-// titlesGroupChanged = true;
-// subjectChanged();
-
- // update the children group
- removeAsListener();
- childrenDisplayGroup.fetch();
- addAsListener();
-
- // update selection
- selectFromDisplayGroup( titlesDisplayGroup );
-*/
- }
-
- protected void fireRootStructureChanged()
- {
- int count = rootNode.displayedObjects().count();
- int[] childIndices = new int[ count ];
- Object[] children = new Object[ count ];
- for ( int i = 0; i < count; i++ )
- {
- childIndices[i] = i;
- children[i] = rootNode.getChildNodeAt( i );
- }
-
- // must fire a tree structure changed with children,
- // otherwise the tree gets weird selection behavior
- fireTreeStructureChanged( this, new Object[] { rootNode },
- childIndices, children );
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- if ( childrenDisplayGroup != null )
- {
- if ( childrenDisplayGroup.dataSource() instanceof DelegatingTreeDataSource )
- {
- if ( titlesDisplayGroup == childrenDisplayGroup )
- {
- titlesDisplayGroup.setDataSource( ((DelegatingTreeDataSource)
- childrenDisplayGroup.dataSource()).delegateDataSource );
- }
- else
- {
- childrenDisplayGroup.setDataSource( null );
- }
- }
- }
-
- removeAsListener();
- super.breakConnection();
- }
-
- protected void addAsListener()
- {
- isListening = true;
- selectionModel.addTreeSelectionListener( this );
- }
-
- protected void removeAsListener()
- {
- isListening = false;
- selectionModel.removeTreeSelectionListener( this );
- }
-
- protected boolean isListening = false;
- private boolean pleaseIgnore = false;
- protected boolean titlesGroupChanged = false;
- protected boolean childrenGroupChanged = false;
-
- /**
- * Overridden to better discriminate what is changed.
- */
- public void objectWillChange( Object anObject )
- {
- if ( ! isListening ) return;
-
- if ( anObject == titlesDisplayGroup )
- {
- titlesGroupChanged = true;
- }
- if ( anObject == childrenDisplayGroup )
- {
- childrenGroupChanged = true;
- if ( childrenDisplayGroup.qualifier() != null )
- {
- if ( ( rootNode.qualifier() == null ) ||
- ! childrenDisplayGroup.qualifier().equals( rootNode.qualifier() ) )
- {
- // quietly move qualifier from children group to root node
- rootNode.setQualifier( childrenDisplayGroup.qualifier() );
- childrenDisplayGroup.setQualifier( null );
- rootNode.updateDisplayedObjects();
- }
- }
- }
- super.objectWillChange( anObject );
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
- // titles aspect
- if ( titlesGroupChanged )
- {
- if ( titlesDisplayGroup.contentsChanged() )
- {
- NSArray displayedObjects = titlesDisplayGroup.displayedObjects();
- NSArray childrenObjects;
- if ( titlesDisplayGroup != childrenDisplayGroup
- || displayedObjects.count()
- != (childrenObjects = objectsFetchedIntoChildrenGroup()).count()
- || ! displayedObjects.containsAll( childrenObjects ) )
- {
- populateFromDisplayGroup( displayedObjects );
- }
- }
- }
-
- if ( childrenDisplayGroup.selectionChanged() && !childrenDisplayGroup.contentsChanged() )
- {
- selectFromDisplayGroup( childrenDisplayGroup );
- }
-
- titlesGroupChanged = false;
- childrenGroupChanged = false;
- }
-
- /**
- * Called by subjectChanged() in response to an external change in the titles display group.
- */
- void populateFromDisplayGroup( List displayedObjects )
- {
- // trigger processRecentChanges
- willChange();
-
- // workaround: see below
- int previousCount = rootNode.previouslyDisplayedObjects.length;
-
- // update the root node
- rootNode.setObjectArray( displayedObjects );
-
- //FIXME: workaround for what appears to be a bug in JTree:
- // if root node is not visible and has no children, insert events are ignored
- if ( previousCount == 0 )
- {
- fireRootStructureChanged();
- }
- }
-
- /**
- * Package access so DisplayGroupNode can replace the selection after an update.
- */
- void selectFromDisplayGroup( EODisplayGroup aDisplayGroup )
- { // System.out.println( "selectFromDisplayGroup: " + aDisplayGroup.selectedObjects() );
-
- removeAsListener();
-
- TreePath[] paths = selectionModel.getSelectionPaths();
- NSArray selectedObjects = aDisplayGroup.selectedObjects();
-
- // assemble current selection list
- List treeSelection = new LinkedList();
- if ( paths != null )
- {
- for ( int i = 0; i < paths.length; i ++ )
- {
- treeSelection.add(
- ((DisplayGroupNode)paths[i].getLastPathComponent()).getUserObject() );
- }
- }
-
- if ( ! ( selectedObjects.size() == treeSelection.size()
- && treeSelection.containsAll( selectedObjects ) ) )
- {
- selectionModel.clearSelection();
-
- // workaround to select root node from valueChanged()
- if ( pleaseSelectRootNode )
- {
- selectionModel.addSelectionPath( new TreePath( this.getRoot() ) );
- pleaseSelectRootNode = false;
- }
-
- //FIXME: display group is assumed to have only one instance of each object
- for ( int i = 0; i < selectedObjects.count(); i++ )
- {
- //FIXME: selects only the first instance for now
- //selectionModel.addSelectionPaths(
- // getPathsForObject(
- // selectedObjects.objectAtIndex( i ) ) );
- selectionModel.addSelectionPath(
- getPathForObject(
- selectedObjects.objectAtIndex( i ) ) );
- }
- }
-
- addAsListener();
- }
-
- /**
- * Returns the first node found that represents the
- * specified object, or null if not found.
- * This implementation simply calls getPathForObject.
- */
- public Object getNodeForObject( Object anObject )
- {
- TreePath result = getPathForObject( anObject );
- if ( result != null )
- {
- return result.getLastPathComponent();
- }
- return null;
- }
-
- /**
- * Returns the object represented by the specified node
- * which must be a display group node from this tree.
- */
- public Object getObjectForNode( Object aNode )
- {
- if ( aNode instanceof DisplayGroupNode )
- {
- return ((DisplayGroupNode)aNode).getUserObject();
- }
-
- // not a display group node
- throw new WotonomyException(
- "Not a display group node: " + aNode );
- }
-
- /**
- * Returns the tree path for the specified node,
- * which must be a display group node from this tree.
- */
- public TreePath getPathForNode( Object aNode )
- {
- if ( aNode instanceof DisplayGroupNode )
- {
- return ((DisplayGroupNode)aNode).treePath();
- }
-
- // not a display group node
- throw new WotonomyException(
- "Not a display group node: " + aNode );
- }
-
- /**
- * Returns the first tree path for the node that represents
- * the specified object, or null if the object does not exist in this tree.
- * This implementation does a breadth-first search of the tree
- * for the object, looking only at nodes that have been loaded.
- * This means that if the object does not exist in the tree,
- * the entire tree must be traversed.
- */
- public TreePath getPathForObject( Object anObject )
- {
- return getPathForObjectInPath( anObject, new TreePath( this.getRoot() ) );
- }
-
- /**
- * Returns the tree path for the node that represents
- * the specified object,
- * or null if the object does not exist in this tree.
- * This implementation does a breadth-first search of the tree
- * for the object, looking only at nodes that have been loaded.
- * This means that the entire tree is traversed.
- */
- public TreePath[] getPathsForObject( Object anObject )
- {
- return getPathsForObjectInPath( anObject, new TreePath( this.getRoot() ) );
- }
-
- /**
- * A breadth-first search of the tree starting
- * at the specified tree path, comparing by reference.
- * Returns immediately with the first match.
- */
- private TreePath getPathForObjectInPath( Object anObject, TreePath aPath )
- {
- LinkedList queue = new LinkedList();
-
- // add the specified path
- queue.addLast( aPath );
-
- return processQueue( anObject, queue, null );
- }
-
- /**
- * A breadth-first search of the tree starting
- * at the specified tree path, comparing by reference.
- * The entire branch is searched before returning
- * an array of all matches.
- */
- private TreePath[] getPathsForObjectInPath( Object anObject, TreePath aPath )
- {
- LinkedList queue = new LinkedList();
-
- // add the specified path
- queue.addLast( aPath );
-
- List result = new LinkedList();
- processQueue( anObject, queue, result );
- TreePath[] paths = new TreePath[ result.size() ];
- for ( int i = 0; i < paths.length; i++ )
- {
- paths[i] = (TreePath) result.get(i);
- }
- return paths;
- }
-
- /**
- * Processes the specified queue, appending results to aResult if it exists,
- * or returning immediately with a TreePath is aResult is null.
- */
- private TreePath processQueue( Object anObject, LinkedList aQueue, List aResult )
- {
- TreePath path;
- while ( ! aQueue.isEmpty() )
- {
- path = (TreePath) aQueue.removeFirst();
- path = checkNode( anObject, path, aQueue );
- if ( path != null )
- {
- if ( aResult != null )
- {
- aResult.add( path );
- }
- else
- {
- return path;
- }
- }
- }
- return null;
- }
-
- /**
- * Compares the specified object by reference each of the children of
- * the node at the end of the specified tree path, adding nodes that
- * do not match but have fetched object to the end of the specified queue.
- * Returns the path of the first child node that matches the specified object,
- * or null if no match was found.
- */
- private TreePath checkNode( Object anObject, TreePath aPath, LinkedList aQueue )
- {
- TreePath result = null;
- Object child;
- Object parent = aPath.getLastPathComponent();
- int count = getChildCount( parent );
-
- for ( int i = 0; i < count; i++ )
- {
- child = getChild( parent, i );
-
- // add to queue if node has fetched children
- if ( ((DisplayGroupNode)child).isFetched )
- {
- aQueue.addLast( aPath.pathByAddingChild( child ) );
- }
-
- // compares by reference
- if ( ((DisplayGroupNode)child).object() == anObject )
- {
- // assumes same object cannot be in display group twice
- result = aPath.pathByAddingChild( child );
+ * TreeModelAssociation binds a JTree or similar component that uses a TreeModel
+ * to a display group's list of displayable objects, each of which may have a
+ * list of child objects managed by another display group, and so on.
+ * TreeModelAssociation works exactly like a ListAssociation, with the
+ * additional capability to specify a "Children" aspect, that will allow child
+ * objects to be retrieved from a parent display group.
+ *
+ * <ul>
+ *
+ * <li>titles: a property convertable to a string for display in the nodes of
+ * the tree. The objects in the bound display group will be used to populate the
+ * initial root nodes of the tree (more accurately, children of the offscreen
+ * root node in the tree).</li>
+ *
+ * <li>children: a property of a node value that returns zero, one or many
+ * objects, each of which will correspond to a child node for the corresponding
+ * node in the tree. The data source of the bound display group is replaced a
+ * data source that populates the display group with the selection in the tree
+ * component as determined by calling fetchObjectsIntoChildrenGroup. If this
+ * aspect is not bound, the tree behaves like a list. <br>
+ * <br>
+ * Binding this aspect with a null display group is the same as binding it with
+ * the titles display group. In this configuration the contents of the titles
+ * display group will be replaced with the selection in the tree component, as
+ * specified above, replacing the existing data source. <br>
+ * <br>
+ * In that case, the display groups for the nodes in the tree will still use the
+ * original data source for resolving their children key, and programmatically
+ * setting the contents of the display group will still repopulate the root
+ * nodes of the tree.</li>
+ *
+ * <li>isLeaf: a property of a node value that returns a value convertable to a
+ * boolean value (aside from an actual boolean value, zeroes evaluate to true,
+ * as does any String containing "yes" or "true" or that is convertable to a
+ * number equal to zero; other values evaluate to false). <br>
+ * <br>
+ * If the isLeaf aspect is not bound, the tree must force nodes to load their
+ * children to determine whether they are leaf nodes (in effect loading the
+ * grandchildren for any expanded node). If bound, child loading is deferred
+ * until the node is actually expanded. <br>
+ * <br>
+ * For example, binding this value to a null display group and the key "false"
+ * will result in a deferred-loading tree that works much like Windows
+ * Explorer's network volume browser - all nodes appear with "pluses" until they
+ * are expanded. <br>
+ * <br>
+ * Note that the display group is ignored: the property will be applied directly
+ * to the object corresponding to the node.</li>
+ *
+ * </ul>
+ *
+ * This class acts as the TreeModel for the controlled component: calling
+ * yourcomponent.getModel() will return this association. The tree model methods
+ * on this class are public and may be used to affect changes on the controlled
+ * components.<br>
+ * <br>
+ *
+ * The titles display group's contents are inserted into a new display group
+ * that acts as the root node. After that point, changes in the titles display
+ * group will cause the tree model to reset itself, creating a new display group
+ * for the root node. <br>
+ * <br>
+ *
+ * If a separate display group is bound to the children aspect, it will be used
+ * to hold the selected objects and their siblings and selection will be
+ * maintained there, and the titles display group selection will not be updated.
+ * Any editing or detail associations should in that case be attached to the
+ * children display group, not the titles group. <br>
+ * <br>
+ *
+ * Each node in the tree is an EODisplayGroup that contains the child objects of
+ * the object it represents in the tree. These objects can be programmatically
+ * inserted, updated, or removed using DisplayGroup methods. Each node's takes
+ * its parent group's sortOrderings until a sort ordering is explicitly
+ * specified - setting a sort ordering to null will resume using the parent
+ * group's sort ordering.<br>
+ * <br>
+ *
+ * Each node in the tree also implements MutableTreeNode. The value that a node
+ * represents is the titles property value of the object in the parent's
+ * displayed objects list at the index corresponding to the index of the node.
+ * Calling toString on a node returns the string representation of the titles
+ * property value, and setUserObject will update that value directly in the
+ * corresponding object. Moving a node from one parent to another will remove
+ * the actual object in the parent display group and insert it into the
+ * destination display group.<br>
+ * <br>
+ *
+ * In short, any nodes obtained from this class' implementation of TreeModel may
+ * be cast as either EODisplayGroup or MutableTreeNode and maybe be
+ * programmatically manipulated in either manner.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TreeModelAssociation extends EOAssociation implements TreeModel, TreeSelectionListener {
+ static final NSArray aspects = new NSArray(new Object[] { TitlesAspect, ChildrenAspect, IsLeafAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "model" });
+
+ private final static NSSelector getSelectionModel = new NSSelector("getSelectionModel");
+ private final static NSSelector setModel = new NSSelector("setModel", new Class[] { TreeModel.class });
+
+ EODisplayGroup titlesDisplayGroup, childrenDisplayGroup, leafDisplayGroup;
+ String titlesKey, childrenKey, leafKey;
+ DisplayGroupNode rootNode;
+ Vector listeners;
+ Object rootLabel;
+
+ TreeSelectionModel selectionModel;
+ boolean selectionPaintedImmediately;
+
+ boolean insertingChild;
+ boolean insertingAfter;
+
+ EOObserverProxy recentChangesObserver;
+
+ private boolean pleaseSelectRootNode;
+
+ /**
+ * Constructor expecting a JTree or any other object that has void
+ * setModel(TreeModel) and TreeModel getSelectionModel() methods. This tree
+ * association will be used for the TreeModel. The root node will be labeled
+ * "Root". <br>
+ * <br>
+ *
+ * As an alternate way to use a TreeModelAssociation, you may pass a
+ * TreeSelectionModel to the constructor and then manually set your component to
+ * use this class as its TreeModel.
+ */
+ public TreeModelAssociation(Object anObject) {
+ super(anObject);
+
+ titlesDisplayGroup = null;
+ titlesKey = null;
+ childrenDisplayGroup = null;
+ childrenKey = null;
+ leafDisplayGroup = null;
+ leafKey = null;
+ listeners = new Vector();
+
+ selectionPaintedImmediately = false;
+
+ // after display group nodes process recent changes
+ recentChangesObserver = new EOObserverProxy(this, new NSSelector("processRecentChanges"),
+ EODelayedObserver.ObserverPrioritySixth);
+ EOObserverCenter.addObserver(recentChangesObserver, this);
+
+ insertingChild = true;
+ insertingAfter = true;
+
+ pleaseSelectRootNode = false;
+
+ rootLabel = "Root";
+ rootNode = createNode(null, null);
+ }
+
+ /**
+ * Constructor expecting a JTree or similar component and specifying a label for
+ * the root node.
+ */
+ public TreeModelAssociation(Object anObject, Object aRootLabel) {
+ this(anObject);
+ rootLabel = aRootLabel;
+ rootNode.setUserObject(aRootLabel);
+ }
+
+ /**
+ * Gets the current root label.
+ */
+ public Object rootLabel() {
+ return rootLabel;
+ }
+
+ /**
+ * Gets the current root label.
+ */
+ public Object getRootLabel() {
+ return rootLabel();
+ }
+
+ /**
+ * Sets the root label.
+ */
+ public void setRootLabel(Object aLabel) {
+ rootLabel = aLabel;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return setModel.implementedByObject(anObject);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return TitlesAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ if (TitlesAspect.equals(anAspect)) {
+ titlesDisplayGroup = aDisplayGroup;
+ titlesKey = aKey;
+ }
+ if (ChildrenAspect.equals(anAspect)) {
+ childrenDisplayGroup = aDisplayGroup;
+ childrenKey = aKey;
+ }
+ if (IsLeafAspect.equals(anAspect)) {
+ leafDisplayGroup = aDisplayGroup;
+ leafKey = aKey;
+ }
+ if (childrenDisplayGroup == null) {
+ childrenDisplayGroup = titlesDisplayGroup;
+ }
+ super.bindAspect(anAspect, aDisplayGroup, aKey);
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ if (titlesDisplayGroup == null) {
+ throw new WotonomyException("TreeModelAssociation: Titles aspect must be bound");
+ }
+
+ // populate the root node
+ rootNode = createNode(titlesDisplayGroup, null);
+ rootNode.setObjectArray(titlesDisplayGroup.displayedObjects());
+ rootNode.setSortOrderings(titlesDisplayGroup.sortOrderings());
+
+ EODataSource dataSource = childrenDisplayGroup.dataSource();
+ if (dataSource == null)
+ dataSource = titlesDisplayGroup.dataSource();
+ while (dataSource instanceof DelegatingTreeDataSource) { // unwrap any existing delegating data sources
+ dataSource = ((DelegatingTreeDataSource) dataSource).delegateDataSource;
+ }
+ // create a new delegating data source
+ childrenDisplayGroup.setDataSource(new DelegatingTreeDataSource(this, dataSource));
+
+ // TODO: find out why omitting this line causes weird selection behavior
+ childrenDisplayGroup.setSortOrderings(new NSArray());
+
+ // check for alternate usage
+ if (object() instanceof TreeSelectionModel) {
+ selectionModel = (TreeSelectionModel) object();
+ } else // use specified object
+ {
+ try {
+ setModel.invoke(object(), new Object[] { this });
+ selectionModel = (TreeSelectionModel) getSelectionModel.invoke(object(), new Object[] {});
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
+ addAsListener();
+ super.establishConnection();
+ /*
+ * fireRootStructureChanged();
+ *
+ * // titlesGroupChanged = true; // subjectChanged();
+ *
+ * // update the children group removeAsListener();
+ * childrenDisplayGroup.fetch(); addAsListener();
+ *
+ * // update selection selectFromDisplayGroup( titlesDisplayGroup );
+ */
+ }
+
+ protected void fireRootStructureChanged() {
+ int count = rootNode.displayedObjects().count();
+ int[] childIndices = new int[count];
+ Object[] children = new Object[count];
+ for (int i = 0; i < count; i++) {
+ childIndices[i] = i;
+ children[i] = rootNode.getChildNodeAt(i);
+ }
+
+ // must fire a tree structure changed with children,
+ // otherwise the tree gets weird selection behavior
+ fireTreeStructureChanged(this, new Object[] { rootNode }, childIndices, children);
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ if (childrenDisplayGroup != null) {
+ if (childrenDisplayGroup.dataSource() instanceof DelegatingTreeDataSource) {
+ if (titlesDisplayGroup == childrenDisplayGroup) {
+ titlesDisplayGroup.setDataSource(
+ ((DelegatingTreeDataSource) childrenDisplayGroup.dataSource()).delegateDataSource);
+ } else {
+ childrenDisplayGroup.setDataSource(null);
+ }
+ }
+ }
+
+ removeAsListener();
+ super.breakConnection();
+ }
+
+ protected void addAsListener() {
+ isListening = true;
+ selectionModel.addTreeSelectionListener(this);
+ }
+
+ protected void removeAsListener() {
+ isListening = false;
+ selectionModel.removeTreeSelectionListener(this);
+ }
+
+ protected boolean isListening = false;
+ private boolean pleaseIgnore = false;
+ protected boolean titlesGroupChanged = false;
+ protected boolean childrenGroupChanged = false;
+
+ /**
+ * Overridden to better discriminate what is changed.
+ */
+ public void objectWillChange(Object anObject) {
+ if (!isListening)
+ return;
+
+ if (anObject == titlesDisplayGroup) {
+ titlesGroupChanged = true;
+ }
+ if (anObject == childrenDisplayGroup) {
+ childrenGroupChanged = true;
+ if (childrenDisplayGroup.qualifier() != null) {
+ if ((rootNode.qualifier() == null) || !childrenDisplayGroup.qualifier().equals(rootNode.qualifier())) {
+ // quietly move qualifier from children group to root node
+ rootNode.setQualifier(childrenDisplayGroup.qualifier());
+ childrenDisplayGroup.setQualifier(null);
+ rootNode.updateDisplayedObjects();
+ }
+ }
+ }
+ super.objectWillChange(anObject);
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
+ // titles aspect
+ if (titlesGroupChanged) {
+ if (titlesDisplayGroup.contentsChanged()) {
+ NSArray displayedObjects = titlesDisplayGroup.displayedObjects();
+ NSArray childrenObjects;
+ if (titlesDisplayGroup != childrenDisplayGroup
+ || displayedObjects.count() != (childrenObjects = objectsFetchedIntoChildrenGroup()).count()
+ || !displayedObjects.containsAll(childrenObjects)) {
+ populateFromDisplayGroup(displayedObjects);
+ }
+ }
+ }
+
+ if (childrenDisplayGroup.selectionChanged() && !childrenDisplayGroup.contentsChanged()) {
+ selectFromDisplayGroup(childrenDisplayGroup);
+ }
+
+ titlesGroupChanged = false;
+ childrenGroupChanged = false;
+ }
+
+ /**
+ * Called by subjectChanged() in response to an external change in the titles
+ * display group.
+ */
+ void populateFromDisplayGroup(List displayedObjects) {
+ // trigger processRecentChanges
+ willChange();
+
+ // workaround: see below
+ int previousCount = rootNode.previouslyDisplayedObjects.length;
+
+ // update the root node
+ rootNode.setObjectArray(displayedObjects);
+
+ // FIXME: workaround for what appears to be a bug in JTree:
+ // if root node is not visible and has no children, insert events are ignored
+ if (previousCount == 0) {
+ fireRootStructureChanged();
+ }
+ }
+
+ /**
+ * Package access so DisplayGroupNode can replace the selection after an update.
+ */
+ void selectFromDisplayGroup(EODisplayGroup aDisplayGroup) { // System.out.println( "selectFromDisplayGroup: " +
+ // aDisplayGroup.selectedObjects() );
+
+ removeAsListener();
+
+ TreePath[] paths = selectionModel.getSelectionPaths();
+ NSArray selectedObjects = aDisplayGroup.selectedObjects();
+
+ // assemble current selection list
+ List treeSelection = new LinkedList();
+ if (paths != null) {
+ for (int i = 0; i < paths.length; i++) {
+ treeSelection.add(((DisplayGroupNode) paths[i].getLastPathComponent()).getUserObject());
+ }
+ }
+
+ if (!(selectedObjects.size() == treeSelection.size() && treeSelection.containsAll(selectedObjects))) {
+ selectionModel.clearSelection();
+
+ // workaround to select root node from valueChanged()
+ if (pleaseSelectRootNode) {
+ selectionModel.addSelectionPath(new TreePath(this.getRoot()));
+ pleaseSelectRootNode = false;
+ }
+
+ // FIXME: display group is assumed to have only one instance of each object
+ for (int i = 0; i < selectedObjects.count(); i++) {
+ // FIXME: selects only the first instance for now
+ // selectionModel.addSelectionPaths(
+ // getPathsForObject(
+ // selectedObjects.objectAtIndex( i ) ) );
+ selectionModel.addSelectionPath(getPathForObject(selectedObjects.objectAtIndex(i)));
+ }
+ }
+
+ addAsListener();
+ }
+
+ /**
+ * Returns the first node found that represents the specified object, or null if
+ * not found. This implementation simply calls getPathForObject.
+ */
+ public Object getNodeForObject(Object anObject) {
+ TreePath result = getPathForObject(anObject);
+ if (result != null) {
+ return result.getLastPathComponent();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the object represented by the specified node which must be a display
+ * group node from this tree.
+ */
+ public Object getObjectForNode(Object aNode) {
+ if (aNode instanceof DisplayGroupNode) {
+ return ((DisplayGroupNode) aNode).getUserObject();
+ }
+
+ // not a display group node
+ throw new WotonomyException("Not a display group node: " + aNode);
+ }
+
+ /**
+ * Returns the tree path for the specified node, which must be a display group
+ * node from this tree.
+ */
+ public TreePath getPathForNode(Object aNode) {
+ if (aNode instanceof DisplayGroupNode) {
+ return ((DisplayGroupNode) aNode).treePath();
+ }
+
+ // not a display group node
+ throw new WotonomyException("Not a display group node: " + aNode);
+ }
+
+ /**
+ * Returns the first tree path for the node that represents the specified
+ * object, or null if the object does not exist in this tree. This
+ * implementation does a breadth-first search of the tree for the object,
+ * looking only at nodes that have been loaded. This means that if the object
+ * does not exist in the tree, the entire tree must be traversed.
+ */
+ public TreePath getPathForObject(Object anObject) {
+ return getPathForObjectInPath(anObject, new TreePath(this.getRoot()));
+ }
+
+ /**
+ * Returns the tree path for the node that represents the specified object, or
+ * null if the object does not exist in this tree. This implementation does a
+ * breadth-first search of the tree for the object, looking only at nodes that
+ * have been loaded. This means that the entire tree is traversed.
+ */
+ public TreePath[] getPathsForObject(Object anObject) {
+ return getPathsForObjectInPath(anObject, new TreePath(this.getRoot()));
+ }
+
+ /**
+ * A breadth-first search of the tree starting at the specified tree path,
+ * comparing by reference. Returns immediately with the first match.
+ */
+ private TreePath getPathForObjectInPath(Object anObject, TreePath aPath) {
+ LinkedList queue = new LinkedList();
+
+ // add the specified path
+ queue.addLast(aPath);
+
+ return processQueue(anObject, queue, null);
+ }
+
+ /**
+ * A breadth-first search of the tree starting at the specified tree path,
+ * comparing by reference. The entire branch is searched before returning an
+ * array of all matches.
+ */
+ private TreePath[] getPathsForObjectInPath(Object anObject, TreePath aPath) {
+ LinkedList queue = new LinkedList();
+
+ // add the specified path
+ queue.addLast(aPath);
+
+ List result = new LinkedList();
+ processQueue(anObject, queue, result);
+ TreePath[] paths = new TreePath[result.size()];
+ for (int i = 0; i < paths.length; i++) {
+ paths[i] = (TreePath) result.get(i);
+ }
+ return paths;
+ }
+
+ /**
+ * Processes the specified queue, appending results to aResult if it exists, or
+ * returning immediately with a TreePath is aResult is null.
+ */
+ private TreePath processQueue(Object anObject, LinkedList aQueue, List aResult) {
+ TreePath path;
+ while (!aQueue.isEmpty()) {
+ path = (TreePath) aQueue.removeFirst();
+ path = checkNode(anObject, path, aQueue);
+ if (path != null) {
+ if (aResult != null) {
+ aResult.add(path);
+ } else {
+ return path;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compares the specified object by reference each of the children of the node
+ * at the end of the specified tree path, adding nodes that do not match but
+ * have fetched object to the end of the specified queue. Returns the path of
+ * the first child node that matches the specified object, or null if no match
+ * was found.
+ */
+ private TreePath checkNode(Object anObject, TreePath aPath, LinkedList aQueue) {
+ TreePath result = null;
+ Object child;
+ Object parent = aPath.getLastPathComponent();
+ int count = getChildCount(parent);
+
+ for (int i = 0; i < count; i++) {
+ child = getChild(parent, i);
+
+ // add to queue if node has fetched children
+ if (((DisplayGroupNode) child).isFetched) {
+ aQueue.addLast(aPath.pathByAddingChild(child));
+ }
+
+ // compares by reference
+ if (((DisplayGroupNode) child).object() == anObject) {
+ // assumes same object cannot be in display group twice
+ result = aPath.pathByAddingChild(child);
//System.out.println( "TRUE: " + ((DisplayGroupNode)child).object() + " == " + anObject );
- }
+ }
// else
// {
//System.out.println( ((DisplayGroupNode)child).object() + " != " + anObject );
// }
- }
- return result;
- }
-
- // interface TreeSelectionListener
-
- public void valueChanged(TreeSelectionEvent e)
- {
- if ( ! isListening ) return;
- selectFromSelectionModel();
- }
-
- /**
- * Determines whether the selection should be painted
- * immediately after the user clicks and therefore
- * before the children display group is updated.
- * When the children group is bound to many associations
- * or is bound to a master-detail association, updating
- * the display group can take a perceptibly long time.
- * This property defaults to false.
- * @see #setSelectionPaintedImmediately
- */
- public boolean isSelectionPaintedImmediately()
- {
- return selectionPaintedImmediately;
- }
-
- /**
- * Sets whether the selection should be painted immediately.
- * Setting this property to true will let the tree paint
- * first before the display group is updated.
- * This means that any tree selection listers will
- * also be notified before the display group is updated
- * and will have to invokeLater if they want to see the
- * updated display group.
- */
- public void setSelectionPaintedImmediately( boolean isImmediate )
- {
- selectionPaintedImmediately = isImmediate;
- }
-
- /**
- * Package access so DisplayGroupNode can replace the selection.
- * Returns the display group containing the current selection: titles or children.
- */
- EODisplayGroup selectFromSelectionModel()
- { // System.out.print( "selectFromSelectionModel: " );
- removeAsListener();
- DisplayGroupNode node;
- TreePath parentPath;
- TreePath[] selectedPaths = selectionModel.getSelectionPaths();
- NSMutableArray selectionList = new NSMutableArray();
- if ( selectedPaths != null )
- {
- for ( int i = 0; i < selectedPaths.length; i++ )
- {
- // root node is zero - ignore root node
- if ( ( selectedPaths[i].getLastPathComponent() == rootNode ) )
- {
- // select root in selectFromDisplayGroup()
- pleaseSelectRootNode = true;
- }
- else
- {
- node = (DisplayGroupNode)
- selectedPaths[i].getLastPathComponent();
- Object o = node.object();
-
- if ( selectionList.indexOfIdenticalObject(o) == NSArray.NotFound )
- {
- selectionList.addObject( o );
- }
- }
- }
- }
- childrenDisplayGroup.fetch(); //note that we're not currently listening for changes
- if ( ! childrenDisplayGroup.selectObjectsIdenticalTo( selectionList ) )
- {
- addAsListener(); // because we don't have a listener stack
- selectFromDisplayGroup( childrenDisplayGroup );
- removeAsListener();
- }
- addAsListener();
- return childrenDisplayGroup; // titles is now children if children not explicitly set
- }
-
- // interface TreeModel
-
- public Object getRoot()
- {
- return rootNode;
- }
-
- public Object getChild(Object parent, int index)
- {
- // interestingly, this gets called by
- // BasicTreeUI.paintVerticalPartOfLeg for
- // the last child of each expanded tree node.
- Object result = ((DisplayGroupNode)parent).getChildNodeAt( index );
+ }
+ return result;
+ }
+
+ // interface TreeSelectionListener
+
+ public void valueChanged(TreeSelectionEvent e) {
+ if (!isListening)
+ return;
+ selectFromSelectionModel();
+ }
+
+ /**
+ * Determines whether the selection should be painted immediately after the user
+ * clicks and therefore before the children display group is updated. When the
+ * children group is bound to many associations or is bound to a master-detail
+ * association, updating the display group can take a perceptibly long time.
+ * This property defaults to false.
+ *
+ * @see #setSelectionPaintedImmediately
+ */
+ public boolean isSelectionPaintedImmediately() {
+ return selectionPaintedImmediately;
+ }
+
+ /**
+ * Sets whether the selection should be painted immediately. Setting this
+ * property to true will let the tree paint first before the display group is
+ * updated. This means that any tree selection listers will also be notified
+ * before the display group is updated and will have to invokeLater if they want
+ * to see the updated display group.
+ */
+ public void setSelectionPaintedImmediately(boolean isImmediate) {
+ selectionPaintedImmediately = isImmediate;
+ }
+
+ /**
+ * Package access so DisplayGroupNode can replace the selection. Returns the
+ * display group containing the current selection: titles or children.
+ */
+ EODisplayGroup selectFromSelectionModel() { // System.out.print( "selectFromSelectionModel: " );
+ removeAsListener();
+ DisplayGroupNode node;
+ TreePath parentPath;
+ TreePath[] selectedPaths = selectionModel.getSelectionPaths();
+ NSMutableArray selectionList = new NSMutableArray();
+ if (selectedPaths != null) {
+ for (int i = 0; i < selectedPaths.length; i++) {
+ // root node is zero - ignore root node
+ if ((selectedPaths[i].getLastPathComponent() == rootNode)) {
+ // select root in selectFromDisplayGroup()
+ pleaseSelectRootNode = true;
+ } else {
+ node = (DisplayGroupNode) selectedPaths[i].getLastPathComponent();
+ Object o = node.object();
+
+ if (selectionList.indexOfIdenticalObject(o) == NSArray.NotFound) {
+ selectionList.addObject(o);
+ }
+ }
+ }
+ }
+ childrenDisplayGroup.fetch(); // note that we're not currently listening for changes
+ if (!childrenDisplayGroup.selectObjectsIdenticalTo(selectionList)) {
+ addAsListener(); // because we don't have a listener stack
+ selectFromDisplayGroup(childrenDisplayGroup);
+ removeAsListener();
+ }
+ addAsListener();
+ return childrenDisplayGroup; // titles is now children if children not explicitly set
+ }
+
+ // interface TreeModel
+
+ public Object getRoot() {
+ return rootNode;
+ }
+
+ public Object getChild(Object parent, int index) {
+ // interestingly, this gets called by
+ // BasicTreeUI.paintVerticalPartOfLeg for
+ // the last child of each expanded tree node.
+ Object result = ((DisplayGroupNode) parent).getChildNodeAt(index);
//((DisplayGroupNode)parent).suppressRecentChangeProcessing();
-return result;
+ return result;
// return ((DisplayGroupNode)parent).getChildNodeAt( index );
- }
+ }
- public int getChildCount(Object parent)
- {
- int result = ((DisplayGroupNode)parent).getChildCount();
+ public int getChildCount(Object parent) {
+ int result = ((DisplayGroupNode) parent).getChildCount();
//((DisplayGroupNode)parent).suppressRecentChangeProcessing();
-return result;
+ return result;
// return ((DisplayGroupNode)parent).getChildCount();
- }
+ }
- public boolean isLeaf(Object node)
- {
- boolean result = ((DisplayGroupNode)node).isLeaf();
+ public boolean isLeaf(Object node) {
+ boolean result = ((DisplayGroupNode) node).isLeaf();
//((DisplayGroupNode)node).suppressRecentChangeProcessing();
-return result;
+ return result;
// return ((DisplayGroupNode)node).isLeaf();
- }
-
- /**
- * Returns whether this node is visible in the UI.
- * This implementation returns true.
- * <br><br>
- * Subclasses should return false if they can
- * determine that the node is not displayed or
- * expanded or otherwise visible. Non-visible
- * nodes will fetch only when they are shown.
- */
- public boolean isVisible(Object node)
- {
- return true;
- }
-
- public void valueForPathChanged(TreePath path, Object newValue)
- {
- ((DisplayGroupNode)path.getLastPathComponent()).setUserObject( newValue );
- }
-
- public int getIndexOfChild(Object parent, Object child)
- {
- int result = ((DisplayGroupNode)parent).getIndex( (DisplayGroupNode) child );
+ }
+
+ /**
+ * Returns whether this node is visible in the UI. This implementation returns
+ * true. <br>
+ * <br>
+ * Subclasses should return false if they can determine that the node is not
+ * displayed or expanded or otherwise visible. Non-visible nodes will fetch only
+ * when they are shown.
+ */
+ public boolean isVisible(Object node) {
+ return true;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue) {
+ ((DisplayGroupNode) path.getLastPathComponent()).setUserObject(newValue);
+ }
+
+ public int getIndexOfChild(Object parent, Object child) {
+ int result = ((DisplayGroupNode) parent).getIndex((DisplayGroupNode) child);
//((DisplayGroupNode)parent).suppressRecentChangeProcessing();
-return result;
+ return result;
// return ((DisplayGroupNode)parent).getIndex( (DisplayGroupNode) child );
- }
-
- public void addTreeModelListener(TreeModelListener aListener)
- {
- listeners.add( aListener );
- }
- public void removeTreeModelListener(TreeModelListener aListener)
- {
- listeners.remove( aListener );
- }
-
- /**
- * Fires a tree nodes changed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesChanged(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
-
- willChange(); // queue processRecentChanges
- TreeModelEvent event = new TreeModelEvent(
- source, path, childIndices, children );
+ }
+
+ public void addTreeModelListener(TreeModelListener aListener) {
+ listeners.add(aListener);
+ }
+
+ public void removeTreeModelListener(TreeModelListener aListener) {
+ listeners.remove(aListener);
+ }
+
+ /**
+ * Fires a tree nodes changed event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
+
+ willChange(); // queue processRecentChanges
+ TreeModelEvent event = new TreeModelEvent(source, path, childIndices, children);
//System.out.println( "fireTreeNodesChanged: " + event );
- Enumeration it = listeners.elements();
- while ( it.hasMoreElements() )
- {
- try
- {
- ((TreeModelListener)it.nextElement()).treeNodesChanged( event );
- }
- catch ( Exception exc )
- {
- System.out.println( "TreeModelAssociation.fireTreeNodesChanged: caught: " + exc );
- System.out.println( "Source:" + source );
- System.out.println( "Path:" );
- for ( int i = 0; i < path.length; i++ )
- {
- System.out.print( path[i] + "-" );
- }
- System.out.println();
- System.out.println( "Indices:" );
- for ( int i = 0; i < childIndices.length; i++ )
- {
- System.out.print( childIndices[i] + "-" );
- }
- System.out.println();
- System.out.println( "Children:" );
- for ( int i = 0; i < children.length; i++ )
- {
- System.out.print( children[i] + "-" );
- }
- System.out.println();
- exc.printStackTrace();
- }
- }
- }
-
- /**
- * Fires a tree nodes inserted event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesInserted(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
-
- willChange(); // queue processRecentChanges
- TreeModelEvent event = new TreeModelEvent(
- source, path, childIndices, children );
+ Enumeration it = listeners.elements();
+ while (it.hasMoreElements()) {
+ try {
+ ((TreeModelListener) it.nextElement()).treeNodesChanged(event);
+ } catch (Exception exc) {
+ System.out.println("TreeModelAssociation.fireTreeNodesChanged: caught: " + exc);
+ System.out.println("Source:" + source);
+ System.out.println("Path:");
+ for (int i = 0; i < path.length; i++) {
+ System.out.print(path[i] + "-");
+ }
+ System.out.println();
+ System.out.println("Indices:");
+ for (int i = 0; i < childIndices.length; i++) {
+ System.out.print(childIndices[i] + "-");
+ }
+ System.out.println();
+ System.out.println("Children:");
+ for (int i = 0; i < children.length; i++) {
+ System.out.print(children[i] + "-");
+ }
+ System.out.println();
+ exc.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Fires a tree nodes inserted event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) {
+
+ willChange(); // queue processRecentChanges
+ TreeModelEvent event = new TreeModelEvent(source, path, childIndices, children);
//System.out.println( "fireTreeNodesInserted: " + event );
- Enumeration it = listeners.elements();
- while ( it.hasMoreElements() )
- {
- try
- {
- ((TreeModelListener)it.nextElement()).treeNodesInserted( event );
- }
- catch ( Exception exc )
- {
- System.out.println( "TreeModelAssociation.fireTreeNodesInserted: caught: " + exc );
- }
- }
- }
-
- /**
- * Fires a tree nodes removed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeNodesRemoved(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
-
- willChange(); // queue processRecentChanges
- TreeModelEvent event = new TreeModelEvent(
- source, path, childIndices, children );
+ Enumeration it = listeners.elements();
+ while (it.hasMoreElements()) {
+ try {
+ ((TreeModelListener) it.nextElement()).treeNodesInserted(event);
+ } catch (Exception exc) {
+ System.out.println("TreeModelAssociation.fireTreeNodesInserted: caught: " + exc);
+ }
+ }
+ }
+
+ /**
+ * Fires a tree nodes removed event to all listeners. Provided as a convenience
+ * if you need to make manual changes to the tree model.
+ */
+ public void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) {
+
+ willChange(); // queue processRecentChanges
+ TreeModelEvent event = new TreeModelEvent(source, path, childIndices, children);
//System.out.println( "fireTreeNodesRemoved: " + event );
- Enumeration it = listeners.elements();
- while ( it.hasMoreElements() )
- {
- try
- {
- //NOTE: removing nodes causes tree to fire selection change event
- // which confuses us if we're rearranging nodes (when sorting, for example).
- boolean wasListening = isListening;
- if ( wasListening ) isListening = false;
- ((TreeModelListener)it.nextElement()).treeNodesRemoved( event );
- if ( wasListening ) isListening = true;
- }
- catch ( Exception exc )
- {
- System.out.println( "TreeModelAssociation.fireTreeNodesRemoved: caught: " + exc );
- }
- }
- }
-
- /**
- * Fires a tree structure changed event to all listeners.
- * Provided as a convenience if you need to make manual
- * changes to the tree model.
- */
- public void fireTreeStructureChanged(Object source,
- Object[] path,
- int[] childIndices,
- Object[] children)
- {
-
- willChange(); // queue processRecentChanges
- TreeModelEvent event = new TreeModelEvent(
- source, path, childIndices, children );
+ Enumeration it = listeners.elements();
+ while (it.hasMoreElements()) {
+ try {
+ // NOTE: removing nodes causes tree to fire selection change event
+ // which confuses us if we're rearranging nodes (when sorting, for example).
+ boolean wasListening = isListening;
+ if (wasListening)
+ isListening = false;
+ ((TreeModelListener) it.nextElement()).treeNodesRemoved(event);
+ if (wasListening)
+ isListening = true;
+ } catch (Exception exc) {
+ System.out.println("TreeModelAssociation.fireTreeNodesRemoved: caught: " + exc);
+ }
+ }
+ }
+
+ /**
+ * Fires a tree structure changed event to all listeners. Provided as a
+ * convenience if you need to make manual changes to the tree model.
+ */
+ public void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
+
+ willChange(); // queue processRecentChanges
+ TreeModelEvent event = new TreeModelEvent(source, path, childIndices, children);
//System.out.println( "fireStructureChanged: " + event );
- Enumeration it = listeners.elements();
- while ( it.hasMoreElements() )
- {
- ((TreeModelListener)it.nextElement()).treeStructureChanged( event );
- }
- }
-
- /**
- * Creates and returns a new display group node.
- */
- public DisplayGroupNode createNode( EODisplayGroup aParentGroup, Object anObject )
- {
- return new MutableDisplayGroupNode( this, aParentGroup, anObject );
- }
-
- /**
- * Gets whether new objects programmatically inserted into the children
- * display group should be inserted as a child of the first selected node.
- * If false, new objects are inserted as siblings of the first selected node.
- * Default value is true.
- */
- public boolean isInsertingChild()
- {
- return insertingChild;
- }
-
- /**
- * Sets whether new objects programmatically inserted into the children
- * display group should be inserted as a child of the first selected node.
- * If false, new objects are inserted as siblings of the first selected node.
- * Default value is true.
- */
- public void setInsertingChild( boolean asChild )
- {
- insertingChild = asChild;
- }
-
- /**
- * Determines where new objects programmatically inserted into the children
- * display group should be inserted, based on the value of insertingChild.
- * If insertingChild, isInsertingAfter causes objects to be inserted at
- * the end of the selected node's child list; otherwise, objects are inserted
- * at the beginning of the list.
- * If inserting as a sibling, isInsertingAfter causes objects to be inserted
- * before the selected node in the selected node's parent's child list;
- * otherwise, objects are inserted after the selected node in the child list.
- * Default value is true.
- */
- public boolean isInsertingAfter()
- {
- return insertingAfter;
- }
-
- /**
- * Determines where new objects programmatically inserted into the children
- * display group should be inserted, based on the value of insertingChild.
- * If insertingChild, isInsertingAfter causes objects to be inserted at
- * the end of the selected node's child list; otherwise, objects are inserted
- * at the beginning of the list.
- * If inserting as a sibling, isInsertingAfter causes objects to be inserted
- * before the selected node in the selected node's parent's child list;
- * otherwise, objects are inserted after the selected node in the child list.
- * Default value is true.
- */
- public void setInsertingAfter( boolean after )
- {
- insertingAfter = after;
- }
-
- /**
- * Called to by the children group's data source when it receives
- * an insertObject message, usually after an object has been inserted
- * into the children display group.
- * Return the object that should be passed to the titles display
- * group's data source's implementation of insertObject, or return
- * null to prevent that method from being called. <br><br>
- * This implementation inserts the specified object into the tree
- * as determined by calling isInsertingChild and isInsertingAfter,
- * then returns the unmodified object. If there's no selection, or
- * no selection model, the root node is assumed to be selected.
- * And if the root node is selected, the new node will obviously be
- * inserted as a child. Override to customize.
- */
- protected Object objectInsertedIntoChildrenGroup( Object anObject )
- {
- // determine selection
- DisplayGroupNode selectedNode = (DisplayGroupNode) getRoot();
- if ( selectionModel != null )
- {
- // get selected path
- TreePath path = selectionModel.getSelectionPath();
-
- // get selected node
- if ( path != null )
- {
- selectedNode = (DisplayGroupNode) path.getLastPathComponent();
- }
- }
- // determine location of insertion
- int index = 0;
- if ( ( isInsertingChild() ) || ( selectedNode == getRoot() ) )
- {
- if ( isInsertingAfter() )
- {
- index = selectedNode.getChildCount();
- }
- }
- else // inserting as sibling
- {
- DisplayGroupNode parentNode = selectedNode.getParentGroup();
- index = parentNode.getIndex( selectedNode );
- if ( isInsertingAfter() )
- {
- index++;
- }
- selectedNode = parentNode;
- }
-
- // insert and return
- selectedNode.insertObjectAtIndex( anObject, index );
- return anObject;
- }
-
- /**
- * Called to by the children group's data source when it receives
- * a deleteObject message, usually after an object has been deleted
- * from the children display group.
- * Return the object that should be passed to the titles display
- * group's data source's implementation of deleteObject, or return
- * null to prevent that method from being called. <br><br>
- * This implementation deletes all instances of the selected object
- * from the tree nodes that are currently loaded, and returns the
- * unmodified object. Override to customize.
- */
- protected Object objectDeletedFromChildrenGroup( Object anObject )
- {
- TreePath[] paths = getPathsForObject( anObject );
- if ( paths != null )
- {
- for ( int i = 0; i < paths.length; i++ )
- {
- ((DisplayGroupNode)paths[i].getLastPathComponent()).removeFromParent();
- }
- }
- return anObject;
- }
-
- /**
- * Called to by the children group's data source to populate it
- * with all selected nodes and their siblings. To customize,
- * override this method, or specify a different data source for
- * the children display group.
- */
- protected NSArray objectsFetchedIntoChildrenGroup()
- {
- DisplayGroupNode node;
- TreePath parentPath;
- TreePath[] selectedPaths = selectionModel.getSelectionPaths();
- NSMutableArray objectList = new NSMutableArray();
- if ( selectedPaths != null )
- {
- for ( int i = 0; i < selectedPaths.length; i++ )
- {
- // root node is zero - ignore root node
- if ( ( selectedPaths[i].getLastPathComponent() == rootNode ) )
- {
- // select root in selectFromDisplayGroup()
- pleaseSelectRootNode = true;
- }
- else
- {
- node = (DisplayGroupNode)
- selectedPaths[i].getLastPathComponent();
- Object o = node.object();
-
- // add all children of parent to object list - includes self
- if ( node.parentGroup != null )
- {
- Enumeration e =
- node.parentGroup.displayedObjects().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- // add only if not already in list
- o = e.nextElement();
- if ( objectList.indexOfIdenticalObject(o) == NSArray.NotFound )
- {
- objectList.addObject( o );
- }
- }
- }
- else // no parent node - add the node by itself
- {
- // add only if not already in list
- if ( objectList.indexOfIdenticalObject(o) == NSArray.NotFound )
- {
- objectList.addObject( o );
- }
- }
- }
- }
- }
-
- // if no selection
- if ( objectList.size() == 0 )
- {
- // populate with children of root
- objectList.addAll( rootNode.displayedObjects() );
- }
- return objectList;
- }
-
- /**
- * Queues processRecentChanges to be run in the event queue.
- */
- private void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- /**
- * Tells the children display group to refetch, so that it reflects
- * any changes that were made in the node tree,
- * and then updates the selection in the selection model.
- * Triggered in response to willChange().
- */
- public void processRecentChanges()
- {
- Runnable update = new Runnable()
- {
- public void run()
- {
- removeAsListener(); // prevent data source refetch: see fetchObjects()
- childrenDisplayGroup.fetch();
- addAsListener();
- selectFromDisplayGroup( childrenDisplayGroup );
- }
- };
- if ( isListening )
- {
- if ( selectionPaintedImmediately )
- {
- // if painting selection immediately, run even later
- // so that AWT's repaint event fires before we do.
- SwingUtilities.invokeLater( update );
- }
- else
- {
- // otherwise run now
- update.run();
- }
- }
- }
-
- /**
- * Delegates most behaviors to the specified data source,
- * except fetchObjects, which calls fetchObjectsIntoChildrenGroup
- * on the tree model association. If delegate is null,
- * calls are passed to the superclass which is a PropertyDataSource.
- */
- static class DelegatingTreeDataSource extends PropertyDataSource
- {
- TreeModelAssociation parentAssociation;
- EODataSource delegateDataSource;
-
- public DelegatingTreeDataSource(
- TreeModelAssociation aTreeModelAssociation, EODataSource aDataSource )
- {
- parentAssociation = aTreeModelAssociation;
- delegateDataSource = aDataSource;
- }
-
- /**
- * Calls to delegateDataSource if it exists, otherwise
- * calls to super.
- */
- public Object createObject()
- {
- if ( delegateDataSource != null )
- {
- return delegateDataSource.createObject();
- }
- return super.createObject();
- }
-
- /**
- * Calls objectInsertedIntoChildrenGroup, and if not null
- * calls to delegateDataSource.insertObject if it exists,
- * and super.insertObjectAtIndex if not.
- */
- public void insertObjectAtIndex( Object anObject, int anIndex )
- {
- anObject =
- parentAssociation.objectInsertedIntoChildrenGroup(
- anObject );
- if ( anObject != null )
- {
- if ( delegateDataSource != null )
- {
- if ( delegateDataSource instanceof OrderedDataSource )
- {
- ((OrderedDataSource)delegateDataSource).insertObjectAtIndex( anObject, anIndex );
- }
- else
- {
- delegateDataSource.insertObject( anObject );
- }
- }
- else
- {
- super.insertObjectAtIndex( anObject, anIndex );
- }
- }
- }
-
- /**
- * Calls objectDeletedIntoChildrenGroup, and if not null
- * calls to delegateDataSource if it exists.
- */
- public void deleteObject( Object anObject )
- {
- anObject =
- parentAssociation.objectDeletedFromChildrenGroup(
- anObject );
- if ( anObject != null )
- {
- if ( delegateDataSource != null )
- {
- delegateDataSource.deleteObject( anObject );
- }
- super.deleteObject( anObject );
- }
- }
-
- /**
- * Overridden to return the delegate's editing context,
- * the titles display group's editing context,
- * and failing that calling to super.
- */
- public EOEditingContext editingContext ()
- {
- EOEditingContext result = null;
- if ( delegateDataSource != null )
- {
- result = delegateDataSource.editingContext();
- }
- if ( result == null )
- {
- EODataSource parentDataSource =
- parentAssociation.titlesDisplayGroup.dataSource();
- if ( parentDataSource != this && parentDataSource != null )
- {
- result = parentAssociation.titlesDisplayGroup.
- dataSource().editingContext();
- }
- }
- if ( result == null )
- {
- result = super.editingContext();
- }
- return result;
- }
-
- /**
- * Returns a List containing the objects in this
- * data source.
- */
- public NSArray fetchObjects ()
- {
- // if titles group is doing double-duty as children group
- if ( parentAssociation.titlesDisplayGroup == parentAssociation.childrenDisplayGroup )
- {
- // if we're not initiating this fetch
- if ( parentAssociation.isListening )
- {
- // need to call to delegate to see if we should update values
- if ( delegateDataSource != null )
- {
+ Enumeration it = listeners.elements();
+ while (it.hasMoreElements()) {
+ ((TreeModelListener) it.nextElement()).treeStructureChanged(event);
+ }
+ }
+
+ /**
+ * Creates and returns a new display group node.
+ */
+ public DisplayGroupNode createNode(EODisplayGroup aParentGroup, Object anObject) {
+ return new MutableDisplayGroupNode(this, aParentGroup, anObject);
+ }
+
+ /**
+ * Gets whether new objects programmatically inserted into the children display
+ * group should be inserted as a child of the first selected node. If false, new
+ * objects are inserted as siblings of the first selected node. Default value is
+ * true.
+ */
+ public boolean isInsertingChild() {
+ return insertingChild;
+ }
+
+ /**
+ * Sets whether new objects programmatically inserted into the children display
+ * group should be inserted as a child of the first selected node. If false, new
+ * objects are inserted as siblings of the first selected node. Default value is
+ * true.
+ */
+ public void setInsertingChild(boolean asChild) {
+ insertingChild = asChild;
+ }
+
+ /**
+ * Determines where new objects programmatically inserted into the children
+ * display group should be inserted, based on the value of insertingChild. If
+ * insertingChild, isInsertingAfter causes objects to be inserted at the end of
+ * the selected node's child list; otherwise, objects are inserted at the
+ * beginning of the list. If inserting as a sibling, isInsertingAfter causes
+ * objects to be inserted before the selected node in the selected node's
+ * parent's child list; otherwise, objects are inserted after the selected node
+ * in the child list. Default value is true.
+ */
+ public boolean isInsertingAfter() {
+ return insertingAfter;
+ }
+
+ /**
+ * Determines where new objects programmatically inserted into the children
+ * display group should be inserted, based on the value of insertingChild. If
+ * insertingChild, isInsertingAfter causes objects to be inserted at the end of
+ * the selected node's child list; otherwise, objects are inserted at the
+ * beginning of the list. If inserting as a sibling, isInsertingAfter causes
+ * objects to be inserted before the selected node in the selected node's
+ * parent's child list; otherwise, objects are inserted after the selected node
+ * in the child list. Default value is true.
+ */
+ public void setInsertingAfter(boolean after) {
+ insertingAfter = after;
+ }
+
+ /**
+ * Called to by the children group's data source when it receives an
+ * insertObject message, usually after an object has been inserted into the
+ * children display group. Return the object that should be passed to the titles
+ * display group's data source's implementation of insertObject, or return null
+ * to prevent that method from being called. <br>
+ * <br>
+ * This implementation inserts the specified object into the tree as determined
+ * by calling isInsertingChild and isInsertingAfter, then returns the unmodified
+ * object. If there's no selection, or no selection model, the root node is
+ * assumed to be selected. And if the root node is selected, the new node will
+ * obviously be inserted as a child. Override to customize.
+ */
+ protected Object objectInsertedIntoChildrenGroup(Object anObject) {
+ // determine selection
+ DisplayGroupNode selectedNode = (DisplayGroupNode) getRoot();
+ if (selectionModel != null) {
+ // get selected path
+ TreePath path = selectionModel.getSelectionPath();
+
+ // get selected node
+ if (path != null) {
+ selectedNode = (DisplayGroupNode) path.getLastPathComponent();
+ }
+ }
+ // determine location of insertion
+ int index = 0;
+ if ((isInsertingChild()) || (selectedNode == getRoot())) {
+ if (isInsertingAfter()) {
+ index = selectedNode.getChildCount();
+ }
+ } else // inserting as sibling
+ {
+ DisplayGroupNode parentNode = selectedNode.getParentGroup();
+ index = parentNode.getIndex(selectedNode);
+ if (isInsertingAfter()) {
+ index++;
+ }
+ selectedNode = parentNode;
+ }
+
+ // insert and return
+ selectedNode.insertObjectAtIndex(anObject, index);
+ return anObject;
+ }
+
+ /**
+ * Called to by the children group's data source when it receives a deleteObject
+ * message, usually after an object has been deleted from the children display
+ * group. Return the object that should be passed to the titles display group's
+ * data source's implementation of deleteObject, or return null to prevent that
+ * method from being called. <br>
+ * <br>
+ * This implementation deletes all instances of the selected object from the
+ * tree nodes that are currently loaded, and returns the unmodified object.
+ * Override to customize.
+ */
+ protected Object objectDeletedFromChildrenGroup(Object anObject) {
+ TreePath[] paths = getPathsForObject(anObject);
+ if (paths != null) {
+ for (int i = 0; i < paths.length; i++) {
+ ((DisplayGroupNode) paths[i].getLastPathComponent()).removeFromParent();
+ }
+ }
+ return anObject;
+ }
+
+ /**
+ * Called to by the children group's data source to populate it with all
+ * selected nodes and their siblings. To customize, override this method, or
+ * specify a different data source for the children display group.
+ */
+ protected NSArray objectsFetchedIntoChildrenGroup() {
+ DisplayGroupNode node;
+ TreePath parentPath;
+ TreePath[] selectedPaths = selectionModel.getSelectionPaths();
+ NSMutableArray objectList = new NSMutableArray();
+ if (selectedPaths != null) {
+ for (int i = 0; i < selectedPaths.length; i++) {
+ // root node is zero - ignore root node
+ if ((selectedPaths[i].getLastPathComponent() == rootNode)) {
+ // select root in selectFromDisplayGroup()
+ pleaseSelectRootNode = true;
+ } else {
+ node = (DisplayGroupNode) selectedPaths[i].getLastPathComponent();
+ Object o = node.object();
+
+ // add all children of parent to object list - includes self
+ if (node.parentGroup != null) {
+ Enumeration e = node.parentGroup.displayedObjects().objectEnumerator();
+ while (e.hasMoreElements()) {
+ // add only if not already in list
+ o = e.nextElement();
+ if (objectList.indexOfIdenticalObject(o) == NSArray.NotFound) {
+ objectList.addObject(o);
+ }
+ }
+ } else // no parent node - add the node by itself
+ {
+ // add only if not already in list
+ if (objectList.indexOfIdenticalObject(o) == NSArray.NotFound) {
+ objectList.addObject(o);
+ }
+ }
+ }
+ }
+ }
+
+ // if no selection
+ if (objectList.size() == 0) {
+ // populate with children of root
+ objectList.addAll(rootNode.displayedObjects());
+ }
+ return objectList;
+ }
+
+ /**
+ * Queues processRecentChanges to be run in the event queue.
+ */
+ private void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ /**
+ * Tells the children display group to refetch, so that it reflects any changes
+ * that were made in the node tree, and then updates the selection in the
+ * selection model. Triggered in response to willChange().
+ */
+ public void processRecentChanges() {
+ Runnable update = new Runnable() {
+ public void run() {
+ removeAsListener(); // prevent data source refetch: see fetchObjects()
+ childrenDisplayGroup.fetch();
+ addAsListener();
+ selectFromDisplayGroup(childrenDisplayGroup);
+ }
+ };
+ if (isListening) {
+ if (selectionPaintedImmediately) {
+ // if painting selection immediately, run even later
+ // so that AWT's repaint event fires before we do.
+ SwingUtilities.invokeLater(update);
+ } else {
+ // otherwise run now
+ update.run();
+ }
+ }
+ }
+
+ /**
+ * Delegates most behaviors to the specified data source, except fetchObjects,
+ * which calls fetchObjectsIntoChildrenGroup on the tree model association. If
+ * delegate is null, calls are passed to the superclass which is a
+ * PropertyDataSource.
+ */
+ static class DelegatingTreeDataSource extends PropertyDataSource {
+ TreeModelAssociation parentAssociation;
+ EODataSource delegateDataSource;
+
+ public DelegatingTreeDataSource(TreeModelAssociation aTreeModelAssociation, EODataSource aDataSource) {
+ parentAssociation = aTreeModelAssociation;
+ delegateDataSource = aDataSource;
+ }
+
+ /**
+ * Calls to delegateDataSource if it exists, otherwise calls to super.
+ */
+ public Object createObject() {
+ if (delegateDataSource != null) {
+ return delegateDataSource.createObject();
+ }
+ return super.createObject();
+ }
+
+ /**
+ * Calls objectInsertedIntoChildrenGroup, and if not null calls to
+ * delegateDataSource.insertObject if it exists, and super.insertObjectAtIndex
+ * if not.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ anObject = parentAssociation.objectInsertedIntoChildrenGroup(anObject);
+ if (anObject != null) {
+ if (delegateDataSource != null) {
+ if (delegateDataSource instanceof OrderedDataSource) {
+ ((OrderedDataSource) delegateDataSource).insertObjectAtIndex(anObject, anIndex);
+ } else {
+ delegateDataSource.insertObject(anObject);
+ }
+ } else {
+ super.insertObjectAtIndex(anObject, anIndex);
+ }
+ }
+ }
+
+ /**
+ * Calls objectDeletedIntoChildrenGroup, and if not null calls to
+ * delegateDataSource if it exists.
+ */
+ public void deleteObject(Object anObject) {
+ anObject = parentAssociation.objectDeletedFromChildrenGroup(anObject);
+ if (anObject != null) {
+ if (delegateDataSource != null) {
+ delegateDataSource.deleteObject(anObject);
+ }
+ super.deleteObject(anObject);
+ }
+ }
+
+ /**
+ * Overridden to return the delegate's editing context, the titles display
+ * group's editing context, and failing that calling to super.
+ */
+ public EOEditingContext editingContext() {
+ EOEditingContext result = null;
+ if (delegateDataSource != null) {
+ result = delegateDataSource.editingContext();
+ }
+ if (result == null) {
+ EODataSource parentDataSource = parentAssociation.titlesDisplayGroup.dataSource();
+ if (parentDataSource != this && parentDataSource != null) {
+ result = parentAssociation.titlesDisplayGroup.dataSource().editingContext();
+ }
+ }
+ if (result == null) {
+ result = super.editingContext();
+ }
+ return result;
+ }
+
+ /**
+ * Returns a List containing the objects in this data source.
+ */
+ public NSArray fetchObjects() {
+ // if titles group is doing double-duty as children group
+ if (parentAssociation.titlesDisplayGroup == parentAssociation.childrenDisplayGroup) {
+ // if we're not initiating this fetch
+ if (parentAssociation.isListening) {
+ // need to call to delegate to see if we should update values
+ if (delegateDataSource != null) {
// System.out.println( "fetching from delegate (slow!)" );
- NSArray result = delegateDataSource.fetchObjects();
- NSArray rootObjects = parentAssociation.rootNode.displayedObjects();
- // if titles data source has different objects, return them
- if ( rootObjects.count() != result.count()
- || ! rootObjects.containsAll( result ) )
- {
- // this will force the root node to repopulate in subjectChanged()
+ NSArray result = delegateDataSource.fetchObjects();
+ NSArray rootObjects = parentAssociation.rootNode.displayedObjects();
+ // if titles data source has different objects, return them
+ if (rootObjects.count() != result.count() || !rootObjects.containsAll(result)) {
+ // this will force the root node to repopulate in subjectChanged()
//System.out.println( "fetchObjects: data source" );
- return result;
- }
- }
- }
- }
- // otherwise: just repopulate the titles group
+ return result;
+ }
+ }
+ }
+ }
+ // otherwise: just repopulate the titles group
//System.out.println( "fetchObjects: objectsFetchedIntoChildrenGroup" );
- return parentAssociation.objectsFetchedIntoChildrenGroup();
- }
-
- /**
- * Returns a data source that is capable of
- * manipulating objects of the type returned by
- * applying the specified key to objects
- * vended by this data source.
- * @see #qualifyWithRelationshipKey
- */
- public EODataSource
- dataSourceQualifiedByKey ( String aKey )
- {
- if ( delegateDataSource != null )
- {
- return delegateDataSource.dataSourceQualifiedByKey( aKey );
- }
- return null;
- }
-
- /**
- * Restricts this data source to vend those
- * objects that are associated with the specified
- * key on the specified object.
- */
- public void
- qualifyWithRelationshipKey (
- String aKey, Object anObject )
- {
- if ( delegateDataSource != null )
- {
- delegateDataSource.qualifyWithRelationshipKey( aKey, anObject );
- }
- }
-
- /**
- * Returns the value from the delegateDataSource, if it exists.
- * Otherwise calls super.
- */
- public EOClassDescription classDescriptionForObjects()
- {
- if ( delegateDataSource != null )
- {
- return delegateDataSource.classDescriptionForObjects();
- }
- return super.classDescriptionForObjects();
- }
-
- }
-
+ return parentAssociation.objectsFetchedIntoChildrenGroup();
+ }
+
+ /**
+ * Returns a data source that is capable of manipulating objects of the type
+ * returned by applying the specified key to objects vended by this data source.
+ *
+ * @see #qualifyWithRelationshipKey
+ */
+ public EODataSource dataSourceQualifiedByKey(String aKey) {
+ if (delegateDataSource != null) {
+ return delegateDataSource.dataSourceQualifiedByKey(aKey);
+ }
+ return null;
+ }
+
+ /**
+ * Restricts this data source to vend those objects that are associated with the
+ * specified key on the specified object.
+ */
+ public void qualifyWithRelationshipKey(String aKey, Object anObject) {
+ if (delegateDataSource != null) {
+ delegateDataSource.qualifyWithRelationshipKey(aKey, anObject);
+ }
+ }
+
+ /**
+ * Returns the value from the delegateDataSource, if it exists. Otherwise calls
+ * super.
+ */
+ public EOClassDescription classDescriptionForObjects() {
+ if (delegateDataSource != null) {
+ return delegateDataSource.classDescriptionForObjects();
+ }
+ return super.classDescriptionForObjects();
+ }
+
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.20 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.20 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.19 2002/05/03 21:41:18 mpowers
- * No longer clearing the selection model when updating from display group:
- * we now only modify if a change needs to be made.
- * No longer listening for selection change during firing of delete events:
- * delete events cause JTree's to update their selection model.
- * Fix for paintsSelectionImmediately: TreeAssociation.processRecentChanges()
- * must happen after the screen is painted, or the selection is not displayed.
+ * Revision 1.19 2002/05/03 21:41:18 mpowers No longer clearing the selection
+ * model when updating from display group: we now only modify if a change needs
+ * to be made. No longer listening for selection change during firing of delete
+ * events: delete events cause JTree's to update their selection model. Fix for
+ * paintsSelectionImmediately: TreeAssociation.processRecentChanges() must
+ * happen after the screen is painted, or the selection is not displayed.
*
- * Revision 1.18 2002/04/23 19:12:28 mpowers
- * Reimplemented fireEventsForChanges. Fitter and happier.
+ * Revision 1.18 2002/04/23 19:12:28 mpowers Reimplemented fireEventsForChanges.
+ * Fitter and happier.
*
- * Revision 1.17 2002/04/19 21:18:46 mpowers
- * Removed tree event coalescing, which was causing way too many problems.
- * The fireChangeEvent algorithm is way faster than before, so we should
- * still be better off than before. At least now, we don't have to track
- * whether the view component has encountered a particular node.
+ * Revision 1.17 2002/04/19 21:18:46 mpowers Removed tree event coalescing,
+ * which was causing way too many problems. The fireChangeEvent algorithm is way
+ * faster than before, so we should still be better off than before. At least
+ * now, we don't have to track whether the view component has encountered a
+ * particular node.
*
- * Revision 1.16 2002/04/18 20:36:11 mpowers
- * TreeModelAssociation now populates children group before selected objects.
- * Got rid of the forceOnSync workaround for cancelled selection change.
+ * Revision 1.16 2002/04/18 20:36:11 mpowers TreeModelAssociation now populates
+ * children group before selected objects. Got rid of the forceOnSync workaround
+ * for cancelled selection change.
*
- * Revision 1.15 2002/04/15 21:52:50 mpowers
- * Tightening up TreeModelAssociation and DisplayGroupNode.
- * Now only firing root structure changed once.
- * Now disposing of root's children.
- * Better event coalescing.
+ * Revision 1.15 2002/04/15 21:52:50 mpowers Tightening up TreeModelAssociation
+ * and DisplayGroupNode. Now only firing root structure changed once. Now
+ * disposing of root's children. Better event coalescing.
*
- * Revision 1.14 2002/04/12 21:05:58 mpowers
- * Now distinguishing changes in titles group even better.
+ * Revision 1.14 2002/04/12 21:05:58 mpowers Now distinguishing changes in
+ * titles group even better.
*
- * Revision 1.11 2002/04/10 21:20:04 mpowers
- * Better handling for tree nodes when working with editing contexts.
- * Better handling for invalidation. No longer broadcasting events
- * when nodes have not been "registered" in the tree.
+ * Revision 1.11 2002/04/10 21:20:04 mpowers Better handling for tree nodes when
+ * working with editing contexts. Better handling for invalidation. No longer
+ * broadcasting events when nodes have not been "registered" in the tree.
*
- * Revision 1.10 2002/04/03 20:01:24 mpowers
- * Removed printlns.
+ * Revision 1.10 2002/04/03 20:01:24 mpowers Removed printlns.
*
- * Revision 1.8 2002/03/11 03:16:28 mpowers
- * Better handling of change events; coalescing changes to children group.
+ * Revision 1.8 2002/03/11 03:16:28 mpowers Better handling of change events;
+ * coalescing changes to children group.
*
- * Revision 1.7 2002/03/08 23:19:57 mpowers
- * Refactoring of DelegatingTreeDataSource to facilitate binding of titles
- * and children aspects to the same display group.
+ * Revision 1.7 2002/03/08 23:19:57 mpowers Refactoring of
+ * DelegatingTreeDataSource to facilitate binding of titles and children aspects
+ * to the same display group.
*
- * Revision 1.6 2002/03/07 23:04:36 mpowers
- * Refining TreeColumnAssociation.
+ * Revision 1.6 2002/03/07 23:04:36 mpowers Refining TreeColumnAssociation.
*
- * Revision 1.5 2002/03/06 13:04:16 mpowers
- * Implemented cascading qualifiers in tree nodes.
+ * Revision 1.5 2002/03/06 13:04:16 mpowers Implemented cascading qualifiers in
+ * tree nodes.
*
- * Revision 1.4 2002/03/04 22:47:48 mpowers
- * Fixed sort ordering for titles group. Optimization for delegate selection.
+ * Revision 1.4 2002/03/04 22:47:48 mpowers Fixed sort ordering for titles
+ * group. Optimization for delegate selection.
*
- * Revision 1.3 2002/03/04 12:28:47 mpowers
- * Revised case where children and titles are bound to same display group.
+ * Revision 1.3 2002/03/04 12:28:47 mpowers Revised case where children and
+ * titles are bound to same display group.
*
- * Revision 1.2 2002/03/01 23:42:09 mpowers
- * Implemented TreeColumnAssociation, and updated documentation.
+ * Revision 1.2 2002/03/01 23:42:09 mpowers Implemented TreeColumnAssociation,
+ * and updated documentation.
*
- * Revision 1.1 2002/02/27 23:19:17 mpowers
- * Refactoring of TreeAssociation to create TreeModelAssociation parent.
+ * Revision 1.1 2002/02/27 23:19:17 mpowers Refactoring of TreeAssociation to
+ * create TreeModelAssociation parent.
*
- * Revision 1.38 2002/02/18 03:46:08 mpowers
- * Implemented TreeTableCellRenderer.
+ * Revision 1.38 2002/02/18 03:46:08 mpowers Implemented TreeTableCellRenderer.
*
- * Revision 1.37 2002/02/13 21:20:15 mpowers
- * Updated comments.
+ * Revision 1.37 2002/02/13 21:20:15 mpowers Updated comments.
*
- * Revision 1.36 2001/11/21 15:13:25 mpowers
- * Better repainting for selectionPaintedImmediately.
- * Better handling for selection with multiple instances of the same
- * object in the tree (from yjcheung).
+ * Revision 1.36 2001/11/21 15:13:25 mpowers Better repainting for
+ * selectionPaintedImmediately. Better handling for selection with multiple
+ * instances of the same object in the tree (from yjcheung).
*
- * Revision 1.35 2001/11/20 19:13:51 mpowers
- * Finished implementation of children group's specialized data source.
+ * Revision 1.35 2001/11/20 19:13:51 mpowers Finished implementation of children
+ * group's specialized data source.
*
- * Revision 1.34 2001/11/19 16:30:37 mpowers
- * Tree repaint strategy is now a preference: selectionPaintedImmediately.
+ * Revision 1.34 2001/11/19 16:30:37 mpowers Tree repaint strategy is now a
+ * preference: selectionPaintedImmediately.
*
- * Revision 1.33 2001/11/15 17:56:41 mpowers
- * Initial implementation of data source for the children display group.
+ * Revision 1.33 2001/11/15 17:56:41 mpowers Initial implementation of data
+ * source for the children display group.
*
- * Revision 1.32 2001/11/14 00:05:54 mpowers
- * Eliminated the run later in favor of repainting the component immediately.
- * This makes things more predictable for users of the association that
- * want to listen to mouse or selection events on the tree.
+ * Revision 1.32 2001/11/14 00:05:54 mpowers Eliminated the run later in favor
+ * of repainting the component immediately. This makes things more predictable
+ * for users of the association that want to listen to mouse or selection events
+ * on the tree.
*
- * Revision 1.31 2001/11/02 20:43:15 mpowers
- * Fixes for delegate's shouldChangeSelection veto (from yjcheung).
+ * Revision 1.31 2001/11/02 20:43:15 mpowers Fixes for delegate's
+ * shouldChangeSelection veto (from yjcheung).
*
- * Revision 1.30 2001/10/29 20:42:56 mpowers
- * On selection change, repainting tree before notifying display group;
- * using NSRunLoop instead of SwingUtilities.
+ * Revision 1.30 2001/10/29 20:42:56 mpowers On selection change, repainting
+ * tree before notifying display group; using NSRunLoop instead of
+ * SwingUtilities.
*
- * Revision 1.29 2001/10/12 20:12:53 mpowers
- * Better handling of selection change vetoing when changing selection
- * to a node that is not the sibling of the originally selected node.
+ * Revision 1.29 2001/10/12 20:12:53 mpowers Better handling of selection change
+ * vetoing when changing selection to a node that is not the sibling of the
+ * originally selected node.
*
- * Revision 1.28 2001/09/14 13:40:26 mpowers
- * User-initiated selection changes are now handled on the next event loop
- * so that the component repaints the new selection before any potentially
- * lengthy logic is triggered by the selection change.
+ * Revision 1.28 2001/09/14 13:40:26 mpowers User-initiated selection changes
+ * are now handled on the next event loop so that the component repaints the new
+ * selection before any potentially lengthy logic is triggered by the selection
+ * change.
*
- * Revision 1.27 2001/09/10 14:10:03 mpowers
- * Tree now handles multiple instances of the same object.
+ * Revision 1.27 2001/09/10 14:10:03 mpowers Tree now handles multiple instances
+ * of the same object.
*
- * Revision 1.26 2001/07/18 13:03:32 mpowers
- * TreeNodes now refetch only on demand. Previously, once a node had
- * been fetched, it was always refetched after an invalidate, even if
- * the node was not being displayed.
+ * Revision 1.26 2001/07/18 13:03:32 mpowers TreeNodes now refetch only on
+ * demand. Previously, once a node had been fetched, it was always refetched
+ * after an invalidate, even if the node was not being displayed.
*
- * Revision 1.25 2001/05/14 15:25:35 mpowers
- * No longer copying titles group's data source to children group.
+ * Revision 1.25 2001/05/14 15:25:35 mpowers No longer copying titles group's
+ * data source to children group.
*
- * Revision 1.24 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.24 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.23 2001/05/01 00:52:32 mpowers
- * Implemented breadth-first traversal of tree for node.
+ * Revision 1.23 2001/05/01 00:52:32 mpowers Implemented breadth-first traversal
+ * of tree for node.
*
- * Revision 1.22 2001/04/26 01:15:19 mpowers
- * Major clean-up of DisplayGroupNode: fitter, happier, more productive.
+ * Revision 1.22 2001/04/26 01:15:19 mpowers Major clean-up of DisplayGroupNode:
+ * fitter, happier, more productive.
*
- * Revision 1.21 2001/04/22 23:13:35 mpowers
- * Minor bug.
+ * Revision 1.21 2001/04/22 23:13:35 mpowers Minor bug.
*
- * Revision 1.20 2001/04/22 23:05:33 mpowers
- * Totally revised DisplayGroupNode so each object gets its own node
- * (so the nodes are no longer fixed by index).
+ * Revision 1.20 2001/04/22 23:05:33 mpowers Totally revised DisplayGroupNode so
+ * each object gets its own node (so the nodes are no longer fixed by index).
*
- * Revision 1.19 2001/04/21 23:06:33 mpowers
- * A major revisiting to support the revising of DisplayGroupNode.
+ * Revision 1.19 2001/04/21 23:06:33 mpowers A major revisiting to support the
+ * revising of DisplayGroupNode.
*
- * Revision 1.18 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.18 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.17 2001/03/29 21:35:08 mpowers
- * Now handling circular references in the graph.
+ * Revision 1.17 2001/03/29 21:35:08 mpowers Now handling circular references in
+ * the graph.
*
- * Revision 1.16 2001/03/22 21:25:42 mpowers
- * Fixed some nasty issues with jtree's internal state and array bounds.
+ * Revision 1.16 2001/03/22 21:25:42 mpowers Fixed some nasty issues with
+ * jtree's internal state and array bounds.
*
- * Revision 1.15 2001/03/19 21:37:58 mpowers
- * Improved refresh of titles display group.
- * Fixed dangling selection problem after refresh.
+ * Revision 1.15 2001/03/19 21:37:58 mpowers Improved refresh of titles display
+ * group. Fixed dangling selection problem after refresh.
*
- * Revision 1.14 2001/03/09 22:08:57 mpowers
- * Trying to handle the dangling reference problem after an update.
+ * Revision 1.14 2001/03/09 22:08:57 mpowers Trying to handle the dangling
+ * reference problem after an update.
*
- * Revision 1.13 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.13 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.12 2001/01/25 02:16:25 mpowers
- * TreeModelAssociation now returns DisplayGroupNode.getUserObject.
+ * Revision 1.12 2001/01/25 02:16:25 mpowers TreeModelAssociation now returns
+ * DisplayGroupNode.getUserObject.
*
- * Revision 1.11 2001/01/24 18:14:40 mpowers
- * Fixed problem with leaving children aspect unspecified.
+ * Revision 1.11 2001/01/24 18:14:40 mpowers Fixed problem with leaving children
+ * aspect unspecified.
*
- * Revision 1.10 2001/01/24 17:49:15 mpowers
- * Added getObjectForNode and getNodeForObject convenience methods.
+ * Revision 1.10 2001/01/24 17:49:15 mpowers Added getObjectForNode and
+ * getNodeForObject convenience methods.
*
- * Revision 1.9 2001/01/24 17:44:11 mpowers
- * Renamed getPathForNode to getPathForObject to be more precise.
- * And created a new getPathForNode method.
+ * Revision 1.9 2001/01/24 17:44:11 mpowers Renamed getPathForNode to
+ * getPathForObject to be more precise. And created a new getPathForNode method.
*
- * Revision 1.8 2001/01/24 17:20:29 mpowers
- * Children display group now holds siblings of selected objects
- * in addition to the selected objects.
+ * Revision 1.8 2001/01/24 17:20:29 mpowers Children display group now holds
+ * siblings of selected objects in addition to the selected objects.
*
- * Revision 1.5 2001/01/19 23:21:15 mpowers
- * Fine tuning events broadcast from TreeModelAssociation.
+ * Revision 1.5 2001/01/19 23:21:15 mpowers Fine tuning events broadcast from
+ * TreeModelAssociation.
*
- * Revision 1.4 2001/01/18 21:27:29 mpowers
- * Major rework of TreeModelAssociation.
+ * Revision 1.4 2001/01/18 21:27:29 mpowers Major rework of
+ * TreeModelAssociation.
*
- * Revision 1.2 2001/01/11 20:29:19 mpowers
- * Expanded access to tree event firing methods.
+ * Revision 1.2 2001/01/11 20:29:19 mpowers Expanded access to tree event firing
+ * methods.
*
- * Revision 1.1.1.1 2000/12/21 15:49:18 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:49:18 mpowers Contributing wotonomy.
*
- * Revision 1.20 2000/12/20 16:25:42 michael
- * Added log to all files.
+ * Revision 1.20 2000/12/20 16:25:42 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AbsoluteLayout.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AbsoluteLayout.java
index 1fef587..579a595 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AbsoluteLayout.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AbsoluteLayout.java
@@ -25,50 +25,43 @@ import java.awt.LayoutManager;
import java.io.Serializable;
/**
- * AbsoluteLayout specifies that all components in the
- * container will be placed according to their size
- * and their location relative to the container's origin. <br><br>
+ * AbsoluteLayout specifies that all components in the container will be placed
+ * according to their size and their location relative to the container's
+ * origin. <br>
+ * <br>
*
- * You can achieve the same effect by setting a container's
- * layout manager to null, but this class allows you to subclass
- * it if you need specific control or functionality.
+ * You can achieve the same effect by setting a container's layout manager to
+ * null, but this class allows you to subclass it if you need specific control
+ * or functionality.
*
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 904 $
*/
-public class AbsoluteLayout implements LayoutManager, Serializable
-{
- public void addLayoutComponent(String name,
- Component comp)
- {
- }
+public class AbsoluteLayout implements LayoutManager, Serializable {
+ public void addLayoutComponent(String name, Component comp) {
+ }
- public void removeLayoutComponent(Component comp)
- {
- }
+ public void removeLayoutComponent(Component comp) {
+ }
- public Dimension preferredLayoutSize(Container parent)
- {
- return minimumLayoutSize( parent );
- }
+ public Dimension preferredLayoutSize(Container parent) {
+ return minimumLayoutSize(parent);
+ }
- public Dimension minimumLayoutSize(Container parent)
- {
- int width = 0;
- int height = 0;
+ public Dimension minimumLayoutSize(Container parent) {
+ int width = 0;
+ int height = 0;
- Component[] c = parent.getComponents();
- for ( int i = 0; i < c.length; i++ )
- {
- width = Math.max( width, c[i].getLocation().x + c[i].getBounds().width );
- height = Math.max( height, c[i].getLocation().y + c[i].getBounds().height );
- }
+ Component[] c = parent.getComponents();
+ for (int i = 0; i < c.length; i++) {
+ width = Math.max(width, c[i].getLocation().x + c[i].getBounds().width);
+ height = Math.max(height, c[i].getLocation().y + c[i].getBounds().height);
+ }
- return new Dimension( width, height );
- }
+ return new Dimension(width, height);
+ }
- public void layoutContainer(Container parent)
- {
- }
+ public void layoutContainer(Container parent) {
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlphaTextField.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlphaTextField.java
index c36f5e2..9300d35 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlphaTextField.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlphaTextField.java
@@ -19,317 +19,286 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.ui.swing.components;
/**
-* AlphaTextField is a "smart" text field that restricts the user's input. The
-* input can be restricted to alphabetic, alphanumeric, or all characters. The
-* maximum number of characters can also be limited.
-* The defaults for this component is alphabetic only string of unlimited length.
-*
-* @author rob@straylight.princeton.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class AlphaTextField extends SmartTextField
-{
-
-/*******************************
-* CONSTANTS
-*******************************/
-
-/**
-* Sets the input to alphabetic characters only. The characters "a-z" and "A-Z"
-* are the only valid characters. All other characters will be ignored.
-* @see #getAlphaType()
-*/
- public static final int ALPHABETIC = 0;
-
-/**
-* Sets the input to alphanumeric characters only. The characters "a-z", "A-Z"
-* and "0-9" are the only valid characters. All other characters will be ignored.
-* @see #getAlphaType()
-*/
- public static final int ALPHANUMERIC = 1;
-
-/**
-* Sets the input to alphanumeric characters and a few special characters only.
-* The valid characters are "a-z", "A-Z", "0-9", space, "-", "_", "\", and ":".
-* This is helpful for file names (with paths) as input strings.
-* All other characters will be ignored.
-* @see #getAlphaType()
-*/
- public static final int ALPHANUMERIC_PLUS = 2;
-
-/**
-* Sets the input to all characters without restriction.
-* @see #getAlphaType()
-*/
- public static final int ALL = 3;
-
-
-/*******************************
-* DATA MEMBERS
-*******************************/
-
- // The level of input restrictions, defaults to ALPHABETIC
- private int alphaType;
-
- // The maximum length of the input string, defaults to 0, no maximum
- private int stringLength;
-
-
-/*******************************
-* PUBLIC METHODS
-*******************************/
-
-/**
-* The default constructor of this class. The default string of this text
-* field is set to the empty string (""). The maximum length is set to 0,
-* which specifies no limit.
-*/
- public AlphaTextField()
- {
- this("", 0);
- }
-
-/**
-* Constructor of this class with the initial text of the text field specified.
-* The maximum length is set to 0, which specifies no limit.
-* @param text Initial text of the text field.
-*/
- public AlphaTextField(String text)
- {
- this(text, 0);
- }
-
-/**
-* Constructor of this class with width (in columns) of the text field specified.
-* The initial text is set to the empty string (""). The maximum length is set
-* to 0, which specifies no limit.
-* @param columns The width of the text field in characters.
-*/
- public AlphaTextField(int columns)
- {
- this("", columns);
- }
-
-/**
-* Constructor of this class with width (in columns) and initial text of the
-* text field specified. The maximum length is set to 0, which specifies no limit.
-* @param text Initial text of the text field.
-* @param columns The width of the text field in characters.
-*/
- public AlphaTextField(String text, int columns)
- {
- super(text, columns);
- }
-
-/**
-* Constructor that allows the user to set the Alpha type of the text field
-* and the maximum string length.
-* @param anAlphaType The character restriction type.
-* @param aLength The maximum number of characters allowed in the string.
-*/
- public AlphaTextField(int anAlphaType, int aLength)
- {
- super( "", 0 );
- setAlphaType( anAlphaType );
- setStringLength( aLength );
- }
-
-/**
-* Gets the current restriction type of this text field.
-* @see #ALPHABETIC
-* @see #ALPHANUMERIC
-* @see #ALPHANUMERIC_PLUS
-* @see #ALL
-* @return The current restriction type as defined by the constansts of this class.
-*/
- public int getAlphaType()
- {
- return alphaType;
- }
-
-/**
-* Sets the restriction type of this text field.
-* @see #ALPHABETIC
-* @see #ALPHANUMERIC
-* @see #ALPHANUMERIC_PLUS
-* @see #ALL
-* @param newAlphaType The restriction of this text field.
-*/
- public void setAlphaType(int newAlphaType)
- {
- switch (newAlphaType)
- {
- case ALPHABETIC:
- case ALPHANUMERIC:
- case ALPHANUMERIC_PLUS:
- case ALL:
- {
- alphaType = newAlphaType;
- break;
- }
- default:
- {
- alphaType = ALPHABETIC;
- break;
- }
- }
- }
-
-/**
-* Sets the maximum string length of this text field. If the length is set to
-* zero, then there is no limit. The default string length is zero. Negative
-* sizes will set the length to zero.
-* @param newStringLength The maximum length of the string that the user can input.
-*/
- public void setStringLength(int newStringLength)
- {
- if (newStringLength < 0)
- {
- stringLength = 0;
- }
- else
- {
- stringLength = newStringLength;
- }
- }
-
-/**
-* Gets the current length of the maximum string size the user can enter.
-* @return The maximum length the string of the text field can be.
-*/
- public int getStringLength()
- {
- return stringLength;
- }
-
-
-/*******************************
-* PROTECTED METHODS
-*******************************/
-
- protected boolean isValidCharacter(char aChar)
- {
- // if its a non-printable character, then its ok
- if ((aChar < ' ') || (aChar > '~'))
- {
- return true;
- }
-
- // can only be a printable character now, check it for validation
- return isValidCharacterType(aChar);
- }
-
- protected boolean isValidString(String aString)
- {
- if (aString.length() > stringLength)
- {
- return false;
- }
-
- for (int i = 0; i < aString.length(); ++i)
- {
- if (!(isValidCharacterType(aString.charAt(i))))
- {
- return false;
- }
- }
-
- return true;
- }
-
- protected void postProcessing()
- {
- // No need to do anything.
- }
-
-
-/*******************************
-* PROTECTED METHODS
-*******************************/
-
- private boolean isValidCharacterType(char aChar)
- {
- switch (alphaType)
- {
- case ALPHABETIC:
- {
- if (!(isValidAlphabeticCharacter(aChar)))
- {
- return false;
- }
- break;
- }
- case ALPHANUMERIC:
- {
- if (!(isValidAlphanumericCharacter(aChar)))
- {
- return false;
- }
- break;
- }
- case ALPHANUMERIC_PLUS:
- {
- if (!(isValidAlphanumericPlusCharacter(aChar)))
- {
- return false;
- }
- break;
- }
- case ALL:
- {
- if (!(isValidAllCharacter(aChar)))
- {
- return false;
- }
- break;
- }
- default:
- {
- return false;
- }
- }
-
- return true;
- }
-
- private boolean isValidAlphabeticCharacter(char aChar)
- {
- if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z')))
- {
- return false;
- }
- return true;
- }
-
- private boolean isValidAlphanumericCharacter(char aChar)
- {
- if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z')) && ((aChar < '0') || (aChar > '9')))
- {
- return false;
- }
- return true;
- }
-
- private boolean isValidAlphanumericPlusCharacter(char aChar)
- {
- if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z')) && ((aChar < '0') || (aChar > '9')))
- {
- if ((aChar != ' ') && (aChar != '_') && (aChar != '-') && (aChar != ':') && (aChar != '\\'))
- {
- return false;
- }
- }
- return true;
- }
-
- private boolean isValidAllCharacter(char aChar)
- {
- if ((aChar < ' ') || (aChar > '~'))
- {
- return false;
- }
- return true;
- }
+ * AlphaTextField is a "smart" text field that restricts the user's input. The
+ * input can be restricted to alphabetic, alphanumeric, or all characters. The
+ * maximum number of characters can also be limited. The defaults for this
+ * component is alphabetic only string of unlimited length.
+ *
+ * @author rob@straylight.princeton.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class AlphaTextField extends SmartTextField {
+
+ /*******************************
+ * CONSTANTS
+ *******************************/
+
+ /**
+ * Sets the input to alphabetic characters only. The characters "a-z" and "A-Z"
+ * are the only valid characters. All other characters will be ignored.
+ *
+ * @see #getAlphaType()
+ */
+ public static final int ALPHABETIC = 0;
+
+ /**
+ * Sets the input to alphanumeric characters only. The characters "a-z", "A-Z"
+ * and "0-9" are the only valid characters. All other characters will be
+ * ignored.
+ *
+ * @see #getAlphaType()
+ */
+ public static final int ALPHANUMERIC = 1;
+
+ /**
+ * Sets the input to alphanumeric characters and a few special characters only.
+ * The valid characters are "a-z", "A-Z", "0-9", space, "-", "_", "\", and ":".
+ * This is helpful for file names (with paths) as input strings. All other
+ * characters will be ignored.
+ *
+ * @see #getAlphaType()
+ */
+ public static final int ALPHANUMERIC_PLUS = 2;
+
+ /**
+ * Sets the input to all characters without restriction.
+ *
+ * @see #getAlphaType()
+ */
+ public static final int ALL = 3;
+
+ /*******************************
+ * DATA MEMBERS
+ *******************************/
+
+ // The level of input restrictions, defaults to ALPHABETIC
+ private int alphaType;
+
+ // The maximum length of the input string, defaults to 0, no maximum
+ private int stringLength;
+
+ /*******************************
+ * PUBLIC METHODS
+ *******************************/
+
+ /**
+ * The default constructor of this class. The default string of this text field
+ * is set to the empty string (""). The maximum length is set to 0, which
+ * specifies no limit.
+ */
+ public AlphaTextField() {
+ this("", 0);
+ }
+
+ /**
+ * Constructor of this class with the initial text of the text field specified.
+ * The maximum length is set to 0, which specifies no limit.
+ *
+ * @param text Initial text of the text field.
+ */
+ public AlphaTextField(String text) {
+ this(text, 0);
+ }
+
+ /**
+ * Constructor of this class with width (in columns) of the text field
+ * specified. The initial text is set to the empty string (""). The maximum
+ * length is set to 0, which specifies no limit.
+ *
+ * @param columns The width of the text field in characters.
+ */
+ public AlphaTextField(int columns) {
+ this("", columns);
+ }
+
+ /**
+ * Constructor of this class with width (in columns) and initial text of the
+ * text field specified. The maximum length is set to 0, which specifies no
+ * limit.
+ *
+ * @param text Initial text of the text field.
+ * @param columns The width of the text field in characters.
+ */
+ public AlphaTextField(String text, int columns) {
+ super(text, columns);
+ }
+
+ /**
+ * Constructor that allows the user to set the Alpha type of the text field and
+ * the maximum string length.
+ *
+ * @param anAlphaType The character restriction type.
+ * @param aLength The maximum number of characters allowed in the string.
+ */
+ public AlphaTextField(int anAlphaType, int aLength) {
+ super("", 0);
+ setAlphaType(anAlphaType);
+ setStringLength(aLength);
+ }
+
+ /**
+ * Gets the current restriction type of this text field.
+ *
+ * @see #ALPHABETIC
+ * @see #ALPHANUMERIC
+ * @see #ALPHANUMERIC_PLUS
+ * @see #ALL
+ * @return The current restriction type as defined by the constansts of this
+ * class.
+ */
+ public int getAlphaType() {
+ return alphaType;
+ }
+
+ /**
+ * Sets the restriction type of this text field.
+ *
+ * @see #ALPHABETIC
+ * @see #ALPHANUMERIC
+ * @see #ALPHANUMERIC_PLUS
+ * @see #ALL
+ * @param newAlphaType The restriction of this text field.
+ */
+ public void setAlphaType(int newAlphaType) {
+ switch (newAlphaType) {
+ case ALPHABETIC:
+ case ALPHANUMERIC:
+ case ALPHANUMERIC_PLUS:
+ case ALL: {
+ alphaType = newAlphaType;
+ break;
+ }
+ default: {
+ alphaType = ALPHABETIC;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sets the maximum string length of this text field. If the length is set to
+ * zero, then there is no limit. The default string length is zero. Negative
+ * sizes will set the length to zero.
+ *
+ * @param newStringLength The maximum length of the string that the user can
+ * input.
+ */
+ public void setStringLength(int newStringLength) {
+ if (newStringLength < 0) {
+ stringLength = 0;
+ } else {
+ stringLength = newStringLength;
+ }
+ }
+
+ /**
+ * Gets the current length of the maximum string size the user can enter.
+ *
+ * @return The maximum length the string of the text field can be.
+ */
+ public int getStringLength() {
+ return stringLength;
+ }
+
+ /*******************************
+ * PROTECTED METHODS
+ *******************************/
+
+ protected boolean isValidCharacter(char aChar) {
+ // if its a non-printable character, then its ok
+ if ((aChar < ' ') || (aChar > '~')) {
+ return true;
+ }
+
+ // can only be a printable character now, check it for validation
+ return isValidCharacterType(aChar);
+ }
+
+ protected boolean isValidString(String aString) {
+ if (aString.length() > stringLength) {
+ return false;
+ }
+
+ for (int i = 0; i < aString.length(); ++i) {
+ if (!(isValidCharacterType(aString.charAt(i)))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected void postProcessing() {
+ // No need to do anything.
+ }
+
+ /*******************************
+ * PROTECTED METHODS
+ *******************************/
+
+ private boolean isValidCharacterType(char aChar) {
+ switch (alphaType) {
+ case ALPHABETIC: {
+ if (!(isValidAlphabeticCharacter(aChar))) {
+ return false;
+ }
+ break;
+ }
+ case ALPHANUMERIC: {
+ if (!(isValidAlphanumericCharacter(aChar))) {
+ return false;
+ }
+ break;
+ }
+ case ALPHANUMERIC_PLUS: {
+ if (!(isValidAlphanumericPlusCharacter(aChar))) {
+ return false;
+ }
+ break;
+ }
+ case ALL: {
+ if (!(isValidAllCharacter(aChar))) {
+ return false;
+ }
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean isValidAlphabeticCharacter(char aChar) {
+ if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z'))) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isValidAlphanumericCharacter(char aChar) {
+ if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z')) && ((aChar < '0') || (aChar > '9'))) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isValidAlphanumericPlusCharacter(char aChar) {
+ if (((aChar < 'A') || (aChar > 'Z')) && ((aChar < 'a') || (aChar > 'z')) && ((aChar < '0') || (aChar > '9'))) {
+ if ((aChar != ' ') && (aChar != '_') && (aChar != '-') && (aChar != ':') && (aChar != '\\')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isValidAllCharacter(char aChar) {
+ if ((aChar < ' ') || (aChar > '~')) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlternatingRowCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlternatingRowCellRenderer.java
index 46d2693..fb4824c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlternatingRowCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/AlternatingRowCellRenderer.java
@@ -28,102 +28,79 @@ import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
/**
-* A TableCellRenderer that wraps another TableCellRenderer
-* and sets the background to the specified color for odd-numbered rows.
-* This makes every other row appear to be a different color,
-* which helps users distinguish rows of data in densely-packed
-* tables.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * A TableCellRenderer that wraps another TableCellRenderer and sets the
+ * background to the specified color for odd-numbered rows. This makes every
+ * other row appear to be a different color, which helps users distinguish rows
+ * of data in densely-packed tables.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class AlternatingRowCellRenderer implements TableCellRenderer {
- protected TableCellRenderer wrappedRenderer;
- protected Color alternateColor;
-
- /**
- * Default constructor uses a lighter shade of the system control color
- * and wraps a DefaultTableCellRenderer.
- */
- public AlternatingRowCellRenderer()
- {
- this( new DefaultTableCellRenderer() );
- }
-
- /**
- * Uses the specified color for the background of the alternating rows,
- * and wraps a DefaultTableCellRenderer.
- */
- public AlternatingRowCellRenderer(
- Color aColor )
- {
- this( aColor, new DefaultTableCellRenderer() );
- }
+ protected TableCellRenderer wrappedRenderer;
+ protected Color alternateColor;
- /**
- * Uses the uses a lighter shade of the system control color
- * for the background of the alternating rows,
- * and wraps the specified TableCellRenderer.
- */
- public AlternatingRowCellRenderer(
- TableCellRenderer aRenderer )
- {
- Color c = UIManager.getColor( "control" );
- c = new Color( // lighten this color just slightly
- (int) ( c.getRed() + ( ( 255 - c.getRed() ) / 1.5 ) ),
- (int) ( c.getGreen() + ( ( 255 - c.getGreen() ) / 1.5 ) ),
- (int) ( c.getBlue() + ( ( 255 - c.getBlue() ) / 1.5 ) ) );
+ /**
+ * Default constructor uses a lighter shade of the system control color and
+ * wraps a DefaultTableCellRenderer.
+ */
+ public AlternatingRowCellRenderer() {
+ this(new DefaultTableCellRenderer());
+ }
- alternateColor = c;
- wrappedRenderer = aRenderer;
- }
+ /**
+ * Uses the specified color for the background of the alternating rows, and
+ * wraps a DefaultTableCellRenderer.
+ */
+ public AlternatingRowCellRenderer(Color aColor) {
+ this(aColor, new DefaultTableCellRenderer());
+ }
- /**
- * Uses the specified color for the background of the alternating rows,
- * and wraps the specified TableCellRenderer.
- */
- public AlternatingRowCellRenderer(
- Color aColor, TableCellRenderer aRenderer )
- {
- alternateColor = aColor;
- wrappedRenderer = aRenderer;
- }
+ /**
+ * Uses the uses a lighter shade of the system control color for the background
+ * of the alternating rows, and wraps the specified TableCellRenderer.
+ */
+ public AlternatingRowCellRenderer(TableCellRenderer aRenderer) {
+ Color c = UIManager.getColor("control");
+ c = new Color( // lighten this color just slightly
+ (int) (c.getRed() + ((255 - c.getRed()) / 1.5)), (int) (c.getGreen() + ((255 - c.getGreen()) / 1.5)),
+ (int) (c.getBlue() + ((255 - c.getBlue()) / 1.5)));
- public Component getTableCellRendererComponent(
- JTable table, Object value,
- boolean isSelected, boolean hasFocus,
- int row, int column)
- {
- Component result = wrappedRenderer.getTableCellRendererComponent(
- table, value, isSelected, hasFocus, row, column );
- if ( ! isSelected )
- {
- if ( row % 2 == 0 )
- {
- if ( ! result.getBackground().equals( table.getBackground() ) )
- {
- result.setBackground( table.getBackground() );
- }
- }
- else
- {
- if ( ! result.getBackground().equals( alternateColor ) )
- {
- // jdk1.3's default renderer is opaque
- if ( result instanceof JComponent )
- {
- ((JComponent)result).setOpaque( true );
- }
-
- result.setBackground( alternateColor );
- }
- }
- }
- return result;
- }
-}
+ alternateColor = c;
+ wrappedRenderer = aRenderer;
+ }
+ /**
+ * Uses the specified color for the background of the alternating rows, and
+ * wraps the specified TableCellRenderer.
+ */
+ public AlternatingRowCellRenderer(Color aColor, TableCellRenderer aRenderer) {
+ alternateColor = aColor;
+ wrappedRenderer = aRenderer;
+ }
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ Component result = wrappedRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
+ column);
+ if (!isSelected) {
+ if (row % 2 == 0) {
+ if (!result.getBackground().equals(table.getBackground())) {
+ result.setBackground(table.getBackground());
+ }
+ } else {
+ if (!result.getBackground().equals(alternateColor)) {
+ // jdk1.3's default renderer is opaque
+ if (result instanceof JComponent) {
+ ((JComponent) result).setOpaque(true);
+ }
+ result.setBackground(alternateColor);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterFlowLayout.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterFlowLayout.java
index 1c438b6..632fb59 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterFlowLayout.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterFlowLayout.java
@@ -25,491 +25,505 @@ import java.awt.FlowLayout;
import java.awt.Insets;
/**
- * BetterFlowLayout works just like FlowLayout, except that
- * you can specify a vertical orientation in addition to the
- * usual horizontal orientations. You can also specify that
- * all the components be sized to the same height and/or width.
- * By default, the behavior is identical to FlowLayout.
+ * BetterFlowLayout works just like FlowLayout, except that you can specify a
+ * vertical orientation in addition to the usual horizontal orientations. You
+ * can also specify that all the components be sized to the same height and/or
+ * width. By default, the behavior is identical to FlowLayout.
*
* @author michael@mpowers.net
* @author $Author: cgruber $
- * @version $Revision: 904 $
- * $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
*/
public class BetterFlowLayout extends FlowLayout {
- /**
- * This value indicates vertical orientation and
- * that each column of components should be top-justified.
- */
- public static final int TOP = 32;
-
- /**
- * This value indicates vertical orientation and
- * that each column of components should be centered.
- */
- public static final int CENTER_VERTICAL = 16;
-
- /**
- * This value indicates vertical orientation and
- * that each column of components should be bottom-justified.
- */
- public static final int BOTTOM = 8;
-
- /**
- * Tracks orientation.
- */
- protected boolean isHorizontal = true;
-
- /**
- * Tracks component sizing of width.
- */
- protected boolean isWidthUniform = false;
- /**
- * Tracks component sizing of height.
- */
- protected boolean isHeightUniform = false;
-
- /**
- * Constructs a new Flow Layout with a centered alignment and a
- * default 5-unit horizontal and vertical gap.
- */
- public BetterFlowLayout() {
- this(CENTER, 5, 5);
- }
-
- /**
- * Constructs a new Flow Layout with the specified alignment and a
- * default 5-unit horizontal and vertical gap.
- * The value of the alignment argument must be one of
- * <code>BetterFlowLayout.LEFT</code>, <code>BetterFlowLayout.RIGHT</code>,
- * or <code>BetterFlowLayout.CENTER</code>.
- * @param align the alignment value
- */
- public BetterFlowLayout(int align) {
- this(align, 5, 5);
- }
-
- /**
- * Creates a new flow layout manager with the indicated alignment
- * and the indicated horizontal and vertical gaps.
- * <p>
- * The value of the alignment argument must be one of
- * <code>BetterFlowLayout.LEFT</code>, <code>BetterFlowLayout.RIGHT</code>,
- * or <code>BetterFlowLayout.CENTER</code>.
- * @param align the alignment value.
- * @param hgap the horizontal gap between components.
- * @param vgap the vertical gap between components.
- */
- public BetterFlowLayout(int align, int hgap, int vgap) {
- setHgap(hgap);
- setVgap(vgap);
- setAlignment(align);
- }
-
- /**
- * Sets whether all components should have the same height.
- * @param isUniform the new value.
- * @see #isHeightUniform
- */
- public void setHeightUniform(boolean isUniform) {
- isHeightUniform = isUniform;
- }
-
- /**
- * Sets whether all components should have the same width.
- * @param isUniform the new value.
- * @see #isWidthUniform
- */
- public void setWidthUniform(boolean isUniform) {
- isWidthUniform = isUniform;
- }
-
- /**
- * Determines whether all components will have the same height.
- * The uniform height will be the maximum of the preferred heights
- * of all the components in the container.
- * This value defaults to false.
- * @return whether components will have the same height.
- */
- public boolean isHeightUniform() {
- return isHeightUniform;
- }
-
- /**
- * Determines whether all components will have the same width.
- * The uniform height will be the maximum of the preferred widths
- * of all the components in the container.
- * This value defaults to false.
- * @return whether components will have the same width.
- */
- public boolean isWidthUniform() {
- return isWidthUniform;
- }
-
- /**
- * Sets the alignment for this layout.
- * Possible values for horizontal orientation are <code>LEFT</code>,
- * <code>RIGHT</code>, and <code>CENTER</code>.
- * Possible values for vertical orientation are <code>TOP</code>,
- * <code>BOTTOM</code>, and <code>CENTER_VERTICAL</code>.
- * @param align the alignment value.
- * @see java.awt.FlowLayout#getAlignment
- */
- public void setAlignment(int align) {
- if ( ( align == TOP ) || ( align == BOTTOM ) || ( align == CENTER_VERTICAL ) )
- {
- isHorizontal = false;
- }
- else
- {
- isHorizontal = true;
- }
-
- super.setAlignment( align );
- }
-
- /**
- * Returns the preferred dimensions for this layout given the components
- * in the specified target container.
- * @param target the component which needs to be laid out
- * @return the preferred dimensions to lay out the
- * subcomponents of the specified container.
- * @see Container
- * @see #minimumLayoutSize
- * @see java.awt.Container#getPreferredSize
- */
- public Dimension preferredLayoutSize(Container target) {
- if ( isHorizontal ) {
- return preferredLayoutSizeHorizontal( target );
- } else {
- return preferredLayoutSizeVertical( target );
- }
- }
-
- /**
- * Returns the preferred dimensions for this layout given the components
- * in the specified target container.
- * @param target the component which needs to be laid out
- * @return the preferred dimensions to lay out the
- * subcomponents of the specified container.
- * @see Container
- * @see #minimumLayoutSize
- * @see java.awt.Container#getPreferredSize
- */
- public Dimension preferredLayoutSizeHorizontal(Container target) {
- synchronized (target.getTreeLock()) {
- Dimension dim = new Dimension(0, 0);
- int nmembers = target.getComponentCount();
- int maxWidth = 0;
-
- for (int i = 0 ; i < nmembers ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- Dimension d = m.getPreferredSize();
- dim.height = Math.max(dim.height, d.height);
- maxWidth = Math.max(maxWidth, d.width);
- if (i > 0) {
- dim.width += getHgap();
- }
- dim.width += d.width;
- }
- }
- if ( isWidthUniform )
- dim.width = ( maxWidth + getHgap() ) * nmembers - getHgap();
- Insets insets = target.getInsets();
- dim.width += insets.left + insets.right + getHgap()*2;
- dim.height += insets.top + insets.bottom + getVgap()*2;
- return dim;
- }
- }
-
- /**
- * Returns the preferred dimensions for this layout given the components
- * in the specified target container.
- * @param target the component which needs to be laid out
- * @return the preferred dimensions to lay out the
- * subcomponents of the specified container.
- * @see Container
- * @see #minimumLayoutSize
- * @see java.awt.Container#getPreferredSize
- */
- public Dimension preferredLayoutSizeVertical(Container target) {
- synchronized (target.getTreeLock()) {
- Dimension dim = new Dimension(0, 0);
- int nmembers = target.getComponentCount();
- int maxHeight = 0;
-
- for (int i = 0 ; i < nmembers ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- Dimension d = m.getPreferredSize();
- dim.width = Math.max(dim.width, d.width);
- maxHeight = Math.max(maxHeight, d.height);
- if (i > 0) {
- dim.height += getVgap();
- }
- dim.height += d.height;
- }
- }
- if ( isHeightUniform )
- dim.height = ( maxHeight + getVgap() ) * nmembers - getVgap();
- Insets insets = target.getInsets();
- dim.width += insets.left + insets.right + getHgap()*2;
- dim.height += insets.top + insets.bottom + getVgap()*2;
- return dim;
- }
- }
-
- /**
- * Returns the minimum dimensions needed to layout the components
- * contained in the specified target container.
- * @param target the component which needs to be laid out
- * @return the minimum dimensions to lay out the
- * subcomponents of the specified container.
- * @see #preferredLayoutSize
- * @see java.awt.Container
- * @see java.awt.Container#doLayout
- */
- public Dimension minimumLayoutSize(Container target) {
- // preferred size is also the minimum size
- if ( isHorizontal ) {
- return preferredLayoutSizeHorizontal( target );
- } else {
- return preferredLayoutSizeVertical( target );
- }
- }
-
- /**
- * Lays out the container. This method lets each component take
- * its preferred size by reshaping the components in the
- * target container in order to satisfy the constraints of
- * this <code>BetterFlowLayout</code> object.
- * @param target the specified component being laid out.
- * @see Container
- * @see java.awt.Container#doLayout
- */
- public void layoutContainer(Container target) {
- if ( isHorizontal ) {
- layoutContainerHorizontal( target );
- } else {
- layoutContainerVertical( target );
- }
- }
-
- /**
- * Lays out the container. This method lets each component take
- * its preferred size by reshaping the components in the
- * target container in order to satisfy the constraints of
- * this <code>BetterFlowLayout</code> object.
- * @param target the specified component being laid out.
- * @see Container
- * @see java.awt.Container#doLayout
- */
- protected void layoutContainerHorizontal(Container target) {
- synchronized (target.getTreeLock()) {
- Insets insets = target.getInsets();
- int maxwidth = target.getSize().width - (insets.left + insets.right + getHgap()*2);
- int nmembers = target.getComponentCount();
- int x = 0, y = insets.top + getVgap();
- int rowh = 0, start = 0;
-
- boolean ltr = true; // target.getComponentOrientation().isLeftToRight();
- Dimension uniform = getUniformDimension( target );
-
- for (int i = 0 ; i < nmembers ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- Dimension d = m.getPreferredSize();
- if ( isWidthUniform )
- d.width = uniform.width;
- if ( isHeightUniform )
- d.height = uniform.height;
- m.setSize(d.width, d.height);
-
- if ((x == 0) || ((x + d.width) <= maxwidth)) {
- if (x > 0) {
- x += getHgap();
- }
- x += d.width;
- rowh = Math.max(rowh, d.height);
- } else {
- moveComponentsHorizontal(target, insets.left + getHgap(), y, maxwidth - x, rowh, start, i, ltr);
- x = d.width;
- y += getVgap() + rowh;
- rowh = d.height;
- start = i;
- }
- }
- }
- moveComponentsHorizontal(target, insets.left + getHgap(), y, maxwidth - x, rowh, start, nmembers, ltr);
- }
- }
-
- /**
- * Centers the elements in the specified row, if there is any slack.
- * @param target the component which needs to be moved
- * @param x the x coordinate
- * @param y the y coordinate
- * @param width the width dimensions
- * @param height the height dimensions
- * @param rowStart the beginning of the row
- * @param rowEnd the the ending of the row
- */
- private void moveComponentsHorizontal(Container target, int x, int y, int width, int height,
- int rowStart, int rowEnd, boolean ltr) {
- synchronized (target.getTreeLock()) {
- switch (getAlignment()) {
- case LEFT:
- x += ltr ? 0 : width;
- break;
- case CENTER:
- x += width / 2;
- break;
- case RIGHT:
- x += ltr ? width : 0;
- break;
+ /**
+ * This value indicates vertical orientation and that each column of components
+ * should be top-justified.
+ */
+ public static final int TOP = 32;
+
+ /**
+ * This value indicates vertical orientation and that each column of components
+ * should be centered.
+ */
+ public static final int CENTER_VERTICAL = 16;
+
+ /**
+ * This value indicates vertical orientation and that each column of components
+ * should be bottom-justified.
+ */
+ public static final int BOTTOM = 8;
+
+ /**
+ * Tracks orientation.
+ */
+ protected boolean isHorizontal = true;
+
+ /**
+ * Tracks component sizing of width.
+ */
+ protected boolean isWidthUniform = false;
+ /**
+ * Tracks component sizing of height.
+ */
+ protected boolean isHeightUniform = false;
+
+ /**
+ * Constructs a new Flow Layout with a centered alignment and a default 5-unit
+ * horizontal and vertical gap.
+ */
+ public BetterFlowLayout() {
+ this(CENTER, 5, 5);
+ }
+
+ /**
+ * Constructs a new Flow Layout with the specified alignment and a default
+ * 5-unit horizontal and vertical gap. The value of the alignment argument must
+ * be one of <code>BetterFlowLayout.LEFT</code>,
+ * <code>BetterFlowLayout.RIGHT</code>, or <code>BetterFlowLayout.CENTER</code>.
+ *
+ * @param align the alignment value
+ */
+ public BetterFlowLayout(int align) {
+ this(align, 5, 5);
+ }
+
+ /**
+ * Creates a new flow layout manager with the indicated alignment and the
+ * indicated horizontal and vertical gaps.
+ * <p>
+ * The value of the alignment argument must be one of
+ * <code>BetterFlowLayout.LEFT</code>, <code>BetterFlowLayout.RIGHT</code>, or
+ * <code>BetterFlowLayout.CENTER</code>.
+ *
+ * @param align the alignment value.
+ * @param hgap the horizontal gap between components.
+ * @param vgap the vertical gap between components.
+ */
+ public BetterFlowLayout(int align, int hgap, int vgap) {
+ setHgap(hgap);
+ setVgap(vgap);
+ setAlignment(align);
+ }
+
+ /**
+ * Sets whether all components should have the same height.
+ *
+ * @param isUniform the new value.
+ * @see #isHeightUniform
+ */
+ public void setHeightUniform(boolean isUniform) {
+ isHeightUniform = isUniform;
+ }
+
+ /**
+ * Sets whether all components should have the same width.
+ *
+ * @param isUniform the new value.
+ * @see #isWidthUniform
+ */
+ public void setWidthUniform(boolean isUniform) {
+ isWidthUniform = isUniform;
+ }
+
+ /**
+ * Determines whether all components will have the same height. The uniform
+ * height will be the maximum of the preferred heights of all the components in
+ * the container. This value defaults to false.
+ *
+ * @return whether components will have the same height.
+ */
+ public boolean isHeightUniform() {
+ return isHeightUniform;
+ }
+
+ /**
+ * Determines whether all components will have the same width. The uniform
+ * height will be the maximum of the preferred widths of all the components in
+ * the container. This value defaults to false.
+ *
+ * @return whether components will have the same width.
+ */
+ public boolean isWidthUniform() {
+ return isWidthUniform;
+ }
+
+ /**
+ * Sets the alignment for this layout. Possible values for horizontal
+ * orientation are <code>LEFT</code>, <code>RIGHT</code>, and
+ * <code>CENTER</code>. Possible values for vertical orientation are
+ * <code>TOP</code>, <code>BOTTOM</code>, and <code>CENTER_VERTICAL</code>.
+ *
+ * @param align the alignment value.
+ * @see java.awt.FlowLayout#getAlignment
+ */
+ public void setAlignment(int align) {
+ if ((align == TOP) || (align == BOTTOM) || (align == CENTER_VERTICAL)) {
+ isHorizontal = false;
+ } else {
+ isHorizontal = true;
+ }
+
+ super.setAlignment(align);
+ }
+
+ /**
+ * Returns the preferred dimensions for this layout given the components in the
+ * specified target container.
+ *
+ * @param target the component which needs to be laid out
+ * @return the preferred dimensions to lay out the subcomponents of the
+ * specified container.
+ * @see Container
+ * @see #minimumLayoutSize
+ * @see java.awt.Container#getPreferredSize
+ */
+ public Dimension preferredLayoutSize(Container target) {
+ if (isHorizontal) {
+ return preferredLayoutSizeHorizontal(target);
+ } else {
+ return preferredLayoutSizeVertical(target);
+ }
+ }
+
+ /**
+ * Returns the preferred dimensions for this layout given the components in the
+ * specified target container.
+ *
+ * @param target the component which needs to be laid out
+ * @return the preferred dimensions to lay out the subcomponents of the
+ * specified container.
+ * @see Container
+ * @see #minimumLayoutSize
+ * @see java.awt.Container#getPreferredSize
+ */
+ public Dimension preferredLayoutSizeHorizontal(Container target) {
+ synchronized (target.getTreeLock()) {
+ Dimension dim = new Dimension(0, 0);
+ int nmembers = target.getComponentCount();
+ int maxWidth = 0;
+
+ for (int i = 0; i < nmembers; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ Dimension d = m.getPreferredSize();
+ dim.height = Math.max(dim.height, d.height);
+ maxWidth = Math.max(maxWidth, d.width);
+ if (i > 0) {
+ dim.width += getHgap();
+ }
+ dim.width += d.width;
+ }
+ }
+ if (isWidthUniform)
+ dim.width = (maxWidth + getHgap()) * nmembers - getHgap();
+ Insets insets = target.getInsets();
+ dim.width += insets.left + insets.right + getHgap() * 2;
+ dim.height += insets.top + insets.bottom + getVgap() * 2;
+ return dim;
+ }
+ }
+
+ /**
+ * Returns the preferred dimensions for this layout given the components in the
+ * specified target container.
+ *
+ * @param target the component which needs to be laid out
+ * @return the preferred dimensions to lay out the subcomponents of the
+ * specified container.
+ * @see Container
+ * @see #minimumLayoutSize
+ * @see java.awt.Container#getPreferredSize
+ */
+ public Dimension preferredLayoutSizeVertical(Container target) {
+ synchronized (target.getTreeLock()) {
+ Dimension dim = new Dimension(0, 0);
+ int nmembers = target.getComponentCount();
+ int maxHeight = 0;
+
+ for (int i = 0; i < nmembers; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ Dimension d = m.getPreferredSize();
+ dim.width = Math.max(dim.width, d.width);
+ maxHeight = Math.max(maxHeight, d.height);
+ if (i > 0) {
+ dim.height += getVgap();
+ }
+ dim.height += d.height;
+ }
+ }
+ if (isHeightUniform)
+ dim.height = (maxHeight + getVgap()) * nmembers - getVgap();
+ Insets insets = target.getInsets();
+ dim.width += insets.left + insets.right + getHgap() * 2;
+ dim.height += insets.top + insets.bottom + getVgap() * 2;
+ return dim;
+ }
+ }
+
+ /**
+ * Returns the minimum dimensions needed to layout the components contained in
+ * the specified target container.
+ *
+ * @param target the component which needs to be laid out
+ * @return the minimum dimensions to lay out the subcomponents of the specified
+ * container.
+ * @see #preferredLayoutSize
+ * @see java.awt.Container
+ * @see java.awt.Container#doLayout
+ */
+ public Dimension minimumLayoutSize(Container target) {
+ // preferred size is also the minimum size
+ if (isHorizontal) {
+ return preferredLayoutSizeHorizontal(target);
+ } else {
+ return preferredLayoutSizeVertical(target);
+ }
+ }
+
+ /**
+ * Lays out the container. This method lets each component take its preferred
+ * size by reshaping the components in the target container in order to satisfy
+ * the constraints of this <code>BetterFlowLayout</code> object.
+ *
+ * @param target the specified component being laid out.
+ * @see Container
+ * @see java.awt.Container#doLayout
+ */
+ public void layoutContainer(Container target) {
+ if (isHorizontal) {
+ layoutContainerHorizontal(target);
+ } else {
+ layoutContainerVertical(target);
+ }
+ }
+
+ /**
+ * Lays out the container. This method lets each component take its preferred
+ * size by reshaping the components in the target container in order to satisfy
+ * the constraints of this <code>BetterFlowLayout</code> object.
+ *
+ * @param target the specified component being laid out.
+ * @see Container
+ * @see java.awt.Container#doLayout
+ */
+ protected void layoutContainerHorizontal(Container target) {
+ synchronized (target.getTreeLock()) {
+ Insets insets = target.getInsets();
+ int maxwidth = target.getSize().width - (insets.left + insets.right + getHgap() * 2);
+ int nmembers = target.getComponentCount();
+ int x = 0, y = insets.top + getVgap();
+ int rowh = 0, start = 0;
+
+ boolean ltr = true; // target.getComponentOrientation().isLeftToRight();
+ Dimension uniform = getUniformDimension(target);
+
+ for (int i = 0; i < nmembers; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ Dimension d = m.getPreferredSize();
+ if (isWidthUniform)
+ d.width = uniform.width;
+ if (isHeightUniform)
+ d.height = uniform.height;
+ m.setSize(d.width, d.height);
+
+ if ((x == 0) || ((x + d.width) <= maxwidth)) {
+ if (x > 0) {
+ x += getHgap();
+ }
+ x += d.width;
+ rowh = Math.max(rowh, d.height);
+ } else {
+ moveComponentsHorizontal(target, insets.left + getHgap(), y, maxwidth - x, rowh, start, i, ltr);
+ x = d.width;
+ y += getVgap() + rowh;
+ rowh = d.height;
+ start = i;
+ }
+ }
+ }
+ moveComponentsHorizontal(target, insets.left + getHgap(), y, maxwidth - x, rowh, start, nmembers, ltr);
+ }
+ }
+
+ /**
+ * Centers the elements in the specified row, if there is any slack.
+ *
+ * @param target the component which needs to be moved
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param width the width dimensions
+ * @param height the height dimensions
+ * @param rowStart the beginning of the row
+ * @param rowEnd the the ending of the row
+ */
+ private void moveComponentsHorizontal(Container target, int x, int y, int width, int height, int rowStart,
+ int rowEnd, boolean ltr) {
+ synchronized (target.getTreeLock()) {
+ switch (getAlignment()) {
+ case LEFT:
+ x += ltr ? 0 : width;
+ break;
+ case CENTER:
+ x += width / 2;
+ break;
+ case RIGHT:
+ x += ltr ? width : 0;
+ break;
//1.2 case LEADING:
//1.2 break;
//1.2 case TRAILING:
//1.2 x += width;
//1.2 break;
+ }
+ for (int i = rowStart; i < rowEnd; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ if (ltr) {
+ m.setLocation(x, y + (height - m.getBounds().height) / 2);
+ } else {
+ m.setLocation(target.getBounds().width - x - m.getBounds().width,
+ y + (height - m.getBounds().height) / 2);
+ }
+ x += m.getBounds().width + getHgap();
+ }
+ }
+ }
}
- for (int i = rowStart ; i < rowEnd ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- if (ltr) {
- m.setLocation(x, y + (height - m.getBounds().height) / 2);
- } else {
- m.setLocation(target.getBounds().width - x - m.getBounds().width, y + (height - m.getBounds().height) / 2);
- }
- x += m.getBounds().width + getHgap();
- }
+
+ /**
+ * Lays out the container. This method lets each component take its preferred
+ * size by reshaping the components in the target container in order to satisfy
+ * the constraints of this <code>BetterFlowLayout</code> object.
+ *
+ * @param target the specified component being laid out.
+ * @see Container
+ * @see java.awt.Container#doLayout
+ */
+ protected void layoutContainerVertical(Container target) {
+ synchronized (target.getTreeLock()) {
+
+ Insets insets = target.getInsets();
+ int maxheight = target.getBounds().height - (insets.top + insets.bottom + getVgap() * 2);
+ int nmembers = target.getComponentCount();
+ int y = 0, x = insets.left + getHgap();
+ int colw = 0, start = 0;
+
+ Dimension uniform = getUniformDimension(target);
+ for (int i = 0; i < nmembers; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ Dimension d = m.getPreferredSize();
+ if (isWidthUniform)
+ d.width = uniform.width;
+ if (isHeightUniform)
+ d.height = uniform.height;
+ m.setSize(d.width, d.height);
+
+ if ((y == 0) || ((y + d.height) <= maxheight)) {
+ if (y > 0) {
+ y += getVgap();
+ }
+ y += d.height;
+ colw = Math.max(colw, d.width);
+ } else {
+ moveComponentsVertical(target, x, insets.top + getVgap(), colw, maxheight - y, start, i);
+ y = d.height;
+ x += getHgap() + colw;
+ colw = d.width;
+ start = i;
+ }
+ }
+ }
+ moveComponentsVertical(target, x, insets.top + getVgap(), colw, maxheight - y, start, nmembers);
+ }
}
- }
- }
-
- /**
- * Lays out the container. This method lets each component take
- * its preferred size by reshaping the components in the
- * target container in order to satisfy the constraints of
- * this <code>BetterFlowLayout</code> object.
- * @param target the specified component being laid out.
- * @see Container
- * @see java.awt.Container#doLayout
- */
- protected void layoutContainerVertical(Container target) {
- synchronized (target.getTreeLock()) {
-
- Insets insets = target.getInsets();
- int maxheight = target.getBounds().height - (insets.top + insets.bottom + getVgap()*2);
- int nmembers = target.getComponentCount();
- int y = 0, x = insets.left + getHgap();
- int colw = 0, start = 0;
-
- Dimension uniform = getUniformDimension( target );
- for (int i = 0 ; i < nmembers ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- Dimension d = m.getPreferredSize();
- if ( isWidthUniform )
- d.width = uniform.width;
- if ( isHeightUniform )
- d.height = uniform.height;
- m.setSize(d.width, d.height);
-
- if ((y == 0) || ((y + d.height) <= maxheight)) {
- if (y > 0) {
- y += getVgap();
- }
- y += d.height;
- colw = Math.max(colw, d.width);
- } else {
- moveComponentsVertical(target, x, insets.top + getVgap(), colw, maxheight - y, start, i );
- y = d.height;
- x += getHgap() + colw;
- colw = d.width;
- start = i;
- }
- }
- }
- moveComponentsVertical(target, x, insets.top + getVgap(), colw, maxheight - y, start, nmembers );
- }
- }
-
- /**
- * Centers the elements in the specified row, if there is any slack.
- * @param target the component which needs to be moved
- * @param x the x coordinate
- * @param y the y coordinate
- * @param width the width dimensions
- * @param height the height dimensions
- * @param colStart the beginning of the column
- * @param colEnd the the ending of the column
- */
- private void moveComponentsVertical(Container target, int x, int y, int width, int height,
- int colStart, int colEnd) {
- synchronized (target.getTreeLock()) {
- switch (getAlignment()) {
- case TOP:
- y += 0;
- break;
- case CENTER_VERTICAL:
- y += ( height / 2 ); // - preferredLayoutSize( target ).height ) / 2 );
- break;
- case BOTTOM:
- y += height;
- break;
- }
- for (int i = colStart ; i < colEnd ; i++) {
- Component m = target.getComponent(i);
- if (m.isVisible()) {
- m.setLocation(x + (width - m.getBounds().width) / 2, y );
+
+ /**
+ * Centers the elements in the specified row, if there is any slack.
+ *
+ * @param target the component which needs to be moved
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param width the width dimensions
+ * @param height the height dimensions
+ * @param colStart the beginning of the column
+ * @param colEnd the the ending of the column
+ */
+ private void moveComponentsVertical(Container target, int x, int y, int width, int height, int colStart,
+ int colEnd) {
+ synchronized (target.getTreeLock()) {
+ switch (getAlignment()) {
+ case TOP:
+ y += 0;
+ break;
+ case CENTER_VERTICAL:
+ y += (height / 2); // - preferredLayoutSize( target ).height ) / 2 );
+ break;
+ case BOTTOM:
+ y += height;
+ break;
+ }
+ for (int i = colStart; i < colEnd; i++) {
+ Component m = target.getComponent(i);
+ if (m.isVisible()) {
+ m.setLocation(x + (width - m.getBounds().width) / 2, y);
// m.setLocation(x, y );
// m.setSize( width, m.getBounds().height ); //!
- y += m.getBounds().height + getVgap();
- }
- }
- }
- }
-
- /**
- * Returns a dimension representing the maximum preferred
- * height and width of all the components in the container.
- * @param target the container to scan.
- * @return a dimension containing the maximum values.
- */
- protected Dimension getUniformDimension(Container target) {
- Component m = null;
- Dimension preferred = null;
- int maxWidth = 0, maxHeight = 0;
- int nmembers = target.getComponentCount();
- for ( int i = 0; i < nmembers; i++ ) {
- m = target.getComponent( i );
- if ( m.isVisible() ) {
- preferred = m.getPreferredSize();
- maxWidth = Math.max( maxWidth, preferred.width );
- maxHeight = Math.max( maxHeight, preferred.height );
- }
- }
- return new Dimension( maxWidth, maxHeight );
- }
-
- /**
- * Returns a string representation of this <code>BetterFlowLayout</code>
- * object and its values.
- * @return a string representation of this layout.
- */
- public String toString() {
- String str = "";
- switch (getAlignment()) {
- case TOP: str = ",align=top"; break;
- case CENTER_VERTICAL: str = ",align=vertical"; break;
- case BOTTOM: str = ",align=bottom"; break;
- default: return super.toString();
+ y += m.getBounds().height + getVgap();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a dimension representing the maximum preferred height and width of
+ * all the components in the container.
+ *
+ * @param target the container to scan.
+ * @return a dimension containing the maximum values.
+ */
+ protected Dimension getUniformDimension(Container target) {
+ Component m = null;
+ Dimension preferred = null;
+ int maxWidth = 0, maxHeight = 0;
+ int nmembers = target.getComponentCount();
+ for (int i = 0; i < nmembers; i++) {
+ m = target.getComponent(i);
+ if (m.isVisible()) {
+ preferred = m.getPreferredSize();
+ maxWidth = Math.max(maxWidth, preferred.width);
+ maxHeight = Math.max(maxHeight, preferred.height);
+ }
+ }
+ return new Dimension(maxWidth, maxHeight);
}
- return getClass().getName() + "[hgap=" + getHgap() + ",vgap=" + getVgap() + str + "]";
- }
+ /**
+ * Returns a string representation of this <code>BetterFlowLayout</code> object
+ * and its values.
+ *
+ * @return a string representation of this layout.
+ */
+ public String toString() {
+ String str = "";
+ switch (getAlignment()) {
+ case TOP:
+ str = ",align=top";
+ break;
+ case CENTER_VERTICAL:
+ str = ",align=vertical";
+ break;
+ case BOTTOM:
+ str = ",align=bottom";
+ break;
+ default:
+ return super.toString();
+ }
+ return getClass().getName() + "[hgap=" + getHgap() + ",vgap=" + getVgap() + str + "]";
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterRootLayout.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterRootLayout.java
index 6e23ca1..238dd14 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterRootLayout.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterRootLayout.java
@@ -28,247 +28,209 @@ import java.awt.Rectangle;
import javax.swing.JPanel;
import javax.swing.JRootPane;
-/**
-* A custom layout for a JRootPane that handles the the layout of a
-* JRootPane's layeredPane, glassPane, and menuBar, and in addition
-* handles four decorative components arranged in a border layout.
-* Add the decorative components to the JRootPane using the directional
-* constants; CENTER is reserved for the content pane and menu bar.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
-public class BetterRootLayout extends BorderLayout
-{
+/**
+ * A custom layout for a JRootPane that handles the the layout of a JRootPane's
+ * layeredPane, glassPane, and menuBar, and in addition handles four decorative
+ * components arranged in a border layout. Add the decorative components to the
+ * JRootPane using the directional constants; CENTER is reserved for the content
+ * pane and menu bar.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
+public class BetterRootLayout extends BorderLayout {
/**
* Returns the amount of space the layout would like to have.
*
* @param the Container for which this layout manager is being used
* @return a Dimension object containing the layout's preferred size
* @throws ClassCastException if parent is not a JRootPane
- */
- public Dimension preferredLayoutSize(Container parent)
- {
+ */
+ public Dimension preferredLayoutSize(Container parent) {
JRootPane rootPane = (JRootPane) parent;
-
+
JPanel proxyPanel = new JPanel();
- proxyPanel.setLayout( new BorderLayout() );
-
+ proxyPanel.setLayout(new BorderLayout());
+
JPanel contentProxy = null;
- if(rootPane.getContentPane() != null) {
+ if (rootPane.getContentPane() != null) {
contentProxy = new JPanel();
- contentProxy.setMinimumSize(
- rootPane.getContentPane().getMinimumSize() );
- contentProxy.setMaximumSize(
- rootPane.getContentPane().getMaximumSize() );
- contentProxy.setPreferredSize(
- rootPane.getContentPane().getPreferredSize() );
- proxyPanel.add( contentProxy, CENTER );
+ contentProxy.setMinimumSize(rootPane.getContentPane().getMinimumSize());
+ contentProxy.setMaximumSize(rootPane.getContentPane().getMaximumSize());
+ contentProxy.setPreferredSize(rootPane.getContentPane().getPreferredSize());
+ proxyPanel.add(contentProxy, CENTER);
}
JPanel menuProxy = null;
- if(rootPane.getJMenuBar() != null) {
+ if (rootPane.getJMenuBar() != null) {
menuProxy = new JPanel();
- menuProxy.setMinimumSize(
- rootPane.getJMenuBar().getMinimumSize() );
- menuProxy.setMaximumSize(
- rootPane.getJMenuBar().getMaximumSize() );
- menuProxy.setPreferredSize(
- rootPane.getJMenuBar().getPreferredSize() );
- proxyPanel.add( menuProxy, NORTH );
+ menuProxy.setMinimumSize(rootPane.getJMenuBar().getMinimumSize());
+ menuProxy.setMaximumSize(rootPane.getJMenuBar().getMaximumSize());
+ menuProxy.setPreferredSize(rootPane.getJMenuBar().getPreferredSize());
+ proxyPanel.add(menuProxy, NORTH);
}
-
- this.addLayoutComponent( proxyPanel, CENTER );
-
- Dimension result = super.preferredLayoutSize( parent );
- this.removeLayoutComponent( proxyPanel );
-
+ this.addLayoutComponent(proxyPanel, CENTER);
+
+ Dimension result = super.preferredLayoutSize(parent);
+
+ this.removeLayoutComponent(proxyPanel);
+
proxyPanel.removeAll();
-
+
return result;
}
-
+
/**
* Returns the minimum amount of space the layout needs.
*
* @param the Container for which this layout manager is being used
* @return a Dimension object containing the layout's minimum size
* @throws ClassCastException if parent is not a JRootPane
- */
- public Dimension minimumLayoutSize(Container parent)
- {
+ */
+ public Dimension minimumLayoutSize(Container parent) {
JRootPane rootPane = (JRootPane) parent;
-
+
JPanel proxyPanel = new JPanel();
- proxyPanel.setLayout( new BorderLayout() );
-
+ proxyPanel.setLayout(new BorderLayout());
+
JPanel contentProxy = null;
- if(rootPane.getContentPane() != null) {
+ if (rootPane.getContentPane() != null) {
contentProxy = new JPanel();
- contentProxy.setMinimumSize(
- rootPane.getContentPane().getMinimumSize() );
- contentProxy.setMaximumSize(
- rootPane.getContentPane().getMaximumSize() );
- contentProxy.setPreferredSize(
- rootPane.getContentPane().getPreferredSize() );
- proxyPanel.add( contentProxy, CENTER );
+ contentProxy.setMinimumSize(rootPane.getContentPane().getMinimumSize());
+ contentProxy.setMaximumSize(rootPane.getContentPane().getMaximumSize());
+ contentProxy.setPreferredSize(rootPane.getContentPane().getPreferredSize());
+ proxyPanel.add(contentProxy, CENTER);
}
JPanel menuProxy = null;
- if(rootPane.getJMenuBar() != null) {
+ if (rootPane.getJMenuBar() != null) {
menuProxy = new JPanel();
- menuProxy.setMinimumSize(
- rootPane.getJMenuBar().getMinimumSize() );
- menuProxy.setMaximumSize(
- rootPane.getJMenuBar().getMaximumSize() );
- menuProxy.setPreferredSize(
- rootPane.getJMenuBar().getPreferredSize() );
- proxyPanel.add( menuProxy, NORTH );
+ menuProxy.setMinimumSize(rootPane.getJMenuBar().getMinimumSize());
+ menuProxy.setMaximumSize(rootPane.getJMenuBar().getMaximumSize());
+ menuProxy.setPreferredSize(rootPane.getJMenuBar().getPreferredSize());
+ proxyPanel.add(menuProxy, NORTH);
}
-
- this.addLayoutComponent( proxyPanel, CENTER );
-
- Dimension result = super.minimumLayoutSize( parent );
- this.removeLayoutComponent( proxyPanel );
-
+ this.addLayoutComponent(proxyPanel, CENTER);
+
+ Dimension result = super.minimumLayoutSize(parent);
+
+ this.removeLayoutComponent(proxyPanel);
+
proxyPanel.removeAll();
-
+
return result;
}
-
+
/**
* Returns the maximum amount of space the layout can use.
*
* @param the Container for which this layout manager is being used
* @return a Dimension object containing the layout's maximum size
* @throws ClassCastException if parent is not a JRootPane
- */
- public Dimension maximumLayoutSize(Container target)
- {
+ */
+ public Dimension maximumLayoutSize(Container target) {
JRootPane rootPane = (JRootPane) target;
-
+
JPanel proxyPanel = new JPanel();
- proxyPanel.setLayout( new BorderLayout() );
-
+ proxyPanel.setLayout(new BorderLayout());
+
JPanel contentProxy = null;
- if(rootPane.getContentPane() != null) {
+ if (rootPane.getContentPane() != null) {
contentProxy = new JPanel();
- contentProxy.setMinimumSize(
- rootPane.getContentPane().getMinimumSize() );
- contentProxy.setMaximumSize(
- rootPane.getContentPane().getMaximumSize() );
- contentProxy.setPreferredSize(
- rootPane.getContentPane().getPreferredSize() );
- proxyPanel.add( contentProxy, CENTER );
+ contentProxy.setMinimumSize(rootPane.getContentPane().getMinimumSize());
+ contentProxy.setMaximumSize(rootPane.getContentPane().getMaximumSize());
+ contentProxy.setPreferredSize(rootPane.getContentPane().getPreferredSize());
+ proxyPanel.add(contentProxy, CENTER);
}
JPanel menuProxy = null;
- if(rootPane.getJMenuBar() != null) {
+ if (rootPane.getJMenuBar() != null) {
menuProxy = new JPanel();
- menuProxy.setMinimumSize(
- rootPane.getJMenuBar().getMinimumSize() );
- menuProxy.setMaximumSize(
- rootPane.getJMenuBar().getMaximumSize() );
- menuProxy.setPreferredSize(
- rootPane.getJMenuBar().getPreferredSize() );
- proxyPanel.add( menuProxy, NORTH );
+ menuProxy.setMinimumSize(rootPane.getJMenuBar().getMinimumSize());
+ menuProxy.setMaximumSize(rootPane.getJMenuBar().getMaximumSize());
+ menuProxy.setPreferredSize(rootPane.getJMenuBar().getPreferredSize());
+ proxyPanel.add(menuProxy, NORTH);
}
-
- this.addLayoutComponent( proxyPanel, CENTER );
-
- Dimension result = super.maximumLayoutSize( target );
- this.removeLayoutComponent( proxyPanel );
-
+ this.addLayoutComponent(proxyPanel, CENTER);
+
+ Dimension result = super.maximumLayoutSize(target);
+
+ this.removeLayoutComponent(proxyPanel);
+
proxyPanel.removeAll();
-
+
return result;
}
-
+
/**
* Instructs the layout manager to perform the layout for the specified
* container.
*
* @param the Container for which this layout manager is being used
* @throws ClassCastException if parent is not a JRootPane
- */
- public void layoutContainer(Container parent)
- {
+ */
+ public void layoutContainer(Container parent) {
JRootPane rootPane = (JRootPane) parent;
-
+
Rectangle b = parent.getBounds();
Insets i = rootPane.getInsets();
int w = b.width - i.right - i.left;
int h = b.height - i.top - i.bottom;
-
+
// layout panes
- if(rootPane.getLayeredPane() != null) {
+ if (rootPane.getLayeredPane() != null) {
rootPane.getLayeredPane().setBounds(i.left, i.top, w, h);
}
- if(rootPane.getGlassPane() != null) {
+ if (rootPane.getGlassPane() != null) {
rootPane.getGlassPane().setBounds(i.left, i.top, w, h);
}
-
+
// handle proxy panel
-
+
JPanel proxyPanel = new JPanel();
- proxyPanel.setLayout( new BorderLayout() );
-
- this.addLayoutComponent( proxyPanel, CENTER );
-
- super.layoutContainer( parent );
+ proxyPanel.setLayout(new BorderLayout());
+
+ this.addLayoutComponent(proxyPanel, CENTER);
+
+ super.layoutContainer(parent);
// use proxy sizes to set sizes of layeredPane's children
Rectangle proxyRect = proxyPanel.getBounds();
- if(rootPane.getJMenuBar() != null) {
+ if (rootPane.getJMenuBar() != null) {
Rectangle menuRect = proxyPanel.getBounds();
menuRect.height = rootPane.getJMenuBar().getPreferredSize().height;
- rootPane.getJMenuBar().setBounds( menuRect );
+ rootPane.getJMenuBar().setBounds(menuRect);
proxyRect.y += menuRect.height;
proxyRect.height -= menuRect.height;
}
- if(rootPane.getContentPane() != null) {
- rootPane.getContentPane().setBounds( proxyRect );
+ if (rootPane.getContentPane() != null) {
+ rootPane.getContentPane().setBounds(proxyRect);
}
- this.removeLayoutComponent( proxyPanel );
-
+ this.removeLayoutComponent(proxyPanel);
+
proxyPanel.removeAll();
}
-
+
/**
- * Passes NORTH, SOUTH, EAST, WEST and CENTER to super implementation,
- * and ignores all others.
- */
- public void addLayoutComponent(Component comp, Object constraints)
- {
- if ( NORTH.equals( constraints ) )
- {
- super.addLayoutComponent( comp, constraints );
- }
- else
- if ( SOUTH.equals( constraints ) )
- {
- super.addLayoutComponent( comp, constraints );
- }
- else
- if ( EAST.equals( constraints ) )
- {
- super.addLayoutComponent( comp, constraints );
+ * Passes NORTH, SOUTH, EAST, WEST and CENTER to super implementation, and
+ * ignores all others.
+ */
+ public void addLayoutComponent(Component comp, Object constraints) {
+ if (NORTH.equals(constraints)) {
+ super.addLayoutComponent(comp, constraints);
+ } else if (SOUTH.equals(constraints)) {
+ super.addLayoutComponent(comp, constraints);
+ } else if (EAST.equals(constraints)) {
+ super.addLayoutComponent(comp, constraints);
+ } else if (WEST.equals(constraints)) {
+ super.addLayoutComponent(comp, constraints);
+ } else if (CENTER.equals(constraints)) {
+ super.addLayoutComponent(comp, constraints);
}
- else
- if ( WEST.equals( constraints ) )
- {
- super.addLayoutComponent( comp, constraints );
- }
- else
- if ( CENTER.equals( constraints ) )
- {
- super.addLayoutComponent( comp, constraints );
- }
-
+
// otherwise, ignore
}
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterTableUI.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterTableUI.java
index deb0eb6..cb1d48a 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterTableUI.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/BetterTableUI.java
@@ -24,100 +24,84 @@ import javax.swing.event.MouseInputListener;
import javax.swing.plaf.basic.BasicTableUI;
/**
-* BetterTableUI allows a JTable to be disabled by
-* listening for MouseEvents and then forwarding them
-* to the usual MouseInputHandler only if the table
-* is enabled. <BR><BR>
-*
-* This class also works around a bug where an editable
-* table's selection is changed when clicking in an edit
-* cell while the control key is down. This typically
-* happened while users were copying/pasting data from
-* cell to cell. <BR><BR>
-*
-* To use, call <code>JTable.setUI()</code> on any
-* JTable with a BetterTableUI as the parameter.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
-public class BetterTableUI extends BasicTableUI implements MouseInputListener
-{
-/**
-* The listener to get all mouse events when the table is enabled.
-*/
- protected MouseInputListener delegateHandler;
-
-/**
-* Overridden to set self as mouse listener and create delegate.
-*/
- protected MouseInputListener createMouseInputListener()
- {
- // normal handler is a protected inner class of parent
- delegateHandler = new MouseInputHandler();
-
- return this;
- }
-
- // interface MouseInputListener
-
- public void mouseClicked(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseClicked(event);
- }
- }
-
- public void mouseDragged(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseDragged(event);
- }
- }
-
- public void mouseEntered(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseEntered(event);
- }
- }
-
- public void mouseExited(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseExited(event);
- }
- }
-
- public void mouseMoved(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseMoved(event);
- }
- }
-
- public void mousePressed(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- // workaround bug - control key removes an existing selection
- if ( table.isEditing() && event.isControlDown() ) return;
-
- delegateHandler.mousePressed(event);
- }
- }
-
- public void mouseReleased(MouseEvent event)
- {
- if ( (table!=null) && (table.isEnabled()) )
- {
- delegateHandler.mouseReleased(event);
- }
- }
+ * BetterTableUI allows a JTable to be disabled by listening for MouseEvents and
+ * then forwarding them to the usual MouseInputHandler only if the table is
+ * enabled. <BR>
+ * <BR>
+ *
+ * This class also works around a bug where an editable table's selection is
+ * changed when clicking in an edit cell while the control key is down. This
+ * typically happened while users were copying/pasting data from cell to cell.
+ * <BR>
+ * <BR>
+ *
+ * To use, call <code>JTable.setUI()</code> on any JTable with a BetterTableUI
+ * as the parameter.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
+public class BetterTableUI extends BasicTableUI implements MouseInputListener {
+ /**
+ * The listener to get all mouse events when the table is enabled.
+ */
+ protected MouseInputListener delegateHandler;
+
+ /**
+ * Overridden to set self as mouse listener and create delegate.
+ */
+ protected MouseInputListener createMouseInputListener() {
+ // normal handler is a protected inner class of parent
+ delegateHandler = new MouseInputHandler();
+
+ return this;
+ }
+
+ // interface MouseInputListener
+
+ public void mouseClicked(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseClicked(event);
+ }
+ }
+
+ public void mouseDragged(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseDragged(event);
+ }
+ }
+
+ public void mouseEntered(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseEntered(event);
+ }
+ }
+
+ public void mouseExited(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseExited(event);
+ }
+ }
+
+ public void mouseMoved(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseMoved(event);
+ }
+ }
+
+ public void mousePressed(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ // workaround bug - control key removes an existing selection
+ if (table.isEditing() && event.isControlDown())
+ return;
+
+ delegateHandler.mousePressed(event);
+ }
+ }
+
+ public void mouseReleased(MouseEvent event) {
+ if ((table != null) && (table.isEnabled())) {
+ delegateHandler.mouseReleased(event);
+ }
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ButtonPanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ButtonPanel.java
index 769e866..7d662ae 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ButtonPanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ButtonPanel.java
@@ -46,565 +46,527 @@ import javax.swing.JPanel;
import javax.swing.UIManager;
/**
-* ButtonPanel handles display and event broadcasting of standard buttons like
-* OK/Cancel/Save/etc. The constructor takes a list or array of strings, each
-* representing a button to appear on the panel from left to right.
-* Any button click will send an action event to all listeners with the action
-* command containing the corresponding string. Note action events are simply
-* forwarded from the buttons themselves, so the source of the event will be
-* the button, not the button panel. The button panel is the source of the
-* STATE_CHANGED events that notify about changes to the panel itself.<BR><BR>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class ButtonPanel extends JPanel implements ActionListener, MouseMotionListener
-{
- // TODO: Button text should be read from resources.
-/**
-* Specifies a "OK" button.
-* This is also the action command sent by the OK button.
-*/
- public static final String OK = "OK";
-/**
-* Specifies a "Save" button.
-* This is also the action command sent by the Save button.
-*/
- public static final String SAVE = "Save";
-/**
-* Specifies a "Refresh" button.
-* This is also the action command sent by the Refresh button.
-*/
- public static final String REFRESH = "Refresh";
-/**
-* Specifies a "Clear All" button.
-* This is also the action command sent by the Clear All button.
-*/
- public static final String CLEAR_ALL = "Clear All";
-/**
-* Specifies a "Refresh" button.
-* This is also the action command sent by the Cancel button.
-*/
- public static final String CANCEL = "Cancel";
-/**
-* Specifies a "Yes" button.
-* This is also the action command sent by the Yes button.
-*/
- public static final String YES = "Yes";
-/**
-* Specifies a "No" button.
-* This is also the action command sent by the No button.
-*/
- public static final String NO = "No";
-/**
-* Specifies an "Add" button.
-* This is also the action command sent by the Add button.
-*/
- public static final String ADD = "Add";
-/**
-* Specifies a "Remove" button.
-* This is also the action command sent by the Remove button.
-*/
- public static final String REMOVE = "Remove";
-/**
-* This is the action command to all listeners when the button state is changed.
-*/
- public static final String STATE_CHANGED = "STATE_CHANGED";
-
-/**
-* This is the container to which buttons are added.
-*/
- protected Container buttonContainer = null; // useful for subclasses
-/**
-* This is the list of all buttons on the panel.
-*/
- protected Vector buttonList = null;
-/**
-* The insets for this panel, so they can be modified.
-*/
- protected Insets insets = new Insets( 5, 5, 5, 5 );
-
-/**
-* This is the layout manager - which must be a FlowLayout or subclass.
-*/
- protected FlowLayout buttonPanelLayout = null;
-
- // for action multicasting
- protected ActionListener actionListener = null;
-
-
-/**
-* Constructs a ButtonPanel. Three buttons are created
-* so the panel is filled when used in a GUI-builder environment.
-*/
- public ButtonPanel()
- {
- buttonList = new Vector();
- initLayout();
-
- // default labels for bean layout
- setLabels( new String[] { "One", "Two", "Three" } );
- }
-
-/**
-* This method is responsible for the initial layout of the panel.
-* Subclasses can implement different layouts, but this method
-* is responsible for initializing buttonContainer and buttonPanelLayout
-* and setting the container to use the layout.
-*/
- protected void initLayout()
- {
- this.setInsets( super.getInsets() );
- buttonContainer = this;
- buttonPanelLayout = new BetterFlowLayout( BetterFlowLayout.RIGHT );
- buttonContainer.setLayout(buttonPanelLayout);
- ((BetterFlowLayout)buttonPanelLayout).setWidthUniform( true );
-
- // setBackground( Color.blue ); // useful for debugging
- }
-
-/**
-* Constructs a ButtonPanel using specified buttons.
-* @param buttonList An array containing the strings to be used in labeling the buttons.
-*/
- public ButtonPanel( String[] buttonList )
- {
- this();
- setLabels( buttonList );
- }
-
-/**
-* Constructs a ButtonPane using specified actions. For each action, a button
-* is created, that when pressed the corresponding action is activated. The
-* "name" of the action is used as the title of the button.
-* @param actionList An array of actions to be used to create buttons with.
-*/
- public ButtonPanel( Action[] actionList )
- {
- this();
- setLabels( actionList );
- }
-
-/**
-* Creates the buttons to appear on the panel. Any existing buttons
-* are replaced. The labels are used as names and action commands
-* in addition to labels.
-* @param labels An array of strings to be used in labeling the buttons.
-* If null, all buttons will be removed.
-*/
- public void setLabels( String[] labels )
- {
- if ( labels == null )
- {
- labels = new String[] {};
- }
-
- buttonContainer.removeAll();
- this.buttonList = new Vector( labels.length );
-
- String item = null;
- Component button;
- for ( int i = 0; i < labels.length; i++ )
- {
- item = labels[i];
- if ( item != null )
- {
- button = createComponentWithLabel( item.toString() );
- this.buttonList.addElement( item );
- addComponentToPanel( button );
- button.setEnabled( this.isEnabled() );
-/*
- if ( i == 0 )
- {
- JRootPane root = SwingUtilities.getRootPane( button );
- if ( root != null )
- root.setDefaultButton( button );
- }
-*/
- }
- else
- {
- throw new IllegalArgumentException( "ButtonPanel.setButtons: nulls are not allowed." );
- }
- }
-
- this.revalidate();
- this.repaint();
- broadcastEvent( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, STATE_CHANGED ) );
- }
-
-/**
-*
-*/
- public void setLabels( Action[] actions )
- {
- if ( actions == null )
- {
- actions = new Action[] {};
- }
-
- buttonContainer.removeAll();
- this.buttonList = new Vector( actions.length );
-
- Action action = null;
- Component button;
- for ( int i = 0; i < actions.length; i++ )
- {
- action = actions[i];
- if ( action != null )
- {
- String name = ( String )action.getValue( Action.NAME );
- button = createComponentWithLabel( name );
- this.buttonList.addElement( name );
- addComponentToPanel( button );
- button.setEnabled( this.isEnabled() ? action.isEnabled() : false );
-
- // Add the action to the "button" if it knows about action listeners.
- try
- {
- Method addActionListenerMethod =
- button.getClass().getMethod( "addActionListener", new Class[] { ActionListener.class } );
- addActionListenerMethod.invoke( button, new Object[] { action } );
- }
- catch ( NoSuchMethodException e ) { /* Do Nothing */ }
- catch ( IllegalAccessException e ) { e.printStackTrace(); /* TODO: Do Something? */ }
- catch ( InvocationTargetException e ) { e.printStackTrace(); /* TODO: Do Something? */ }
-
- // Create a new listener for property change events and have
- // the action broadcast to that listener.
- PropertyChangeListener pcListener = new ActionChangeListener( button );
- action.addPropertyChangeListener( pcListener );
- }
- else
- {
- throw new IllegalArgumentException( "ButtonPanel.setButtons: nulls are not allowed." );
- }
- }
-
- this.revalidate();
- this.repaint();
- broadcastEvent( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, STATE_CHANGED ) );
- }
-
-
-/**
-* Gets the labels of the buttons that appear on the panel, ordered from left to right.
-* @return A new list containing strings used in labeling the buttons.
-*/
- public String[] getLabels()
- {
- String[] labels = new String[ buttonList.size() ];
- int i = 0;
- for ( Enumeration it = buttonList.elements(); it.hasMoreElements(); )
- {
- labels[i++] = it.nextElement().toString();
- }
- return labels;
- }
-
-/**
-* Gets the first component having the specified name.
-* @return A component with the specified name, or null if none match.
-*/
- public Component getButton( String aLabel )
- {
- if ( aLabel == null ) return null;
-
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( aLabel.equals( c.getName() ) )
- {
- return c;
- }
- }
- return null;
- }
-
-/**
-* Creates a new component with the specified label.
-* The label is also used for the component's name
-* and action command, if any.
-* (This implementation returns a JButton.)
-* @param aLabel The label for the component that will be created.
-* @return The newly created component.
-*/
- protected Component createComponentWithLabel( String aLabel )
- {
- String buttonLabel = aLabel; // TODO: get string from resource
- JButton newButton = new JButton(); // might allow other types in future
- newButton.setName( aLabel );
- newButton.setText( buttonLabel );
- newButton.setActionCommand( aLabel );
- newButton.addActionListener( this );
- return newButton;
- }
-
-/**
-* Adds a component to the right-most side of the layout.
-* @param aComponent The component to be added to the layout.
-*/
- protected void addComponentToPanel( Component aComponent )
- {
- buttonContainer.add( aComponent );
- }
-
-
-/**
-* Changes the alignment of the buttons in the panel. Defaults to right-justified.
-* @param alignment A valid alignment code, per BetterFlowLayout implementation.
-* @see BetterFlowLayout
-*/
- public void setAlignment( int alignment )
- {
- buttonPanelLayout.setAlignment(alignment);
- buttonContainer.doLayout();
- }
-/**
-* Gets the alignment of the buttons in the panel.
-* @return An alignment code, per FlowLayout implementation.
-* @see FlowLayout
-*/
- public int getAlignment()
- {
- return buttonPanelLayout.getAlignment();
- }
-
-/**
-* Changes the horizontal spacing between components in the panel.
-* @param newHgap the new spacing, in pixels. May not be negative.
-*/
- public void setHgap( int newHgap )
- {
- if ( newHgap < 0 ) return; // may not be negative
- buttonPanelLayout.setHgap( newHgap );
- }
-
-/**
-* Gets the current horizontal spacing between components.
-* @return the current horizontal spacing, in pixels.
-*/
- public int getHgap()
- {
- return buttonPanelLayout.getHgap();
- }
-
-/**
-* Changes the vertical spacing between components in the panel.
-* @param newVgap the new spacing, in pixels. May not be negative.
-*/
- public void setVgap( int newVgap )
- {
- if ( newVgap < 0 ) return; // may not be negative
- buttonPanelLayout.setVgap( newVgap );
- }
-
-/**
-* Gets the current vertical spacing between components.
-* @return the current vertical spacing, in pixels.
-*/
- public int getVgap()
- {
- return buttonPanelLayout.getVgap();
- }
-
-/**
-* Changes the insets for this panel.
-* @param newInsets the new insets.
-*/
- public void setInsets( Insets newInsets )
- {
- insets = newInsets;
- }
-
-/**
-* Overridden to return the user-specified insets for this panel.
-* @return the current insets for this panel.
-*/
- public Insets getInsets()
- {
- return insets;
- }
-
-/**
-* Overridden to call setEnabled on all components on panel.
-* @param isEnabled whether to enable the panel and all components on it.
-*/
- public void setEnabled( boolean isEnabled )
- {
- super.setEnabled( isEnabled );
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- buttonContainer.getComponent( i ).setEnabled( isEnabled );
- }
- }
-
- // Action Multicast methods
-
-/**
-* Adds an action listener to the list that will be
-* notified by button events and changes in button state.
-* @param l An action listener to be notified.
-*/
- public void addActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.add(actionListener, l);
- }
-/**
-* Removes an action listener from the list that will be
-* notified by button events and changes in button state.
-* @param l An action listener to be removed.
-*/
- public void removeActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.remove(actionListener, l);
- }
-/**
-* Notifies all registered action listeners of a pending Action Event.
-* @param e An action event to be broadcast.
-*/
- protected void broadcastEvent(ActionEvent e)
- {
- if (actionListener != null)
- {
- actionListener.actionPerformed(e);
- }
- }
-
- // interface ActionListener
-
-/**
-* Called by buttons on panel and by other components that
-* might be set to broadcast events to this listener.
-* @param e An action event to be received.
-*/
- public void actionPerformed(ActionEvent e)
- {
- broadcastEvent(e);
- }
-
-/**
-* A property change listener that listens specifically for property changes
-* from action objects. This is the class that ties in the action to the
-* button. This class is added to an action as a property change listener.
-* The corresponding component is referenced by this class toe easily handle
-* updates to the component caused by changes to the action.
-*/
- public class ActionChangeListener implements PropertyChangeListener
- {
- /** The UI component that is affected by the action's changes. */
- Component theComponent;
-
- /**
- * Constructs an ActionChangeListener with the given component being
- * the recipient of the action's changes.
- * @param The component to bind with the action.
- */
- public ActionChangeListener( Component aComponent )
- {
- super();
- theComponent = aComponent;
- }
-
- /**
- * Called whenever a property changes on the action object.
- * @pram e The property change event generated by the action.
- */
- public void propertyChange( PropertyChangeEvent e )
- {
- String propertyName = e.getPropertyName();
- if ( propertyName.equals( Action.NAME ) )
- {
- String name = ( String )e.getNewValue();
- if ( theComponent instanceof AbstractButton )
- {
- AbstractButton button = ( AbstractButton )theComponent;
- String oldName = button.getName();
- button.setText( name );
- button.setName( name );
- button.setActionCommand( name );
-
- // Replace the old name of the component with the new name
- // in the ButtonPanel's list of components.
- buttonList.setElementAt( name, buttonList.indexOf( oldName ) );
- }
-
- // TODO: If component is not a button (or doesn't define the getText()
- // then what should be done.
- }
- else if ( propertyName.equals( "enabled" ) )
- {
- Boolean enabled = ( Boolean )e.getNewValue();
- theComponent.setEnabled( ButtonPanel.this.isEnabled() ? enabled.booleanValue() : false );
- }
-
- // TODO: Icon?
- }
- }
-
-
- // for testing
-
- public static void main( String[] argv )
- {
- try
- {
- UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
- }
- catch (Exception exc)
- {
-
- }
-
- JFrame dialog = new JFrame();
- BorderLayout bl = new BorderLayout( 20, 20 );
-
- ButtonPanel panel = new ButtonPanel();
+ * ButtonPanel handles display and event broadcasting of standard buttons like
+ * OK/Cancel/Save/etc. The constructor takes a list or array of strings, each
+ * representing a button to appear on the panel from left to right. Any button
+ * click will send an action event to all listeners with the action command
+ * containing the corresponding string. Note action events are simply forwarded
+ * from the buttons themselves, so the source of the event will be the button,
+ * not the button panel. The button panel is the source of the STATE_CHANGED
+ * events that notify about changes to the panel itself.<BR>
+ * <BR>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class ButtonPanel extends JPanel implements ActionListener, MouseMotionListener {
+ // TODO: Button text should be read from resources.
+ /**
+ * Specifies a "OK" button. This is also the action command sent by the OK
+ * button.
+ */
+ public static final String OK = "OK";
+ /**
+ * Specifies a "Save" button. This is also the action command sent by the Save
+ * button.
+ */
+ public static final String SAVE = "Save";
+ /**
+ * Specifies a "Refresh" button. This is also the action command sent by the
+ * Refresh button.
+ */
+ public static final String REFRESH = "Refresh";
+ /**
+ * Specifies a "Clear All" button. This is also the action command sent by the
+ * Clear All button.
+ */
+ public static final String CLEAR_ALL = "Clear All";
+ /**
+ * Specifies a "Refresh" button. This is also the action command sent by the
+ * Cancel button.
+ */
+ public static final String CANCEL = "Cancel";
+ /**
+ * Specifies a "Yes" button. This is also the action command sent by the Yes
+ * button.
+ */
+ public static final String YES = "Yes";
+ /**
+ * Specifies a "No" button. This is also the action command sent by the No
+ * button.
+ */
+ public static final String NO = "No";
+ /**
+ * Specifies an "Add" button. This is also the action command sent by the Add
+ * button.
+ */
+ public static final String ADD = "Add";
+ /**
+ * Specifies a "Remove" button. This is also the action command sent by the
+ * Remove button.
+ */
+ public static final String REMOVE = "Remove";
+ /**
+ * This is the action command to all listeners when the button state is changed.
+ */
+ public static final String STATE_CHANGED = "STATE_CHANGED";
+
+ /**
+ * This is the container to which buttons are added.
+ */
+ protected Container buttonContainer = null; // useful for subclasses
+ /**
+ * This is the list of all buttons on the panel.
+ */
+ protected Vector buttonList = null;
+ /**
+ * The insets for this panel, so they can be modified.
+ */
+ protected Insets insets = new Insets(5, 5, 5, 5);
+
+ /**
+ * This is the layout manager - which must be a FlowLayout or subclass.
+ */
+ protected FlowLayout buttonPanelLayout = null;
+
+ // for action multicasting
+ protected ActionListener actionListener = null;
+
+ /**
+ * Constructs a ButtonPanel. Three buttons are created so the panel is filled
+ * when used in a GUI-builder environment.
+ */
+ public ButtonPanel() {
+ buttonList = new Vector();
+ initLayout();
+
+ // default labels for bean layout
+ setLabels(new String[] { "One", "Two", "Three" });
+ }
+
+ /**
+ * This method is responsible for the initial layout of the panel. Subclasses
+ * can implement different layouts, but this method is responsible for
+ * initializing buttonContainer and buttonPanelLayout and setting the container
+ * to use the layout.
+ */
+ protected void initLayout() {
+ this.setInsets(super.getInsets());
+ buttonContainer = this;
+ buttonPanelLayout = new BetterFlowLayout(BetterFlowLayout.RIGHT);
+ buttonContainer.setLayout(buttonPanelLayout);
+ ((BetterFlowLayout) buttonPanelLayout).setWidthUniform(true);
+
+ // setBackground( Color.blue ); // useful for debugging
+ }
+
+ /**
+ * Constructs a ButtonPanel using specified buttons.
+ *
+ * @param buttonList An array containing the strings to be used in labeling the
+ * buttons.
+ */
+ public ButtonPanel(String[] buttonList) {
+ this();
+ setLabels(buttonList);
+ }
+
+ /**
+ * Constructs a ButtonPane using specified actions. For each action, a button is
+ * created, that when pressed the corresponding action is activated. The "name"
+ * of the action is used as the title of the button.
+ *
+ * @param actionList An array of actions to be used to create buttons with.
+ */
+ public ButtonPanel(Action[] actionList) {
+ this();
+ setLabels(actionList);
+ }
+
+ /**
+ * Creates the buttons to appear on the panel. Any existing buttons are
+ * replaced. The labels are used as names and action commands in addition to
+ * labels.
+ *
+ * @param labels An array of strings to be used in labeling the buttons. If
+ * null, all buttons will be removed.
+ */
+ public void setLabels(String[] labels) {
+ if (labels == null) {
+ labels = new String[] {};
+ }
+
+ buttonContainer.removeAll();
+ this.buttonList = new Vector(labels.length);
+
+ String item = null;
+ Component button;
+ for (int i = 0; i < labels.length; i++) {
+ item = labels[i];
+ if (item != null) {
+ button = createComponentWithLabel(item.toString());
+ this.buttonList.addElement(item);
+ addComponentToPanel(button);
+ button.setEnabled(this.isEnabled());
+ /*
+ * if ( i == 0 ) { JRootPane root = SwingUtilities.getRootPane( button ); if (
+ * root != null ) root.setDefaultButton( button ); }
+ */
+ } else {
+ throw new IllegalArgumentException("ButtonPanel.setButtons: nulls are not allowed.");
+ }
+ }
+
+ this.revalidate();
+ this.repaint();
+ broadcastEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, STATE_CHANGED));
+ }
+
+ /**
+ *
+ */
+ public void setLabels(Action[] actions) {
+ if (actions == null) {
+ actions = new Action[] {};
+ }
+
+ buttonContainer.removeAll();
+ this.buttonList = new Vector(actions.length);
+
+ Action action = null;
+ Component button;
+ for (int i = 0; i < actions.length; i++) {
+ action = actions[i];
+ if (action != null) {
+ String name = (String) action.getValue(Action.NAME);
+ button = createComponentWithLabel(name);
+ this.buttonList.addElement(name);
+ addComponentToPanel(button);
+ button.setEnabled(this.isEnabled() ? action.isEnabled() : false);
+
+ // Add the action to the "button" if it knows about action listeners.
+ try {
+ Method addActionListenerMethod = button.getClass().getMethod("addActionListener",
+ new Class[] { ActionListener.class });
+ addActionListenerMethod.invoke(button, new Object[] { action });
+ } catch (NoSuchMethodException e) {
+ /* Do Nothing */ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ /* TODO: Do Something? */ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ /* TODO: Do Something? */ }
+
+ // Create a new listener for property change events and have
+ // the action broadcast to that listener.
+ PropertyChangeListener pcListener = new ActionChangeListener(button);
+ action.addPropertyChangeListener(pcListener);
+ } else {
+ throw new IllegalArgumentException("ButtonPanel.setButtons: nulls are not allowed.");
+ }
+ }
+
+ this.revalidate();
+ this.repaint();
+ broadcastEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, STATE_CHANGED));
+ }
+
+ /**
+ * Gets the labels of the buttons that appear on the panel, ordered from left to
+ * right.
+ *
+ * @return A new list containing strings used in labeling the buttons.
+ */
+ public String[] getLabels() {
+ String[] labels = new String[buttonList.size()];
+ int i = 0;
+ for (Enumeration it = buttonList.elements(); it.hasMoreElements();) {
+ labels[i++] = it.nextElement().toString();
+ }
+ return labels;
+ }
+
+ /**
+ * Gets the first component having the specified name.
+ *
+ * @return A component with the specified name, or null if none match.
+ */
+ public Component getButton(String aLabel) {
+ if (aLabel == null)
+ return null;
+
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if (aLabel.equals(c.getName())) {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new component with the specified label. The label is also used for
+ * the component's name and action command, if any. (This implementation returns
+ * a JButton.)
+ *
+ * @param aLabel The label for the component that will be created.
+ * @return The newly created component.
+ */
+ protected Component createComponentWithLabel(String aLabel) {
+ String buttonLabel = aLabel; // TODO: get string from resource
+ JButton newButton = new JButton(); // might allow other types in future
+ newButton.setName(aLabel);
+ newButton.setText(buttonLabel);
+ newButton.setActionCommand(aLabel);
+ newButton.addActionListener(this);
+ return newButton;
+ }
+
+ /**
+ * Adds a component to the right-most side of the layout.
+ *
+ * @param aComponent The component to be added to the layout.
+ */
+ protected void addComponentToPanel(Component aComponent) {
+ buttonContainer.add(aComponent);
+ }
+
+ /**
+ * Changes the alignment of the buttons in the panel. Defaults to
+ * right-justified.
+ *
+ * @param alignment A valid alignment code, per BetterFlowLayout implementation.
+ * @see BetterFlowLayout
+ */
+ public void setAlignment(int alignment) {
+ buttonPanelLayout.setAlignment(alignment);
+ buttonContainer.doLayout();
+ }
+
+ /**
+ * Gets the alignment of the buttons in the panel.
+ *
+ * @return An alignment code, per FlowLayout implementation.
+ * @see FlowLayout
+ */
+ public int getAlignment() {
+ return buttonPanelLayout.getAlignment();
+ }
+
+ /**
+ * Changes the horizontal spacing between components in the panel.
+ *
+ * @param newHgap the new spacing, in pixels. May not be negative.
+ */
+ public void setHgap(int newHgap) {
+ if (newHgap < 0)
+ return; // may not be negative
+ buttonPanelLayout.setHgap(newHgap);
+ }
+
+ /**
+ * Gets the current horizontal spacing between components.
+ *
+ * @return the current horizontal spacing, in pixels.
+ */
+ public int getHgap() {
+ return buttonPanelLayout.getHgap();
+ }
+
+ /**
+ * Changes the vertical spacing between components in the panel.
+ *
+ * @param newVgap the new spacing, in pixels. May not be negative.
+ */
+ public void setVgap(int newVgap) {
+ if (newVgap < 0)
+ return; // may not be negative
+ buttonPanelLayout.setVgap(newVgap);
+ }
+
+ /**
+ * Gets the current vertical spacing between components.
+ *
+ * @return the current vertical spacing, in pixels.
+ */
+ public int getVgap() {
+ return buttonPanelLayout.getVgap();
+ }
+
+ /**
+ * Changes the insets for this panel.
+ *
+ * @param newInsets the new insets.
+ */
+ public void setInsets(Insets newInsets) {
+ insets = newInsets;
+ }
+
+ /**
+ * Overridden to return the user-specified insets for this panel.
+ *
+ * @return the current insets for this panel.
+ */
+ public Insets getInsets() {
+ return insets;
+ }
+
+ /**
+ * Overridden to call setEnabled on all components on panel.
+ *
+ * @param isEnabled whether to enable the panel and all components on it.
+ */
+ public void setEnabled(boolean isEnabled) {
+ super.setEnabled(isEnabled);
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ buttonContainer.getComponent(i).setEnabled(isEnabled);
+ }
+ }
+
+ // Action Multicast methods
+
+ /**
+ * Adds an action listener to the list that will be notified by button events
+ * and changes in button state.
+ *
+ * @param l An action listener to be notified.
+ */
+ public void addActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.add(actionListener, l);
+ }
+
+ /**
+ * Removes an action listener from the list that will be notified by button
+ * events and changes in button state.
+ *
+ * @param l An action listener to be removed.
+ */
+ public void removeActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.remove(actionListener, l);
+ }
+
+ /**
+ * Notifies all registered action listeners of a pending Action Event.
+ *
+ * @param e An action event to be broadcast.
+ */
+ protected void broadcastEvent(ActionEvent e) {
+ if (actionListener != null) {
+ actionListener.actionPerformed(e);
+ }
+ }
+
+ // interface ActionListener
+
+ /**
+ * Called by buttons on panel and by other components that might be set to
+ * broadcast events to this listener.
+ *
+ * @param e An action event to be received.
+ */
+ public void actionPerformed(ActionEvent e) {
+ broadcastEvent(e);
+ }
+
+ /**
+ * A property change listener that listens specifically for property changes
+ * from action objects. This is the class that ties in the action to the button.
+ * This class is added to an action as a property change listener. The
+ * corresponding component is referenced by this class toe easily handle updates
+ * to the component caused by changes to the action.
+ */
+ public class ActionChangeListener implements PropertyChangeListener {
+ /** The UI component that is affected by the action's changes. */
+ Component theComponent;
+
+ /**
+ * Constructs an ActionChangeListener with the given component being the
+ * recipient of the action's changes.
+ *
+ * @param The component to bind with the action.
+ */
+ public ActionChangeListener(Component aComponent) {
+ super();
+ theComponent = aComponent;
+ }
+
+ /**
+ * Called whenever a property changes on the action object.
+ *
+ * @pram e The property change event generated by the action.
+ */
+ public void propertyChange(PropertyChangeEvent e) {
+ String propertyName = e.getPropertyName();
+ if (propertyName.equals(Action.NAME)) {
+ String name = (String) e.getNewValue();
+ if (theComponent instanceof AbstractButton) {
+ AbstractButton button = (AbstractButton) theComponent;
+ String oldName = button.getName();
+ button.setText(name);
+ button.setName(name);
+ button.setActionCommand(name);
+
+ // Replace the old name of the component with the new name
+ // in the ButtonPanel's list of components.
+ buttonList.setElementAt(name, buttonList.indexOf(oldName));
+ }
+
+ // TODO: If component is not a button (or doesn't define the getText()
+ // then what should be done.
+ } else if (propertyName.equals("enabled")) {
+ Boolean enabled = (Boolean) e.getNewValue();
+ theComponent.setEnabled(ButtonPanel.this.isEnabled() ? enabled.booleanValue() : false);
+ }
+
+ // TODO: Icon?
+ }
+ }
+
+ // for testing
+
+ public static void main(String[] argv) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception exc) {
+
+ }
+
+ JFrame dialog = new JFrame();
+ BorderLayout bl = new BorderLayout(20, 20);
+
+ ButtonPanel panel = new ButtonPanel();
// ButtonPanel panel = new ButtonPanel( new String[] { "OkayOkay", "CancelCancel" } );
- dialog.getContentPane().setLayout( bl );
- dialog.getContentPane().add( panel, BorderLayout.CENTER );
- dialog.setLocation( 50, 50 );
- // dialog.setSize( 450, 150 );
-
- panel.setAlignment( BetterFlowLayout.CENTER_VERTICAL );
- panel.getButton( "One" ).setEnabled( false );
-
- dialog.pack();
- dialog.setVisible( true );
-
- try
- {
- BeanInfo info = Introspector.getBeanInfo( ButtonPanel.class );
- PropertyDescriptor[] props = info.getPropertyDescriptors();
- for ( int i = 0; i < props.length; i++ )
- {
- System.out.println( props[i].getName() );
- }
- }
- catch (Exception exc)
- {
- System.out.println( exc );
- }
+ dialog.getContentPane().setLayout(bl);
+ dialog.getContentPane().add(panel, BorderLayout.CENTER);
+ dialog.setLocation(50, 50);
+ // dialog.setSize( 450, 150 );
+ panel.setAlignment(BetterFlowLayout.CENTER_VERTICAL);
+ panel.getButton("One").setEnabled(false);
+ dialog.pack();
+ dialog.setVisible(true);
+ try {
+ BeanInfo info = Introspector.getBeanInfo(ButtonPanel.class);
+ PropertyDescriptor[] props = info.getPropertyDescriptors();
+ for (int i = 0; i < props.length; i++) {
+ System.out.println(props[i].getName());
+ }
+ } catch (Exception exc) {
+ System.out.println(exc);
+ }
- }
-
- public void mouseDragged(MouseEvent e)
- {
- }
-
- public void mouseMoved(MouseEvent e)
- {
- }
+ }
+ public void mouseDragged(MouseEvent e) {
+ }
+ public void mouseMoved(MouseEvent e) {
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/CheckButtonPanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/CheckButtonPanel.java
index 5e847ae..8116678 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/CheckButtonPanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/CheckButtonPanel.java
@@ -27,246 +27,223 @@ import javax.swing.JCheckBox;
import javax.swing.border.EmptyBorder;
/**
-* CheckButtonPanel is a simple extension of ButtonPanel.
-* Differences are that it uses JCheckBoxes and the
-* default alignment is vertical. The panel defaults to having
-* no buttons selected.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class CheckButtonPanel extends ButtonPanel
-{
-/**
-* Constructs a CheckButtonPanel. Three buttons are created
-* so the panel is filled when used in a GUI-builder environment.
-*/
- public CheckButtonPanel()
- {
- super();
- }
-
-/**
-* Constructs a ButtonPanel using specified buttons.
-* @param buttonList An array containing the strings to be used in labeling the buttons.
-*/
- public CheckButtonPanel( String[] buttonList )
- {
- super( buttonList );
- }
-
-/**
-* Overridden to set vertical-center alignment and zero vgap.
-*/
- protected void initLayout()
- {
- super.initLayout();
- buttonPanelLayout.setAlignment( BetterFlowLayout.CENTER_VERTICAL );
- buttonPanelLayout.setVgap( 0 );
- }
-
-/**
-* Overridden to return a JRadioButton.
-* @param aLabel The label for the component that will be created.
-* @return The newly created component.
-*/
- protected Component createComponentWithLabel( String aLabel )
- {
- String buttonLabel = aLabel;
- JCheckBox newButton = new JCheckBox();
- newButton.setName( aLabel );
- newButton.setText( buttonLabel );
- newButton.setActionCommand( aLabel );
- newButton.addActionListener( this );
-
- // reduce insets per java l&f guidelines (was 4 on each side)
- newButton.setBorder( new EmptyBorder( 1, 4, 1, 4 ) );
-
- return newButton;
- }
-
-/**
-* Sets the value of the button whose name matches the given text value.
-* @param aName A String matching the name of one of the buttons.
-* If null, empty, or not matching, nothing happens.
-* @param aValue A value to set the button.
-*/
- public void setValue(String aName, boolean aValue)
- {
- if ( aName != null )
- {
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( c instanceof AbstractButton )
- {
- if ( c.getName().equals( aName ) )
- {
- ((AbstractButton)c).setSelected( aValue );
- c.repaint();
- return;
- }
- }
- }
- }
- // null, empty, or not matching - exit.
- System.out.println( "CheckButtonPanel.setValue: not found: " + aName );
- }
-
-/**
-* Sets the state of the specified buttons to the specified value.
-* @param aLabelArray An Array of Strings listing the buttons to be set.
-* @param aValue The value to which the specified buttons will be set.
-*/
- public void setValues(String[] aLabelArray, boolean aValue)
- {
- if ( aLabelArray != null )
- {
- for ( int i = 0; i < aLabelArray.length; i++ )
- {
- setValue( aLabelArray[i], aValue );
- }
- }
- }
-
-/**
-* Convenience method to set all checkboxes on the panel.
-* @param aValue The value to which all checkboxes on the panel will be set.
-*/
- public void setAllValues(boolean aValue)
- {
- setValues( getLabels(), aValue );
- }
-
-/**
-* Convenience method to check all boxes on the panel.
-*/
- public void checkAll()
- {
- setAllValues( true );
- }
-
-/**
-* Convenience method to clear all boxes on the panel.
-*/
- public void clearAll()
- {
- setAllValues( false );
- }
-
-/**
-* A convenience method to set only those buttons on the entire
-* panel that should be checked. Buttons not in the list are unchecked.
-* @param aLabelArray An Array of Strings listing the buttons to be set.
-*/
- public void setCheckedValues(String[] aLabelArray)
- {
- setAllValues( false );
- setValues( aLabelArray, true );
- }
-
-/**
-* Gets the labels of all checkboxes that are checked.
-* @return A List of Strings containing the labels of the boxes that are checked.
-*/
- public List getCheckedValueList()
- {
- Vector v = new Vector();
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( c instanceof AbstractButton )
- {
- if ( ((AbstractButton)c).isSelected() )
- {
- v.addElement(c.getName());
- }
- }
- }
- return v;
- }
-
-/**
-* Gets the labels of all checkboxes that are checked.
-* @return A String Array containing the labels of the boxes that are checked.
-*/
- public String[] getCheckedValues()
- {
- List v = getCheckedValueList();
- String[] result = new String[ v.size() ];
- for ( int i = 0; i < v.size(); i++ )
- {
- result[i] = (String) v.get(i);
- }
- return result;
- }
-
-/**
-* Gets the value of the specified button.
-* @param aName A String matching the name of one of the buttons.
-* @return True if the button is checked, False if it is not checked.
-* NOTE: If the button is not found in the list, False is returned.
-*/
- public boolean getValue( String aName )
- {
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( ( c instanceof AbstractButton ) && ( ((AbstractButton)c).isSelected() ) )
- {
- if ( ((AbstractButton)c).getText().equals( aName ) )
- {
- return ((AbstractButton)c).isSelected();
- }
- }
- }
- return false;
- }
-
- // for testing
-
- public static void main( String[] argv )
- {
- try
- {
- javax.swing.UIManager.setLookAndFeel( javax.swing.UIManager.getSystemLookAndFeelClassName() );
- }
- catch (Exception exc)
- {
-
- }
-
- javax.swing.JFrame dialog = new javax.swing.JFrame();
- java.awt.BorderLayout bl = new java.awt.BorderLayout( 20, 20 );
-
- CheckButtonPanel panel = new CheckButtonPanel( new String[] { "One", "Two", "Three" } );
-
- dialog.getContentPane().setLayout( bl );
- dialog.getContentPane().add( panel, java.awt.BorderLayout.CENTER );
- dialog.setLocation( 50, 50 );
- // dialog.setSize( 450, 150 );
-
- panel.setAlignment( BetterFlowLayout.CENTER_VERTICAL );
- panel.getButton( "One" ).setEnabled( false );
- panel.setValues( new String[] { "One" }, true );
- panel.setValue( "Three", true );
+ * CheckButtonPanel is a simple extension of ButtonPanel. Differences are that
+ * it uses JCheckBoxes and the default alignment is vertical. The panel defaults
+ * to having no buttons selected.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class CheckButtonPanel extends ButtonPanel {
+ /**
+ * Constructs a CheckButtonPanel. Three buttons are created so the panel is
+ * filled when used in a GUI-builder environment.
+ */
+ public CheckButtonPanel() {
+ super();
+ }
+
+ /**
+ * Constructs a ButtonPanel using specified buttons.
+ *
+ * @param buttonList An array containing the strings to be used in labeling the
+ * buttons.
+ */
+ public CheckButtonPanel(String[] buttonList) {
+ super(buttonList);
+ }
+
+ /**
+ * Overridden to set vertical-center alignment and zero vgap.
+ */
+ protected void initLayout() {
+ super.initLayout();
+ buttonPanelLayout.setAlignment(BetterFlowLayout.CENTER_VERTICAL);
+ buttonPanelLayout.setVgap(0);
+ }
+
+ /**
+ * Overridden to return a JRadioButton.
+ *
+ * @param aLabel The label for the component that will be created.
+ * @return The newly created component.
+ */
+ protected Component createComponentWithLabel(String aLabel) {
+ String buttonLabel = aLabel;
+ JCheckBox newButton = new JCheckBox();
+ newButton.setName(aLabel);
+ newButton.setText(buttonLabel);
+ newButton.setActionCommand(aLabel);
+ newButton.addActionListener(this);
+
+ // reduce insets per java l&f guidelines (was 4 on each side)
+ newButton.setBorder(new EmptyBorder(1, 4, 1, 4));
+
+ return newButton;
+ }
+
+ /**
+ * Sets the value of the button whose name matches the given text value.
+ *
+ * @param aName A String matching the name of one of the buttons. If null,
+ * empty, or not matching, nothing happens.
+ * @param aValue A value to set the button.
+ */
+ public void setValue(String aName, boolean aValue) {
+ if (aName != null) {
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if (c instanceof AbstractButton) {
+ if (c.getName().equals(aName)) {
+ ((AbstractButton) c).setSelected(aValue);
+ c.repaint();
+ return;
+ }
+ }
+ }
+ }
+ // null, empty, or not matching - exit.
+ System.out.println("CheckButtonPanel.setValue: not found: " + aName);
+ }
+
+ /**
+ * Sets the state of the specified buttons to the specified value.
+ *
+ * @param aLabelArray An Array of Strings listing the buttons to be set.
+ * @param aValue The value to which the specified buttons will be set.
+ */
+ public void setValues(String[] aLabelArray, boolean aValue) {
+ if (aLabelArray != null) {
+ for (int i = 0; i < aLabelArray.length; i++) {
+ setValue(aLabelArray[i], aValue);
+ }
+ }
+ }
+
+ /**
+ * Convenience method to set all checkboxes on the panel.
+ *
+ * @param aValue The value to which all checkboxes on the panel will be set.
+ */
+ public void setAllValues(boolean aValue) {
+ setValues(getLabels(), aValue);
+ }
+
+ /**
+ * Convenience method to check all boxes on the panel.
+ */
+ public void checkAll() {
+ setAllValues(true);
+ }
+
+ /**
+ * Convenience method to clear all boxes on the panel.
+ */
+ public void clearAll() {
+ setAllValues(false);
+ }
+
+ /**
+ * A convenience method to set only those buttons on the entire panel that
+ * should be checked. Buttons not in the list are unchecked.
+ *
+ * @param aLabelArray An Array of Strings listing the buttons to be set.
+ */
+ public void setCheckedValues(String[] aLabelArray) {
+ setAllValues(false);
+ setValues(aLabelArray, true);
+ }
+
+ /**
+ * Gets the labels of all checkboxes that are checked.
+ *
+ * @return A List of Strings containing the labels of the boxes that are
+ * checked.
+ */
+ public List getCheckedValueList() {
+ Vector v = new Vector();
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if (c instanceof AbstractButton) {
+ if (((AbstractButton) c).isSelected()) {
+ v.addElement(c.getName());
+ }
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Gets the labels of all checkboxes that are checked.
+ *
+ * @return A String Array containing the labels of the boxes that are checked.
+ */
+ public String[] getCheckedValues() {
+ List v = getCheckedValueList();
+ String[] result = new String[v.size()];
+ for (int i = 0; i < v.size(); i++) {
+ result[i] = (String) v.get(i);
+ }
+ return result;
+ }
+
+ /**
+ * Gets the value of the specified button.
+ *
+ * @param aName A String matching the name of one of the buttons.
+ * @return True if the button is checked, False if it is not checked. NOTE: If
+ * the button is not found in the list, False is returned.
+ */
+ public boolean getValue(String aName) {
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if ((c instanceof AbstractButton) && (((AbstractButton) c).isSelected())) {
+ if (((AbstractButton) c).getText().equals(aName)) {
+ return ((AbstractButton) c).isSelected();
+ }
+ }
+ }
+ return false;
+ }
+
+ // for testing
+
+ public static void main(String[] argv) {
+ try {
+ javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception exc) {
+
+ }
+
+ javax.swing.JFrame dialog = new javax.swing.JFrame();
+ java.awt.BorderLayout bl = new java.awt.BorderLayout(20, 20);
+
+ CheckButtonPanel panel = new CheckButtonPanel(new String[] { "One", "Two", "Three" });
+
+ dialog.getContentPane().setLayout(bl);
+ dialog.getContentPane().add(panel, java.awt.BorderLayout.CENTER);
+ dialog.setLocation(50, 50);
+ // dialog.setSize( 450, 150 );
+
+ panel.setAlignment(BetterFlowLayout.CENTER_VERTICAL);
+ panel.getButton("One").setEnabled(false);
+ panel.setValues(new String[] { "One" }, true);
+ panel.setValue("Three", true);
// panel.setCheckedValues( new String[] { "Two" } );
- String[] values = panel.getCheckedValues();
- for ( int i = 0; i < values.length; i++ )
- {
- System.out.println( values[i] );
- }
+ String[] values = panel.getCheckedValues();
+ for (int i = 0; i < values.length; i++) {
+ System.out.println(values[i]);
+ }
- dialog.pack();
- dialog.setVisible( true );
+ dialog.pack();
+ dialog.setVisible(true);
- }
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellEditor.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellEditor.java
index a0a14ac..10feef7 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellEditor.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellEditor.java
@@ -29,56 +29,42 @@ import javax.swing.JCheckBox;
import javax.swing.JTable;
/**
-* A TableCellEditor that edits colors - it launches a color dialog when clicked.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * A TableCellEditor that edits colors - it launches a color dialog when
+ * clicked.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
class ColorCellEditor extends DefaultCellEditor {
- Color currentColor = null;
-
- public ColorCellEditor(JButton b)
- {
- super(new JCheckBox()); // unfortunately, the constructor
- // expects a check box, combo box,
- // or text field.
- editorComponent = b;
- setClickCountToStart(1); // this is usually 1 or 2.
-
- // must do this so that editing stops when appropriate.
- b.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- fireEditingStopped();
- }
- }
- );
- }
-
- protected void fireEditingStopped()
- {
- super.fireEditingStopped();
- }
-
- public Object getCellEditorValue()
- {
- return currentColor;
- }
-
- public Component getTableCellEditorComponent(JTable table,
- Object value,
- boolean isSelected,
- int row,
- int column)
- {
- ((JButton)editorComponent).setText(value.toString());
- currentColor = (Color)value;
- return editorComponent;
- }
+ Color currentColor = null;
+
+ public ColorCellEditor(JButton b) {
+ super(new JCheckBox()); // unfortunately, the constructor
+ // expects a check box, combo box,
+ // or text field.
+ editorComponent = b;
+ setClickCountToStart(1); // this is usually 1 or 2.
+
+ // must do this so that editing stops when appropriate.
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ fireEditingStopped();
+ }
+ });
+ }
+
+ protected void fireEditingStopped() {
+ super.fireEditingStopped();
+ }
+
+ public Object getCellEditorValue() {
+ return currentColor;
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+ ((JButton) editorComponent).setText(value.toString());
+ currentColor = (Color) value;
+ return editorComponent;
+ }
}
-
-
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellRenderer.java
index 0552183..2fc97bb 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ColorCellRenderer.java
@@ -28,54 +28,39 @@ import javax.swing.border.Border;
import javax.swing.table.TableCellRenderer;
/**
-* A TableCellRenderer that renders colors.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * A TableCellRenderer that renders colors.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class ColorCellRenderer extends JLabel implements TableCellRenderer {
- Border unselectedBorder = null;
- Border selectedBorder = null;
- boolean isBordered = true;
+ Border unselectedBorder = null;
+ Border selectedBorder = null;
+ boolean isBordered = true;
- public ColorCellRenderer(boolean isBordered)
- {
- super();
- this.isBordered = isBordered;
- setOpaque(true); // must do this for background to show up.
- }
+ public ColorCellRenderer(boolean isBordered) {
+ super();
+ this.isBordered = isBordered;
+ setOpaque(true); // must do this for background to show up.
+ }
- public Component getTableCellRendererComponent(
- JTable table, Object color,
- boolean isSelected, boolean hasFocus,
- int row, int column)
- {
- setBackground((Color)color);
- if (isBordered)
- {
- if (isSelected)
- {
- if (selectedBorder == null)
- {
- selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
- table.getSelectionBackground());
- }
- setBorder(selectedBorder);
- }
- else
- {
- if (unselectedBorder == null)
- {
- unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
- table.getBackground());
- }
- setBorder(unselectedBorder);
- }
- }
- return this;
- }
+ public Component getTableCellRendererComponent(JTable table, Object color, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ setBackground((Color) color);
+ if (isBordered) {
+ if (isSelected) {
+ if (selectedBorder == null) {
+ selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5, table.getSelectionBackground());
+ }
+ setBorder(selectedBorder);
+ } else {
+ if (unselectedBorder == null) {
+ unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5, table.getBackground());
+ }
+ setBorder(unselectedBorder);
+ }
+ }
+ return this;
+ }
}
-
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ComboBoxCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ComboBoxCellRenderer.java
index 2bf8dd6..67cb726 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ComboBoxCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ComboBoxCellRenderer.java
@@ -26,32 +26,24 @@ import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
/**
-* A TableCellRenderer that paints a JComboBox. Useful if
-* you want to visibly display the JComboBox before the
-* user clicks on the cell.
-*
-* @author bsafa@intersectsoft.com
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * A TableCellRenderer that paints a JComboBox. Useful if you want to visibly
+ * display the JComboBox before the user clicks on the cell.
+ *
+ * @author bsafa@intersectsoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class ComboBoxCellRenderer extends JComboBox implements TableCellRenderer {
- public ComboBoxCellRenderer()
- {
- super();
- setOpaque(true);
- }
-
- public Component getTableCellRendererComponent(
- JTable table, Object value,
- boolean isSelected, boolean hasFocus,
- int row, int column)
- {
- setBackground(Color.white);
- setSelectedItem(value);
- return this;
- }
+ public ComboBoxCellRenderer() {
+ super();
+ setOpaque(true);
+ }
+
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ setBackground(Color.white);
+ setSelectedItem(value);
+ return this;
+ }
}
-
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/DateTextField.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/DateTextField.java
index 18ed035..8a3b08c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/DateTextField.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/DateTextField.java
@@ -30,601 +30,507 @@ import java.util.Vector;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
-
-/**
-* DateTextField is a "smart" text field that restricts the user's input. The
-* input is restructed to a string representing a date format.
-*
-* @author rob@straylight.princeton.com
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class DateTextField extends JTextField
-{
-
-/*******************************
-* CONSTANTS
-*******************************/
-
-/**
-* Use the current date for this text field.
-*/
- public static final int CURRENT_DATE = 0;
-
/**
-* Use blanks for this text field.
-*/
- public static final int BLANKS = 1;
-
-/**
-* Use underscores for this text field.
-*/
- public static final int UNDERSCORES = 2;
-
-/**
-* Use just a 4-digit year for this text field.
-*/
- public static final int YEAR = 3;
-
- private static final int BACKSPACE = 8;
- private static final int DELETE = 127;
- private static final int PASTE = 22; // Ctl-V
- private static final int CUT = 24; // Ctl-X
-
-
-/*******************************
-* DATA MEMEBERS
-*******************************/
- private int defaultType = CURRENT_DATE;
-
- private boolean warningMessageActive = false;
-
-
-/*******************************
-* PUBLIC METHODS
-*******************************/
-
-/**
-* Default Constructor.
-*/
- public DateTextField()
- {
- this(1, 1, 1999, 0);
-
- Calendar rightNow = Calendar.getInstance();
-
- super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1,
- rightNow.get(Calendar.DATE),
- rightNow.get(Calendar.YEAR)));
- }
-
-/**
-* Constructor.
-* @param month Number of the month, January being 1.
-* @param data The day of the month.
-* @param year The year.
-*/
- public DateTextField(int month, int date, int year)
- {
- this(month, date, year, 0);
- }
-
-/**
-* Constructor.
-* @param columns Width of the text field (in characters).
-*/
- public DateTextField(int columns)
- {
- this(1, 1, 1998, columns);
-
- Calendar rightNow = Calendar.getInstance();
-
- super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1,
- rightNow.get(Calendar.DATE),
- rightNow.get(Calendar.YEAR)));
- }
-
-/**
-* Constructor.
-* @param month Number of the month, January being 1.
-* @param data The day of the month.
-* @param year The year.
-* @param columns Width of the text field (in characters).
-*/
- public DateTextField(int month, int date, int year, int columns)
- {
- super("", columns);
-
- super.setText(createDateString(month, date, year));
-
- this.addFocusListener(new FocusAdapter()
- {
- public void focusLost(FocusEvent e)
- {
- if (!(e.isTemporary()))
- {
- validateDateString(e);
- }
- }
- });
- }
-
-/**
-* Sets the date type to display when the user has not entered any date yet.
-* Default is the current date.
-* @see #CURRENT_DATE
-* @see #BLANKS
-* @see #UNDERSCORES
-* @param newDefaultType The type of date to display when there is no date data.
-*/
- public void setDefaultType(int newDefaultType)
- {
- if (newDefaultType == BLANKS)
- {
- defaultType = BLANKS;
- super.setText(" / / ");
- }
- else if (newDefaultType == UNDERSCORES)
- {
- defaultType = UNDERSCORES;
- super.setText("__/__/____");
- }
- else if (newDefaultType == YEAR)
- {
- defaultType = YEAR;
- super.setText("0000");
- }
- else
- {
- defaultType = CURRENT_DATE;
-
- Calendar rightNow = Calendar.getInstance();
-
- super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1,
- rightNow.get(Calendar.DATE),
- rightNow.get(Calendar.YEAR)));
- }
- }
-
-/**
-* Returns the type of date to display when there is no user input.
-* @see #CURRENT_DATE
-* @see #BLANKS
-* @see #UNDERSCORES
-* @return The type of date to display when there is no date to display.
-*/
- public int getDefaultType()
- {
- return defaultType;
- }
-
-/**
-* Sets the text field to the string representation of the specified date.
-* @param aDate The date to set the text field to.
-*/
- public void setDate(Date aDate)
- {
- Calendar aCalendar = Calendar.getInstance();
-
- aCalendar.setTime(aDate);
-
- super.setText(createDateString(aCalendar.get(Calendar.MONTH) + 1,
- aCalendar.get(Calendar.DATE),
- aCalendar.get(Calendar.YEAR)));
- }
-
-/**
-* Sets the text field directly from a Date object.
-* @param aDate The date to set the text field to.
-*/
- public void setText( Date aDate )
- {
- setDate( aDate );
- }
-
-/**
-* Sets the text field to the date specified in the string. This is overridden
-* from the parent class to insure a valid date is inputted. The format of the
-* date expected is the type of date format this text field is currently set to.
-* @param aString A string representing a date in this text field current format.
-*/
- public void setText( String aString )
- {
- Date testDate = null;
-
- if ( aString != null )
- {
- ParsePosition position = new ParsePosition( 0 );
-
- if ( defaultType == YEAR )
- {
- SimpleDateFormat yearFormatter = new SimpleDateFormat( "yyyy" );
- testDate = yearFormatter.parse( aString, position );
- }
- else
- {
- SimpleDateFormat fullDateFormatter = new SimpleDateFormat( "MM/dd/yyyy" );
- testDate = fullDateFormatter.parse( aString, position );
- }
- }
-
- // The string is not a valid date, use default value for date then.
- if ( testDate == null )
- {
- Calendar aCalendar = Calendar.getInstance();
-
- testDate = aCalendar.getTime();
- }
-
- setDate( testDate );
- }
-
-/**
-* Returns the date as represented by the date string in the text field.
-* @return The date in the text field.
-*/
- public Date getDate() throws NumberFormatException
- {
- Calendar aCalendar = Calendar.getInstance();
- int year = 1980;
- int month = 0;
- int date = 1;
- int[] tempArray = {1,3,5,7,8,10,12};
- Vector monthsWith31Days = new Vector(7);
-
- for (int i = 0; i < tempArray.length; ++i)
- {
- monthsWith31Days.addElement(new Integer(tempArray[i]));
- }
-
- aCalendar.set(year, month, date, 12, 0, 0);
-
- try
- {
- String dateString = getText();
- NumberFormatException nfException = new NumberFormatException(new String("Invalid Date String: " + dateString));
-
- if (defaultType == YEAR)
- {
- year = Integer.parseInt(dateString);
-
- aCalendar.set(year, 0, 1, 12, 0, 0);
-
- return aCalendar.getTime();
- }
-
- month = Integer.parseInt(dateString.substring(0, 2).trim());
- date = Integer.parseInt(dateString.substring(3, 5).trim());
- year = Integer.parseInt(dateString.substring(6).trim());
-
- if ((month < 1) || (month > 12))
- {
- throw nfException;
- }
-
- if ((date < 1) || (date > 31))
- {
- throw nfException;
- }
-
- if ((date == 31) && (!(monthsWith31Days.contains(new Integer(month)))))
- {
- throw nfException;
- }
-
- if ((date == 30) && (month == 2))
- {
- throw nfException;
- }
-
- if ((date == 29) && (month == 2))
- {
- if ((year % 100) == 0)
- {
- if ((year % 400) != 0)
- {
- throw nfException;
- }
- }
- else
- {
- if ((year % 4) != 0)
- {
- throw nfException;
- }
- }
- }
- }
- catch (IndexOutOfBoundsException ioobe)
- {
- NumberFormatException nfException = new NumberFormatException(new String("Invalid Date String: " + getText()));
- throw nfException;
- }
- catch (NumberFormatException nfe)
- {
- NumberFormatException nfException = new NumberFormatException(new String("Invalid Date String: " + getText()));
- throw nfException;
- }
-
- aCalendar.set(year, (month - 1), date, 12, 0, 0);
-
- return aCalendar.getTime();
- }
-
- public void processKeyEvent(KeyEvent e)
- {
- String currentString = "";
- String testString = "";
- char newChar = e.getKeyChar();
- int currentLength = 0;
- int currentCaretPosition = 0;
- int selectionStart = 0;
- int selectionEnd = 0;
- int modifierPosition = 0;
- int modifierDirection = 1;
- char modifierCharacter;
- boolean backspace = false;
- boolean delete = false;
- boolean paste = false;
- boolean cut = false;
- boolean keyPressed = false;
-
- backspace = (newChar == BACKSPACE);
- delete = (newChar == DELETE);
- paste = (newChar == PASTE);
- cut = (newChar == CUT);
-
- keyPressed = (e.paramString().startsWith("KEY_PRESSED"));
-
- if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste) || (cut))) // A "key-typed" event
- {
- if (isValidCharacter(newChar))
- {
- if ((isPrintableCharacter(newChar)) || (backspace) || (delete))
- {
- // Both the key "pressed" and key "released" events get passed
- // in here for the delete and backspace key. Only processes
- // these keys if the event is key "pressed".
- if (((backspace) || (delete)) && (!(keyPressed)))
- {
- // Don't do anything, pass through to consumption.
- }
- else
- {
- // Analyze the current contents of the field
- currentString = getText();
- currentLength = currentString.length();
-
- char[] tempText = new char[currentLength];
-
- currentCaretPosition = getCaretPosition();
-
- selectionStart = getSelectionStart();
- selectionEnd = getSelectionEnd();
-
- // if a range is selected, then get rid of it and place the caret
- // at the begginning of the range and continue processing.
- if (selectionStart != selectionEnd)
- {
- selectionEnd = selectionStart;
- setSelectionEnd(selectionEnd);
-
- currentCaretPosition = selectionStart;
- setCaretPosition(currentCaretPosition);
- }
-
- if (currentCaretPosition <= currentLength)
- {
- // a number of delete or backspace was pressed, delete and
- // backspace deletes a number and places a "space" there
-
- // if caret at start of string and the backspace pressed OR
- // caret at end of string and delete or number pressed THEN
- // don't do anything, otherwise process key stroke
- if (((currentCaretPosition == 0) && (backspace)) ||
- ((currentCaretPosition == currentLength) && (!(backspace))))
- {
- // Don't do any processing.
- }
- else
- {
- modifierPosition = currentCaretPosition;
- if (backspace)
- {
- modifierDirection = -1;
- modifierPosition += modifierDirection;
- }
-
- // Overwrite the current position with the new character
- // inputted or overwrite using a space or underscore if
- // the backspace or delete key was pressed.
- if (defaultType != YEAR)
- {
- modifierCharacter =
- ((delete)||(backspace)) ?
- ((defaultType == UNDERSCORES) ? '_' : ' ') :
- newChar;
- }
- else
- {
- // We are dealing with a 4-digit year. Overwrite
- // with new character or "0" if delete or backspace
- // was pressed.
- modifierCharacter = ((delete)||(backspace)) ? ('0') : newChar;
- }
-
- if (currentString.charAt(modifierPosition) == '/')
- {
- modifierPosition += modifierDirection;
- }
-
- for (int i = 0; i < currentLength; ++i)
- {
- if (i == modifierPosition)
- {
- tempText[i] = modifierCharacter;
- }
- else
- {
- tempText[i] = currentString.charAt(i);
- }
- }
-
- testString = new String(tempText);
- if (isValidString(testString))
- {
- super.setText(testString);
- if (backspace)
- {
- setCaretPosition(modifierPosition);
- }
- else
- {
- setCaretPosition(modifierPosition + 1);
- }
- }
- }
- }
- }
-
- e.consume();
- }
- else if ((cut) || (paste))
- {
- e.consume();
- }
- // else its a non-printable character, let it pass through
- }
- else
- {
- e.consume();
- }
- }
-
- super.processKeyEvent(e);
- }
-
- private boolean isValidCharacter(char aChar)
- {
- if (((aChar >= '!') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~')))
- {
- return false;
- }
- return true;
- }
-
- private boolean isPrintableCharacter(char inputChar)
- {
- if ((inputChar >= ' ') && (inputChar <= '~'))
- {
- return true;
- }
- return false;
- }
-
- private boolean isValidDate(int month, int date, int year)
- {
- if ((month < 1) || (month > 12))
- {
- return false;
- }
-
- if ((date < 1) || (date > 31))
- {
- return false;
- }
-
- if ((year < 0) || (year > 9999))
- {
- return false;
- }
-
- return true;
- }
-
- private boolean isValidString(String aString)
- {
- return true;
- }
-
- private String createDateString(int month, int date, int year)
- {
- String dateString = "";
-
- if (isValidDate(month, date, year))
- {
- if (defaultType != YEAR)
- {
- if (month < 10)
- {
- dateString = "0";
- }
-
- dateString += String.valueOf(month);
- dateString += "/";
-
- if (date < 10)
- {
- dateString += "0";
- }
-
- dateString += String.valueOf(date);
- dateString += "/";
- }
-
- if (year < 1000)
- {
- dateString += "0";
- if (year < 100)
- {
- dateString += "0";
- if (year < 10)
- {
- dateString += "0";
- }
- }
- }
-
- dateString += String.valueOf(year);
- }
- else
- {
- if (defaultType == YEAR)
- {
- dateString = "1999";
- }
- else
- {
- dateString = "01/01/1999";
- }
- }
-
- return dateString;
- }
-
- private void validateDateString(FocusEvent e)
- {
- if (!(warningMessageActive))
- {
- try
- {
- getDate();
- }
- catch (NumberFormatException nfe)
- {
- System.out.println("Invalid Date String!!!");
- warningMessageActive = true;
- JOptionPane.showMessageDialog(this, "Invald Date: " + getText(), "Warning", JOptionPane.WARNING_MESSAGE);
- warningMessageActive = false;
- if (defaultType == YEAR)
- {
- super.setText("1999");
- }
- else
- {
- super.setText("01/01/1999");
- }
- }
- }
- }
+ * DateTextField is a "smart" text field that restricts the user's input. The
+ * input is restructed to a string representing a date format.
+ *
+ * @author rob@straylight.princeton.com
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class DateTextField extends JTextField {
+
+ /*******************************
+ * CONSTANTS
+ *******************************/
+
+ /**
+ * Use the current date for this text field.
+ */
+ public static final int CURRENT_DATE = 0;
+
+ /**
+ * Use blanks for this text field.
+ */
+ public static final int BLANKS = 1;
+
+ /**
+ * Use underscores for this text field.
+ */
+ public static final int UNDERSCORES = 2;
+
+ /**
+ * Use just a 4-digit year for this text field.
+ */
+ public static final int YEAR = 3;
+
+ private static final int BACKSPACE = 8;
+ private static final int DELETE = 127;
+ private static final int PASTE = 22; // Ctl-V
+ private static final int CUT = 24; // Ctl-X
+
+ /*******************************
+ * DATA MEMEBERS
+ *******************************/
+ private int defaultType = CURRENT_DATE;
+
+ private boolean warningMessageActive = false;
+
+ /*******************************
+ * PUBLIC METHODS
+ *******************************/
+
+ /**
+ * Default Constructor.
+ */
+ public DateTextField() {
+ this(1, 1, 1999, 0);
+
+ Calendar rightNow = Calendar.getInstance();
+
+ super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1, rightNow.get(Calendar.DATE),
+ rightNow.get(Calendar.YEAR)));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param month Number of the month, January being 1.
+ * @param data The day of the month.
+ * @param year The year.
+ */
+ public DateTextField(int month, int date, int year) {
+ this(month, date, year, 0);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param columns Width of the text field (in characters).
+ */
+ public DateTextField(int columns) {
+ this(1, 1, 1998, columns);
+
+ Calendar rightNow = Calendar.getInstance();
+
+ super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1, rightNow.get(Calendar.DATE),
+ rightNow.get(Calendar.YEAR)));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param month Number of the month, January being 1.
+ * @param data The day of the month.
+ * @param year The year.
+ * @param columns Width of the text field (in characters).
+ */
+ public DateTextField(int month, int date, int year, int columns) {
+ super("", columns);
+
+ super.setText(createDateString(month, date, year));
+
+ this.addFocusListener(new FocusAdapter() {
+ public void focusLost(FocusEvent e) {
+ if (!(e.isTemporary())) {
+ validateDateString(e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets the date type to display when the user has not entered any date yet.
+ * Default is the current date.
+ *
+ * @see #CURRENT_DATE
+ * @see #BLANKS
+ * @see #UNDERSCORES
+ * @param newDefaultType The type of date to display when there is no date data.
+ */
+ public void setDefaultType(int newDefaultType) {
+ if (newDefaultType == BLANKS) {
+ defaultType = BLANKS;
+ super.setText(" / / ");
+ } else if (newDefaultType == UNDERSCORES) {
+ defaultType = UNDERSCORES;
+ super.setText("__/__/____");
+ } else if (newDefaultType == YEAR) {
+ defaultType = YEAR;
+ super.setText("0000");
+ } else {
+ defaultType = CURRENT_DATE;
+
+ Calendar rightNow = Calendar.getInstance();
+
+ super.setText(createDateString(rightNow.get(Calendar.MONTH) + 1, rightNow.get(Calendar.DATE),
+ rightNow.get(Calendar.YEAR)));
+ }
+ }
+
+ /**
+ * Returns the type of date to display when there is no user input.
+ *
+ * @see #CURRENT_DATE
+ * @see #BLANKS
+ * @see #UNDERSCORES
+ * @return The type of date to display when there is no date to display.
+ */
+ public int getDefaultType() {
+ return defaultType;
+ }
+
+ /**
+ * Sets the text field to the string representation of the specified date.
+ *
+ * @param aDate The date to set the text field to.
+ */
+ public void setDate(Date aDate) {
+ Calendar aCalendar = Calendar.getInstance();
+
+ aCalendar.setTime(aDate);
+
+ super.setText(createDateString(aCalendar.get(Calendar.MONTH) + 1, aCalendar.get(Calendar.DATE),
+ aCalendar.get(Calendar.YEAR)));
+ }
+
+ /**
+ * Sets the text field directly from a Date object.
+ *
+ * @param aDate The date to set the text field to.
+ */
+ public void setText(Date aDate) {
+ setDate(aDate);
+ }
+
+ /**
+ * Sets the text field to the date specified in the string. This is overridden
+ * from the parent class to insure a valid date is inputted. The format of the
+ * date expected is the type of date format this text field is currently set to.
+ *
+ * @param aString A string representing a date in this text field current
+ * format.
+ */
+ public void setText(String aString) {
+ Date testDate = null;
+
+ if (aString != null) {
+ ParsePosition position = new ParsePosition(0);
+
+ if (defaultType == YEAR) {
+ SimpleDateFormat yearFormatter = new SimpleDateFormat("yyyy");
+ testDate = yearFormatter.parse(aString, position);
+ } else {
+ SimpleDateFormat fullDateFormatter = new SimpleDateFormat("MM/dd/yyyy");
+ testDate = fullDateFormatter.parse(aString, position);
+ }
+ }
+
+ // The string is not a valid date, use default value for date then.
+ if (testDate == null) {
+ Calendar aCalendar = Calendar.getInstance();
+
+ testDate = aCalendar.getTime();
+ }
+
+ setDate(testDate);
+ }
+
+ /**
+ * Returns the date as represented by the date string in the text field.
+ *
+ * @return The date in the text field.
+ */
+ public Date getDate() throws NumberFormatException {
+ Calendar aCalendar = Calendar.getInstance();
+ int year = 1980;
+ int month = 0;
+ int date = 1;
+ int[] tempArray = { 1, 3, 5, 7, 8, 10, 12 };
+ Vector monthsWith31Days = new Vector(7);
+
+ for (int i = 0; i < tempArray.length; ++i) {
+ monthsWith31Days.addElement(new Integer(tempArray[i]));
+ }
+
+ aCalendar.set(year, month, date, 12, 0, 0);
+
+ try {
+ String dateString = getText();
+ NumberFormatException nfException = new NumberFormatException(
+ new String("Invalid Date String: " + dateString));
+
+ if (defaultType == YEAR) {
+ year = Integer.parseInt(dateString);
+
+ aCalendar.set(year, 0, 1, 12, 0, 0);
+
+ return aCalendar.getTime();
+ }
+
+ month = Integer.parseInt(dateString.substring(0, 2).trim());
+ date = Integer.parseInt(dateString.substring(3, 5).trim());
+ year = Integer.parseInt(dateString.substring(6).trim());
+
+ if ((month < 1) || (month > 12)) {
+ throw nfException;
+ }
+
+ if ((date < 1) || (date > 31)) {
+ throw nfException;
+ }
+
+ if ((date == 31) && (!(monthsWith31Days.contains(new Integer(month))))) {
+ throw nfException;
+ }
+
+ if ((date == 30) && (month == 2)) {
+ throw nfException;
+ }
+
+ if ((date == 29) && (month == 2)) {
+ if ((year % 100) == 0) {
+ if ((year % 400) != 0) {
+ throw nfException;
+ }
+ } else {
+ if ((year % 4) != 0) {
+ throw nfException;
+ }
+ }
+ }
+ } catch (IndexOutOfBoundsException ioobe) {
+ NumberFormatException nfException = new NumberFormatException(
+ new String("Invalid Date String: " + getText()));
+ throw nfException;
+ } catch (NumberFormatException nfe) {
+ NumberFormatException nfException = new NumberFormatException(
+ new String("Invalid Date String: " + getText()));
+ throw nfException;
+ }
+
+ aCalendar.set(year, (month - 1), date, 12, 0, 0);
+
+ return aCalendar.getTime();
+ }
+
+ public void processKeyEvent(KeyEvent e) {
+ String currentString = "";
+ String testString = "";
+ char newChar = e.getKeyChar();
+ int currentLength = 0;
+ int currentCaretPosition = 0;
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ int modifierPosition = 0;
+ int modifierDirection = 1;
+ char modifierCharacter;
+ boolean backspace = false;
+ boolean delete = false;
+ boolean paste = false;
+ boolean cut = false;
+ boolean keyPressed = false;
+
+ backspace = (newChar == BACKSPACE);
+ delete = (newChar == DELETE);
+ paste = (newChar == PASTE);
+ cut = (newChar == CUT);
+
+ keyPressed = (e.paramString().startsWith("KEY_PRESSED"));
+
+ if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste) || (cut))) // A "key-typed"
+ // event
+ {
+ if (isValidCharacter(newChar)) {
+ if ((isPrintableCharacter(newChar)) || (backspace) || (delete)) {
+ // Both the key "pressed" and key "released" events get passed
+ // in here for the delete and backspace key. Only processes
+ // these keys if the event is key "pressed".
+ if (((backspace) || (delete)) && (!(keyPressed))) {
+ // Don't do anything, pass through to consumption.
+ } else {
+ // Analyze the current contents of the field
+ currentString = getText();
+ currentLength = currentString.length();
+
+ char[] tempText = new char[currentLength];
+
+ currentCaretPosition = getCaretPosition();
+
+ selectionStart = getSelectionStart();
+ selectionEnd = getSelectionEnd();
+
+ // if a range is selected, then get rid of it and place the caret
+ // at the begginning of the range and continue processing.
+ if (selectionStart != selectionEnd) {
+ selectionEnd = selectionStart;
+ setSelectionEnd(selectionEnd);
+
+ currentCaretPosition = selectionStart;
+ setCaretPosition(currentCaretPosition);
+ }
+
+ if (currentCaretPosition <= currentLength) {
+ // a number of delete or backspace was pressed, delete and
+ // backspace deletes a number and places a "space" there
+
+ // if caret at start of string and the backspace pressed OR
+ // caret at end of string and delete or number pressed THEN
+ // don't do anything, otherwise process key stroke
+ if (((currentCaretPosition == 0) && (backspace))
+ || ((currentCaretPosition == currentLength) && (!(backspace)))) {
+ // Don't do any processing.
+ } else {
+ modifierPosition = currentCaretPosition;
+ if (backspace) {
+ modifierDirection = -1;
+ modifierPosition += modifierDirection;
+ }
+
+ // Overwrite the current position with the new character
+ // inputted or overwrite using a space or underscore if
+ // the backspace or delete key was pressed.
+ if (defaultType != YEAR) {
+ modifierCharacter = ((delete) || (backspace))
+ ? ((defaultType == UNDERSCORES) ? '_' : ' ')
+ : newChar;
+ } else {
+ // We are dealing with a 4-digit year. Overwrite
+ // with new character or "0" if delete or backspace
+ // was pressed.
+ modifierCharacter = ((delete) || (backspace)) ? ('0') : newChar;
+ }
+
+ if (currentString.charAt(modifierPosition) == '/') {
+ modifierPosition += modifierDirection;
+ }
+
+ for (int i = 0; i < currentLength; ++i) {
+ if (i == modifierPosition) {
+ tempText[i] = modifierCharacter;
+ } else {
+ tempText[i] = currentString.charAt(i);
+ }
+ }
+
+ testString = new String(tempText);
+ if (isValidString(testString)) {
+ super.setText(testString);
+ if (backspace) {
+ setCaretPosition(modifierPosition);
+ } else {
+ setCaretPosition(modifierPosition + 1);
+ }
+ }
+ }
+ }
+ }
+
+ e.consume();
+ } else if ((cut) || (paste)) {
+ e.consume();
+ }
+ // else its a non-printable character, let it pass through
+ } else {
+ e.consume();
+ }
+ }
+
+ super.processKeyEvent(e);
+ }
+
+ private boolean isValidCharacter(char aChar) {
+ if (((aChar >= '!') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~'))) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isPrintableCharacter(char inputChar) {
+ if ((inputChar >= ' ') && (inputChar <= '~')) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isValidDate(int month, int date, int year) {
+ if ((month < 1) || (month > 12)) {
+ return false;
+ }
+
+ if ((date < 1) || (date > 31)) {
+ return false;
+ }
+
+ if ((year < 0) || (year > 9999)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean isValidString(String aString) {
+ return true;
+ }
+
+ private String createDateString(int month, int date, int year) {
+ String dateString = "";
+
+ if (isValidDate(month, date, year)) {
+ if (defaultType != YEAR) {
+ if (month < 10) {
+ dateString = "0";
+ }
+
+ dateString += String.valueOf(month);
+ dateString += "/";
+
+ if (date < 10) {
+ dateString += "0";
+ }
+
+ dateString += String.valueOf(date);
+ dateString += "/";
+ }
+
+ if (year < 1000) {
+ dateString += "0";
+ if (year < 100) {
+ dateString += "0";
+ if (year < 10) {
+ dateString += "0";
+ }
+ }
+ }
+
+ dateString += String.valueOf(year);
+ } else {
+ if (defaultType == YEAR) {
+ dateString = "1999";
+ } else {
+ dateString = "01/01/1999";
+ }
+ }
+
+ return dateString;
+ }
+
+ private void validateDateString(FocusEvent e) {
+ if (!(warningMessageActive)) {
+ try {
+ getDate();
+ } catch (NumberFormatException nfe) {
+ System.out.println("Invalid Date String!!!");
+ warningMessageActive = true;
+ JOptionPane.showMessageDialog(this, "Invald Date: " + getText(), "Warning",
+ JOptionPane.WARNING_MESSAGE);
+ warningMessageActive = false;
+ if (defaultType == YEAR) {
+ super.setText("1999");
+ } else {
+ super.setText("01/01/1999");
+ }
+ }
+ }
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/FormattedCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/FormattedCellRenderer.java
index b3e2a76..10b1b89 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/FormattedCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/FormattedCellRenderer.java
@@ -27,101 +27,92 @@ import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
/**
-* A cell renderer for dealing with formatted content.
-* Subclasses can specify formats or colors or styles for specific values
-* or locations in the table by overridding getFormatForContext(),
-* getForegroundForContext() and/or getBackgroundForContext().
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class FormattedCellRenderer extends DefaultTableCellRenderer
-{
- protected Format currentFormat, defaultFormat;
- protected Color defaultForeground, defaultBackground;
- protected Font defaultFont;
-
-/**
-* Default constructor with no specified format.
-*/
- public FormattedCellRenderer()
- {
- this( (Format) null );
- }
-
-/**
-* Constructor specifying a format for renderered content.
-*/
- public FormattedCellRenderer( Format aFormat )
- {
- currentFormat = null;
- defaultFormat = aFormat;
- defaultForeground = super.getForeground();
- defaultBackground = super.getForeground();
- }
-
-/**
-* Returns the format currently in use to format cell content.
-* @return The Format that is currently being used.
-*/
- public Format getFormat()
- {
- return defaultFormat;
- }
-
-/**
-* Sets the format to be used to format cell content.
-*/
- public void setFormat( Format aFormat )
- {
- defaultFormat = aFormat;
- }
-
-/**
-* Overrides to retain the default foreground color,
-* much the same as the DefaultCellRenderer does.
-* We have to do this because DefaultCellRenderer's
-* ivars are private.
-*/
- public void setForeground(Color c) {
- super.setForeground(c);
- defaultForeground = c;
- }
-
-/**
-* Overrides to retain the default background color,
-* much the same as the DefaultCellRenderer does.
-* We have to do this because DefaultCellRenderer's
-* ivars are private.
-*/
- public void setBackground(Color c) {
- super.setBackground(c);
- defaultBackground = c;
- }
-
-/**
-* Overrides to retain the default font,
-* much the same as the DefaultCellRenderer does.
-* We have to do this because DefaultCellRenderer's
-* ivars are private.
-*/
- public void setFont(Font f) {
- super.setFont(f);
- defaultFont = f;
- }
-
-/**
-* Overridden to format the value with the appropriate Format. If the
-* value cannot be formatted with the Format, the superclass method is called.
-* @param value An Object to be formatted.
-*/
- protected void setValue(Object value)
- {
- if ( currentFormat != null )
- {
- try
- {
+ * A cell renderer for dealing with formatted content. Subclasses can specify
+ * formats or colors or styles for specific values or locations in the table by
+ * overridding getFormatForContext(), getForegroundForContext() and/or
+ * getBackgroundForContext().
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class FormattedCellRenderer extends DefaultTableCellRenderer {
+ protected Format currentFormat, defaultFormat;
+ protected Color defaultForeground, defaultBackground;
+ protected Font defaultFont;
+
+ /**
+ * Default constructor with no specified format.
+ */
+ public FormattedCellRenderer() {
+ this((Format) null);
+ }
+
+ /**
+ * Constructor specifying a format for renderered content.
+ */
+ public FormattedCellRenderer(Format aFormat) {
+ currentFormat = null;
+ defaultFormat = aFormat;
+ defaultForeground = super.getForeground();
+ defaultBackground = super.getForeground();
+ }
+
+ /**
+ * Returns the format currently in use to format cell content.
+ *
+ * @return The Format that is currently being used.
+ */
+ public Format getFormat() {
+ return defaultFormat;
+ }
+
+ /**
+ * Sets the format to be used to format cell content.
+ */
+ public void setFormat(Format aFormat) {
+ defaultFormat = aFormat;
+ }
+
+ /**
+ * Overrides to retain the default foreground color, much the same as the
+ * DefaultCellRenderer does. We have to do this because DefaultCellRenderer's
+ * ivars are private.
+ */
+ public void setForeground(Color c) {
+ super.setForeground(c);
+ defaultForeground = c;
+ }
+
+ /**
+ * Overrides to retain the default background color, much the same as the
+ * DefaultCellRenderer does. We have to do this because DefaultCellRenderer's
+ * ivars are private.
+ */
+ public void setBackground(Color c) {
+ super.setBackground(c);
+ defaultBackground = c;
+ }
+
+ /**
+ * Overrides to retain the default font, much the same as the
+ * DefaultCellRenderer does. We have to do this because DefaultCellRenderer's
+ * ivars are private.
+ */
+ public void setFont(Font f) {
+ super.setFont(f);
+ defaultFont = f;
+ }
+
+ /**
+ * Overridden to format the value with the appropriate Format. If the value
+ * cannot be formatted with the Format, the superclass method is called.
+ *
+ * @param value An Object to be formatted.
+ */
+ protected void setValue(Object value) {
+ if (currentFormat != null) {
+ try {
// if ( ( value instanceof Number ) && ( value.toString().indexOf( "E" ) != -1 ) )
// {
@@ -132,153 +123,140 @@ public class FormattedCellRenderer extends DefaultTableCellRenderer
// System.out.println( "FormattedCellRenderer.setValue: converted = '" + currentFormat.format( value ) + "'" );
// }
- // WORKAROUND: This works around what may be a rounding bug in DecimalFormat. (PR 256/297)
- currentFormat.format( ZERO );
-
- // DEBUG: code to test for weird one/zero problem (PR 256/297)
- String result = currentFormat.format( value );
-/* above workaround seems to be working
- if ( result.equals( "1" ) )
- {
- System.out.println( "FormattedCellRenderer.setValue: Could be the ONE/ZERO problem!" );
- System.out.println( "FormattedCellRenderer.setValue: format = '" + currentFormat.getClass() + "'" );
- System.out.println( "FormattedCellRenderer.setValue: original value = '" + value + "'" );
- System.out.println( "FormattedCellRenderer.setValue: result = '" + result + "'" );
- }
-*/
- setText( result );
-
+ // WORKAROUND: This works around what may be a rounding bug in DecimalFormat.
+ // (PR 256/297)
+ currentFormat.format(ZERO);
+
+ // DEBUG: code to test for weird one/zero problem (PR 256/297)
+ String result = currentFormat.format(value);
+ /*
+ * above workaround seems to be working if ( result.equals( "1" ) ) {
+ * System.out.println(
+ * "FormattedCellRenderer.setValue: Could be the ONE/ZERO problem!" );
+ * System.out.println( "FormattedCellRenderer.setValue: format = '" +
+ * currentFormat.getClass() + "'" ); System.out.println(
+ * "FormattedCellRenderer.setValue: original value = '" + value + "'" );
+ * System.out.println( "FormattedCellRenderer.setValue: result = '" + result +
+ * "'" ); }
+ */
+ setText(result);
// setText( currentFormat.format( value ) );
- return;
- }
- catch ( IllegalArgumentException exc )
- {
- // fall back on superclass implementation
- }
- }
- super.setValue( value );
- }
-
- // FIXME: remove this when possible
- private static Double ZERO = new Double( 0.0 );
-
-/**
-* Overridden to call context delegate methods.
-*/
- public Component getTableCellRendererComponent(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- Format format;
-
- // allow for context-sensitve formatting
- format = getFormatForContext( table, value, isSelected, hasFocus, row, column );
- if ( format != null )
- {
- currentFormat = format;
- }
- else
- {
- currentFormat = defaultFormat;
- }
-
- Color color;
-
- // allow for context-sensitve foreground color
- color = getForegroundForContext( table, value, isSelected, hasFocus, row, column );
- if ( color != null )
- {
- super.setForeground( color );
- }
- else
- {
- super.setForeground( defaultForeground );
- }
-
- // allow for context-sensitve background color
- color = getBackgroundForContext( table, value, isSelected, hasFocus, row, column );
- if ( color != null )
- {
- super.setBackground( color );
- }
- else
- {
- super.setBackground( defaultBackground );
- }
-
- // have to call this here because super defaults to table's font
- Component result =
- super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
- // NOTE: DefaultTableCellRenderer returns itself.
-
- // allow for context-sensitve font
- Font font = getFontForContext( table, value, isSelected, hasFocus, row, column );
- if ( font != null )
- {
- result.setFont( font );
- }
- else
- {
- result.setFont( defaultFont );
- }
-
- return result;
-
- }
-
-/**
-* Override this method to provide a specific format for the
-* specific cell to be rendered by this component. Any format
-* returned by this method will take precedence of the format
-* specified by setFormat(). <br><br>
-* This default implementation returns null.
-* @return A Format for this cell, or null to rely on the the
-* format specified by setFormat().
-*/
- public Format getFormatForContext(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- return null;
- }
-
-/**
-* Override this method to provide a foreground color for the renderer.
-* Because the table specifies colors for selected cells,
-* these colors will only be used when renderering unselected cells. <br><br>
-* This default implementation returns null.
-* @return A Color for the foreground of the cell, or null to rely on
-* the table's default color scheme.
-*/
- public Color getForegroundForContext(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- return null;
- }
-
-/**
-* Override this method to provide a background color for the renderer.
-* Because the table specifies colors for selected cells,
-* these colors will only be used when renderering unselected cells. <br><br>
-* This default implementation returns null.
-* @return A Color for the background of the cell, or null to rely on
-* the table's default color scheme.
-*/
- public Color getBackgroundForContext(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- return null;
- }
-
-/**
-* Override this method to provide a font for the renderer.<br><br>
-* This default implementation returns null.
-* @return A Font for the cell, or null to rely on the table's default font.
-*/
- public Font getFontForContext(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- return null;
- }
+ return;
+ } catch (IllegalArgumentException exc) {
+ // fall back on superclass implementation
+ }
+ }
+ super.setValue(value);
+ }
+
+ // FIXME: remove this when possible
+ private static Double ZERO = new Double(0.0);
+
+ /**
+ * Overridden to call context delegate methods.
+ */
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ Format format;
+
+ // allow for context-sensitve formatting
+ format = getFormatForContext(table, value, isSelected, hasFocus, row, column);
+ if (format != null) {
+ currentFormat = format;
+ } else {
+ currentFormat = defaultFormat;
+ }
+
+ Color color;
+
+ // allow for context-sensitve foreground color
+ color = getForegroundForContext(table, value, isSelected, hasFocus, row, column);
+ if (color != null) {
+ super.setForeground(color);
+ } else {
+ super.setForeground(defaultForeground);
+ }
+
+ // allow for context-sensitve background color
+ color = getBackgroundForContext(table, value, isSelected, hasFocus, row, column);
+ if (color != null) {
+ super.setBackground(color);
+ } else {
+ super.setBackground(defaultBackground);
+ }
+
+ // have to call this here because super defaults to table's font
+ Component result = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+ // NOTE: DefaultTableCellRenderer returns itself.
+
+ // allow for context-sensitve font
+ Font font = getFontForContext(table, value, isSelected, hasFocus, row, column);
+ if (font != null) {
+ result.setFont(font);
+ } else {
+ result.setFont(defaultFont);
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Override this method to provide a specific format for the specific cell to be
+ * rendered by this component. Any format returned by this method will take
+ * precedence of the format specified by setFormat(). <br>
+ * <br>
+ * This default implementation returns null.
+ *
+ * @return A Format for this cell, or null to rely on the the format specified
+ * by setFormat().
+ */
+ public Format getFormatForContext(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
+ int column) {
+ return null;
+ }
+
+ /**
+ * Override this method to provide a foreground color for the renderer. Because
+ * the table specifies colors for selected cells, these colors will only be used
+ * when renderering unselected cells. <br>
+ * <br>
+ * This default implementation returns null.
+ *
+ * @return A Color for the foreground of the cell, or null to rely on the
+ * table's default color scheme.
+ */
+ public Color getForegroundForContext(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
+ int column) {
+ return null;
+ }
+
+ /**
+ * Override this method to provide a background color for the renderer. Because
+ * the table specifies colors for selected cells, these colors will only be used
+ * when renderering unselected cells. <br>
+ * <br>
+ * This default implementation returns null.
+ *
+ * @return A Color for the background of the cell, or null to rely on the
+ * table's default color scheme.
+ */
+ public Color getBackgroundForContext(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
+ int column) {
+ return null;
+ }
+
+ /**
+ * Override this method to provide a font for the renderer.<br>
+ * <br>
+ * This default implementation returns null.
+ *
+ * @return A Font for the cell, or null to rely on the table's default font.
+ */
+ public Font getFontForContext(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
+ int column) {
+ return null;
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/IconCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/IconCellRenderer.java
index 8320d08..2d9531d 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/IconCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/IconCellRenderer.java
@@ -54,792 +54,654 @@ import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
/**
-* A cell renderer that displays icons in addition to text,
-* and additionally is an editor in case you want to click
-* the icon to trigger some kind of action.
-* You probably should override both getStringForContext and
-* getIconForContext to achieve your desired results.
-* To receive mouse clicks, set the same instance of the
-* renderer as the editor for the same component.<br><br>
-*
-* One notable addition is that this class is an action event
-* broadcaster. ActionEvents are broadcast when the mouse is
-* clicked on the button with an action event containing a
-* user-configurable string that defaults to CLICKED. <br><br>
-*
-* The renderer itself can be used as a JComponent if
-* you need something like a JLabel that allows you to click
-* on the icon. You will want to call setIcon and setText
-* to configure the component since the renderer method would
-* not be called. (If you add an instance of the renderer
-* to a container, you cannnot use the same instance as an
-* editor in a table, tree, or list.)
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class IconCellRenderer extends JPanel
- implements TableCellRenderer, TableCellEditor,
- TreeCellRenderer, TreeCellEditor, ListCellRenderer,
- Runnable, ActionListener, MouseListener
-{
+ * A cell renderer that displays icons in addition to text, and additionally is
+ * an editor in case you want to click the icon to trigger some kind of action.
+ * You probably should override both getStringForContext and getIconForContext
+ * to achieve your desired results. To receive mouse clicks, set the same
+ * instance of the renderer as the editor for the same component.<br>
+ * <br>
+ *
+ * One notable addition is that this class is an action event broadcaster.
+ * ActionEvents are broadcast when the mouse is clicked on the button with an
+ * action event containing a user-configurable string that defaults to CLICKED.
+ * <br>
+ * <br>
+ *
+ * The renderer itself can be used as a JComponent if you need something like a
+ * JLabel that allows you to click on the icon. You will want to call setIcon
+ * and setText to configure the component since the renderer method would not be
+ * called. (If you add an instance of the renderer to a container, you cannnot
+ * use the same instance as an editor in a table, tree, or list.)
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class IconCellRenderer extends JPanel implements TableCellRenderer, TableCellEditor, TreeCellRenderer,
+ TreeCellEditor, ListCellRenderer, Runnable, ActionListener, MouseListener {
public static final String CLICKED = "CLICKED";
-
+
/**
- * The panel that is re-used to render everything.
- * This is returned by getRendererForContext.
- */
- protected JPanel rendererPanel;
+ * The panel that is re-used to render everything. This is returned by
+ * getRendererForContext.
+ */
+ protected JPanel rendererPanel;
protected JLabel rendererLabel;
- protected JButton rendererButton;
+ protected JButton rendererButton;
/**
- * The panel that is used to receive mouse clicks.
- * It must be a different component from rendererPanel.
- * This is returned by getEditorForContext.
- */
- protected JPanel editorPanel;
+ * The panel that is used to receive mouse clicks. It must be a different
+ * component from rendererPanel. This is returned by getEditorForContext.
+ */
+ protected JPanel editorPanel;
protected JLabel editorLabel;
- protected JButton editorButton;
-
+ protected JButton editorButton;
+
private Object lastKnownValue;
- private JComponent lastKnownComponent;
-
+ private JComponent lastKnownComponent;
+
// do as DefaultTableCellRenderer does
private Border noFocusBorder;
private Border treeFocusBorder;
private Color unselectedForeground;
private Color unselectedBackground;
-
+
private Vector actionListeners;
private String actionCommand;
private Vector cellEditorListeners;
-
- private boolean editable;
- private boolean clickable;
-
- /**
- * Default constructor.
- */
- public IconCellRenderer()
- {
- editable = true;
- clickable = true;
-
- noFocusBorder = new EmptyBorder(1, 1, 1, 1);
- treeFocusBorder = new LineBorder(
- UIManager.getColor("Tree.selectionBorderColor") );
- setActionCommand( CLICKED );
-
- rendererPanel = new JPanel();
- rendererPanel.setLayout( new GridBagLayout() );
-
- editorPanel = this;
- editorPanel.setLayout( new GridBagLayout() );
-
- // set up constraints
- GridBagConstraints imageConstraints = new GridBagConstraints();
- imageConstraints.gridx = 0;
- GridBagConstraints labelConstraints = new GridBagConstraints();
- labelConstraints.fill = GridBagConstraints.HORIZONTAL;
- labelConstraints.gridx = 1;
- labelConstraints.weightx = 1.0;
- labelConstraints.ipadx = 1;
- labelConstraints.insets = new Insets( 0, 1, 0, 0 ); // sweat the pixel
-
- // make the editor panel go away when not in use
- // and pass through all mouse events to container
-
- //this is not very useful since editorLabel and editorButton
- //get all of the events
- editorPanel.addMouseListener( this );
-
+
+ private boolean editable;
+ private boolean clickable;
+
+ /**
+ * Default constructor.
+ */
+ public IconCellRenderer() {
+ editable = true;
+ clickable = true;
+
+ noFocusBorder = new EmptyBorder(1, 1, 1, 1);
+ treeFocusBorder = new LineBorder(UIManager.getColor("Tree.selectionBorderColor"));
+ setActionCommand(CLICKED);
+
+ rendererPanel = new JPanel();
+ rendererPanel.setLayout(new GridBagLayout());
+
+ editorPanel = this;
+ editorPanel.setLayout(new GridBagLayout());
+
+ // set up constraints
+ GridBagConstraints imageConstraints = new GridBagConstraints();
+ imageConstraints.gridx = 0;
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ labelConstraints.gridx = 1;
+ labelConstraints.weightx = 1.0;
+ labelConstraints.ipadx = 1;
+ labelConstraints.insets = new Insets(0, 1, 0, 0); // sweat the pixel
+
+ // make the editor panel go away when not in use
+ // and pass through all mouse events to container
+
+ // this is not very useful since editorLabel and editorButton
+ // get all of the events
+ editorPanel.addMouseListener(this);
+
rendererLabel = new JLabel();
- rendererLabel.setOpaque( false );
- rendererPanel.add( rendererLabel, labelConstraints );
+ rendererLabel.setOpaque(false);
+ rendererPanel.add(rendererLabel, labelConstraints);
editorLabel = new JLabel();
- editorLabel.setText( "" ); // default state
- editorLabel.setOpaque( false );
- editorPanel.add( editorLabel, labelConstraints );
+ editorLabel.setText(""); // default state
+ editorLabel.setOpaque(false);
+ editorPanel.add(editorLabel, labelConstraints);
unselectedForeground = rendererLabel.getForeground();
unselectedBackground = rendererLabel.getBackground();
-
- rendererButton = new JButton();
- rendererButton.setBorder( null );
- rendererButton.setBorderPainted( false );
- rendererButton.setContentAreaFilled( false );
- rendererButton.setFocusPainted( false );
- rendererButton.setMargin( new Insets( 0, 0, 0, 0 ) );
- rendererPanel.add( rendererButton, imageConstraints );
-
- editorButton = new JButton();
- editorButton.setEnabled( clickable ); // default state
- editorButton.setIcon( null ); // default state
- editorButton.setBorder( null );
- editorButton.setBorderPainted( false );
- editorButton.setContentAreaFilled( false );
- editorButton.setFocusPainted( false );
- editorButton.setMargin( new Insets( 0, 0, 0, 0 ) );
- editorPanel.add( editorButton, imageConstraints );
-
- editorButton.addActionListener( this );
-
- //add these in order to dispatch the MouseEvents
- //to the lastKnownComponent, and proper management of
- //DnD operations
- editorLabel.addMouseListener( this );
- editorButton.addMouseListener( this );
- }
-
-/**
-* Returns the text string currently displayed in the editor component.
-*/
- public String getText()
- {
- return editorLabel.getText();
- }
-
-/**
-* Sets the text string displayed in the editor component.
-* Default is an empty string.
-*/
- public void setText( String aString )
- {
- editorLabel.setText( aString );
- }
-/**
-* Returns the icon currently displayed in the editor component.
-*/
- public Icon getIcon()
- {
- return editorButton.getIcon();
- }
-
-/**
-* Sets the icon currently displayed in the editor component.
-* Default is null.
-*/
- public void setIcon( Icon anIcon )
- {
- editorButton.setIcon( anIcon );
- if ( !isClickable() )
- {
- editorButton.setDisabledIcon( anIcon );
- }
- }
+ rendererButton = new JButton();
+ rendererButton.setBorder(null);
+ rendererButton.setBorderPainted(false);
+ rendererButton.setContentAreaFilled(false);
+ rendererButton.setFocusPainted(false);
+ rendererButton.setMargin(new Insets(0, 0, 0, 0));
+ rendererPanel.add(rendererButton, imageConstraints);
+
+ editorButton = new JButton();
+ editorButton.setEnabled(clickable); // default state
+ editorButton.setIcon(null); // default state
+ editorButton.setBorder(null);
+ editorButton.setBorderPainted(false);
+ editorButton.setContentAreaFilled(false);
+ editorButton.setFocusPainted(false);
+ editorButton.setMargin(new Insets(0, 0, 0, 0));
+ editorPanel.add(editorButton, imageConstraints);
+
+ editorButton.addActionListener(this);
+
+ // add these in order to dispatch the MouseEvents
+ // to the lastKnownComponent, and proper management of
+ // DnD operations
+ editorLabel.addMouseListener(this);
+ editorButton.addMouseListener(this);
+ }
-/**
-* Returns whether the editor component's label text is editable.
-*/
- public boolean isEditable()
- {
- return editable;
- }
-
-/**
-* Sets whether the editor component's label text is editable.
-* Default is true. Editable text is not yet implemented.
-*/
- public void setEditable( boolean isEditable )
- {
- editable = isEditable;
- }
+ /**
+ * Returns the text string currently displayed in the editor component.
+ */
+ public String getText() {
+ return editorLabel.getText();
+ }
-/**
-* Returns whether the editor component's icon is clickable.
-*/
- public boolean isClickable()
- {
- return clickable;
- }
-
-/**
-* Sets whether the editor component's icon is clickable.
-* Default is true.
-*/
- public void setClickable( boolean isClickable )
- {
- clickable = isClickable;
- editorButton.setEnabled( clickable );
- }
+ /**
+ * Sets the text string displayed in the editor component. Default is an empty
+ * string.
+ */
+ public void setText(String aString) {
+ editorLabel.setText(aString);
+ }
-/**
-* Returns the component from getRendererForContext.
-*/
- public Component getListCellRendererComponent(JList list,
- Object value,
- int index,
- boolean isSelected,
- boolean cellHasFocus)
- {
- lastKnownComponent = list;
- return getRendererForContext(
- list, value, index, 0, isSelected, cellHasFocus, false, true );
- }
+ /**
+ * Returns the icon currently displayed in the editor component.
+ */
+ public Icon getIcon() {
+ return editorButton.getIcon();
+ }
-/**
-* Returns the component from getRendererForContext.
-*/
- public Component getTableCellRendererComponent(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column)
- {
- lastKnownComponent = table;
- return getRendererForContext(
- table, value, row, column, isSelected, hasFocus, false, true );
- }
+ /**
+ * Sets the icon currently displayed in the editor component. Default is null.
+ */
+ public void setIcon(Icon anIcon) {
+ editorButton.setIcon(anIcon);
+ if (!isClickable()) {
+ editorButton.setDisabledIcon(anIcon);
+ }
+ }
-/**
-* Returns the component from getRendererForContext.
-*/
- public Component getTreeCellRendererComponent(JTree tree,
- Object value,
- boolean selected,
- boolean expanded,
- boolean leaf,
- int row,
- boolean hasFocus)
- {
- lastKnownComponent = tree;
- return getRendererForContext(
- tree, value, row, 0, selected, hasFocus, expanded, leaf );
- }
-
-/**
-* Returns getEditorForContext with the same parameters with hasFocus true.
-*/
- public Component getTableCellEditorComponent(JTable table,
- Object value, boolean isSelected, int row, int column)
- {
+ /**
+ * Returns whether the editor component's label text is editable.
+ */
+ public boolean isEditable() {
+ return editable;
+ }
+
+ /**
+ * Sets whether the editor component's label text is editable. Default is true.
+ * Editable text is not yet implemented.
+ */
+ public void setEditable(boolean isEditable) {
+ editable = isEditable;
+ }
+
+ /**
+ * Returns whether the editor component's icon is clickable.
+ */
+ public boolean isClickable() {
+ return clickable;
+ }
+
+ /**
+ * Sets whether the editor component's icon is clickable. Default is true.
+ */
+ public void setClickable(boolean isClickable) {
+ clickable = isClickable;
+ editorButton.setEnabled(clickable);
+ }
+
+ /**
+ * Returns the component from getRendererForContext.
+ */
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ lastKnownComponent = list;
+ return getRendererForContext(list, value, index, 0, isSelected, cellHasFocus, false, true);
+ }
+
+ /**
+ * Returns the component from getRendererForContext.
+ */
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ lastKnownComponent = table;
+ return getRendererForContext(table, value, row, column, isSelected, hasFocus, false, true);
+ }
+
+ /**
+ * Returns the component from getRendererForContext.
+ */
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
+ boolean leaf, int row, boolean hasFocus) {
+ lastKnownComponent = tree;
+ return getRendererForContext(tree, value, row, 0, selected, hasFocus, expanded, leaf);
+ }
+
+ /**
+ * Returns getEditorForContext with the same parameters with hasFocus true.
+ */
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
lastKnownValue = value;
- lastKnownComponent = table;
- return getEditorForContext(
- table, value, row, column, isSelected, true, false, true );
+ lastKnownComponent = table;
+ return getEditorForContext(table, value, row, column, isSelected, true, false, true);
}
-/**
-* Returns the component from getEditorForContext with hasFocus true.
-*/
- public Component getTreeCellEditorComponent(JTree tree,
- Object value,
- boolean isSelected,
- boolean expanded,
- boolean leaf,
- int row)
- {
-
-
- lastKnownValue = value;
- lastKnownComponent = tree;
-
- return getEditorForContext(
- tree, value, row, 0, isSelected, true, expanded, leaf );
- }
-
-/**
-* This default implementation returns a JPanel that is configured by
-* calling configureComponentForContext.
-* @return An component that is used to render content.
-*/
- public Component getRendererForContext(
- JComponent container, Object value,
- int row, int column,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
-
-
- configureComponentForContext( rendererPanel, rendererButton, rendererLabel,
- container, value, row, column,
- isSelected, hasFocus, isExpanded, isLeaf );
+ /**
+ * Returns the component from getEditorForContext with hasFocus true.
+ */
+ public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded,
+ boolean leaf, int row) {
+
+ lastKnownValue = value;
+ lastKnownComponent = tree;
+
+ return getEditorForContext(tree, value, row, 0, isSelected, true, expanded, leaf);
+ }
+
+ /**
+ * This default implementation returns a JPanel that is configured by calling
+ * configureComponentForContext.
+ *
+ * @return An component that is used to render content.
+ */
+ public Component getRendererForContext(JComponent container, Object value, int row, int column, boolean isSelected,
+ boolean hasFocus, boolean isExpanded, boolean isLeaf) {
+
+ configureComponentForContext(rendererPanel, rendererButton, rendererLabel, container, value, row, column,
+ isSelected, hasFocus, isExpanded, isLeaf);
return rendererPanel;
- }
+ }
-/**
-* This method returns a separate component that should be visually
-* identical to the renderer component. We can't simply reuse the
-* renderer component because the renderer is still used to paint
-* the table while the editor component is displayed. Clicks are
-* received on this component.
-* This default implementation returns a JPanel that is configured by
-* calling configureComponentForContext.
-* @return A component used to receive clicks on the cell.
-*/
- public Component getEditorForContext(
- JComponent container, Object value,
- int row, int column,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- configureComponentForContext( editorPanel, editorButton, editorLabel,
- container, value, row, column,
- true, hasFocus, isExpanded, isLeaf ); // editor should always be selected
+ /**
+ * This method returns a separate component that should be visually identical to
+ * the renderer component. We can't simply reuse the renderer component because
+ * the renderer is still used to paint the table while the editor component is
+ * displayed. Clicks are received on this component. This default implementation
+ * returns a JPanel that is configured by calling configureComponentForContext.
+ *
+ * @return A component used to receive clicks on the cell.
+ */
+ public Component getEditorForContext(JComponent container, Object value, int row, int column, boolean isSelected,
+ boolean hasFocus, boolean isExpanded, boolean isLeaf) {
+ configureComponentForContext(editorPanel, editorButton, editorLabel, container, value, row, column, true,
+ hasFocus, isExpanded, isLeaf); // editor should always be selected
return editorPanel;
- }
+ }
-/**
-* Called to configure components
-*/
- protected void configureComponentForContext(
- JPanel component, JButton iconButton, JLabel label,
- JComponent container, Object value,
- int row, int column,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- if (hasFocus)
- {
- if ( container instanceof JTable )
- {
- component.setBorder(
- UIManager.getBorder("Table.focusCellHighlightBorder") );
- }
- else
- {
- component.setBorder( noFocusBorder );
- }
-
- if ( container instanceof JTree ) // was: (false)
- {
- label.setBorder( treeFocusBorder );
- }
- else
- {
- label.setBorder( noFocusBorder );
- }
- }
- else
- {
- label.setBorder(noFocusBorder);
- component.setBorder(noFocusBorder);
- }
-
- if (isSelected)
- {
- if ( container instanceof JTree )
- {
- label.setOpaque( true );
- label.setForeground(UIManager.getColor("Tree.selectionForeground"));
- label.setBackground(UIManager.getColor("Tree.selectionBackground"));
- component.setBackground(container.getBackground());
- }
- else if ( container instanceof JTable )
- {
- label.setOpaque( false );
- label.setForeground( ((JTable)container).getSelectionForeground() );
- component.setBackground(((JTable)container).getSelectionBackground());
- }
- else
- {
- label.setOpaque( false );
- label.setForeground(UIManager.getColor("Table.selectionForeground"));
- component.setBackground(UIManager.getColor("Table.selectionBackground"));
- }
- }
- else
- {
- label.setOpaque( false );
- label.setForeground(container.getForeground());
- component.setBackground(container.getBackground());
- }
-
- label.setFont(container.getFont());
-
- Icon icon = getIconForContext(
- container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf );
- iconButton.setIcon( icon );
- if ( !isClickable() )
- {
- iconButton.setDisabledIcon( icon );
- }
-
- String text = getStringForContext(
- container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf );
-
- if ( ( text == null ) || ( "".equals( text ) ) )
- {
- if ( ! label.getText().equals( "" ) )
- label.setText( "" );
+ /**
+ * Called to configure components
+ */
+ protected void configureComponentForContext(JPanel component, JButton iconButton, JLabel label,
+ JComponent container, Object value, int row, int column, boolean isSelected, boolean hasFocus,
+ boolean isExpanded, boolean isLeaf) {
+ if (hasFocus) {
+ if (container instanceof JTable) {
+ component.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
+ } else {
+ component.setBorder(noFocusBorder);
+ }
+
+ if (container instanceof JTree) // was: (false)
+ {
+ label.setBorder(treeFocusBorder);
+ } else {
+ label.setBorder(noFocusBorder);
+ }
+ } else {
+ label.setBorder(noFocusBorder);
+ component.setBorder(noFocusBorder);
}
- else
- {
- if ( ! label.getText().equals( text ) )
- label.setText( text );
+
+ if (isSelected) {
+ if (container instanceof JTree) {
+ label.setOpaque(true);
+ label.setForeground(UIManager.getColor("Tree.selectionForeground"));
+ label.setBackground(UIManager.getColor("Tree.selectionBackground"));
+ component.setBackground(container.getBackground());
+ } else if (container instanceof JTable) {
+ label.setOpaque(false);
+ label.setForeground(((JTable) container).getSelectionForeground());
+ component.setBackground(((JTable) container).getSelectionBackground());
+ } else {
+ label.setOpaque(false);
+ label.setForeground(UIManager.getColor("Table.selectionForeground"));
+ component.setBackground(UIManager.getColor("Table.selectionBackground"));
+ }
+ } else {
+ label.setOpaque(false);
+ label.setForeground(container.getForeground());
+ component.setBackground(container.getBackground());
+ }
+
+ label.setFont(container.getFont());
+
+ Icon icon = getIconForContext(container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf);
+ iconButton.setIcon(icon);
+ if (!isClickable()) {
+ iconButton.setDisabledIcon(icon);
+ }
+
+ String text = getStringForContext(container, value, row, column, isSelected, hasFocus, isExpanded, isLeaf);
+
+ if ((text == null) || ("".equals(text))) {
+ if (!label.getText().equals(""))
+ label.setText("");
+ } else {
+ if (!label.getText().equals(text))
+ label.setText(text);
}
}
-
-/**
-* Override this method to provide an icon for the renderer.
-* This default implementation returns null.
-* @return An icon to be displayed in the cell, or null to omit the
-* icon from the cell.
-*/
- public Icon getIconForContext(
- JComponent container, Object value,
- int row, int column,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- return null;
- }
-/**
-* Override this method to provide a string for the renderer.
-* This default implementation returns toString on the value parameter,
-* or null if the value is null.
-* @return A string to be displayed in the cell.
-*/
- public String getStringForContext(
- JComponent container, Object value,
- int row, int column,
- boolean isSelected, boolean hasFocus,
- boolean isExpanded, boolean isLeaf )
- {
- if ( value == null ) return null;
- return value.toString();
- }
-
- /**
- * Adds the specified listener to the list of listeners
- * to be notified when the button receives a click.
- */
- public void addActionListener( ActionListener aListener )
- {
- if ( actionListeners == null )
- {
- actionListeners = new Vector( 2 );
+ /**
+ * Override this method to provide an icon for the renderer. This default
+ * implementation returns null.
+ *
+ * @return An icon to be displayed in the cell, or null to omit the icon from
+ * the cell.
+ */
+ public Icon getIconForContext(JComponent container, Object value, int row, int column, boolean isSelected,
+ boolean hasFocus, boolean isExpanded, boolean isLeaf) {
+ return null;
+ }
+
+ /**
+ * Override this method to provide a string for the renderer. This default
+ * implementation returns toString on the value parameter, or null if the value
+ * is null.
+ *
+ * @return A string to be displayed in the cell.
+ */
+ public String getStringForContext(JComponent container, Object value, int row, int column, boolean isSelected,
+ boolean hasFocus, boolean isExpanded, boolean isLeaf) {
+ if (value == null)
+ return null;
+ return value.toString();
+ }
+
+ /**
+ * Adds the specified listener to the list of listeners to be notified when the
+ * button receives a click.
+ */
+ public void addActionListener(ActionListener aListener) {
+ if (actionListeners == null) {
+ actionListeners = new Vector(2);
}
- actionListeners.add( aListener );
+ actionListeners.add(aListener);
}
-
+
/**
- * Removes the specified listener from the list of listeners
- * to be notified when the button receives a click.
- */
- public void removeActionListener( ActionListener aListener )
- {
- actionListeners.remove( aListener );
+ * Removes the specified listener from the list of listeners to be notified when
+ * the button receives a click.
+ */
+ public void removeActionListener(ActionListener aListener) {
+ actionListeners.remove(aListener);
}
-
+
/**
- * Broadcasts the specified action event to all listeners.
- */
- protected void fireActionEvent( ActionEvent anActionEvent )
- {
- if ( actionListeners == null ) return;
+ * Broadcasts the specified action event to all listeners.
+ */
+ protected void fireActionEvent(ActionEvent anActionEvent) {
+ if (actionListeners == null)
+ return;
// vector's enumeration is not fail-fast
Enumeration e = actionListeners.elements();
- while ( e.hasMoreElements() )
- {
- ((ActionListener)e.nextElement()).actionPerformed( anActionEvent );
+ while (e.hasMoreElements()) {
+ ((ActionListener) e.nextElement()).actionPerformed(anActionEvent);
}
}
-
+
/**
- * Returns the action command broadcast when this icon
- * receives a click. Defaults to CLICKED.
- */
- public String getActionCommand()
- {
+ * Returns the action command broadcast when this icon receives a click.
+ * Defaults to CLICKED.
+ */
+ public String getActionCommand() {
return actionCommand;
}
/**
- * Sets the action command broadcast when this table
- * receives a double click.
- */
- public void setActionCommand( String anActionCommand )
- {
- actionCommand = anActionCommand;
+ * Sets the action command broadcast when this table receives a double click.
+ */
+ public void setActionCommand(String anActionCommand) {
+ actionCommand = anActionCommand;
}
-
+
// interface CellEditor
/**
- * Returns lastKnownValue, although this should not be called.
- */
- public Object getCellEditorValue()
- {
+ * Returns lastKnownValue, although this should not be called.
+ */
+ public Object getCellEditorValue() {
return lastKnownValue;
}
-
+
/**
- * Returns true.
- */
- public boolean isCellEditable(EventObject anEvent)
- {
- return true;
+ * Returns true.
+ */
+ public boolean isCellEditable(EventObject anEvent) {
+ return true;
}
-
+
/**
- * Returns true.
- */
- public boolean shouldSelectCell(EventObject anEvent)
- {
+ * Returns true.
+ */
+ public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
-
+
/**
- * Fires an editing stopped event and returns true.
- */
- public boolean stopCellEditing()
- {
- ChangeEvent event = new ChangeEvent( this );
- if ( cellEditorListeners != null )
- {
+ * Fires an editing stopped event and returns true.
+ */
+ public boolean stopCellEditing() {
+ ChangeEvent event = new ChangeEvent(this);
+ if (cellEditorListeners != null) {
// vector's enumeration is not fail-fast
Enumeration e = cellEditorListeners.elements();
- while ( e.hasMoreElements() )
- {
- // broadcast editing cancelled since no value is edited
- ((CellEditorListener)e.nextElement()).editingCanceled( event );
+ while (e.hasMoreElements()) {
+ // broadcast editing cancelled since no value is edited
+ ((CellEditorListener) e.nextElement()).editingCanceled(event);
}
}
- lastKnownComponent = null;
+ lastKnownComponent = null;
return true;
}
-
- /**
- * Fires an editing cancelled event and returns true.
- */
- public void cancelCellEditing()
- {
- //HACK: cancelCellEditing() causes for the dragGesture
- //to be NOT recognized AT ALL since on the next MOUSE_PRESSED
- //the cell editor first needs to startEditing() [if in the tree
- //the CellEditorListener is a BasicTreeUI class]
- //(before the drag gesture event can be recognized).
- //Also the lastKnownComponent should not be set to null,
- //none of the mouse events won't dispathced to the lastKnownComponent
- //in that case.
-
- //Not calling it at all does seem to fix it, but what are the
- //consequences???
- //Trying to workaround this might solve it, but it introduces having
- //an extra listener (a MouseMotionListnener), which might be wasteful
- //(i.e. only if a Mouse_dragged event has been initiated, but DragGesture
- //hasn't been recognized, postpone calling this till finish the DnD event)
- //But what if do DnD and not exited ??? The mouseExited() is not called
- //anyway until the DnD event is done.
-
- ChangeEvent event = new ChangeEvent( this );
- if ( cellEditorListeners == null ) return;
+
+ /**
+ * Fires an editing cancelled event and returns true.
+ */
+ public void cancelCellEditing() {
+ // HACK: cancelCellEditing() causes for the dragGesture
+ // to be NOT recognized AT ALL since on the next MOUSE_PRESSED
+ // the cell editor first needs to startEditing() [if in the tree
+ // the CellEditorListener is a BasicTreeUI class]
+ // (before the drag gesture event can be recognized).
+ // Also the lastKnownComponent should not be set to null,
+ // none of the mouse events won't dispathced to the lastKnownComponent
+ // in that case.
+
+ // Not calling it at all does seem to fix it, but what are the
+ // consequences???
+ // Trying to workaround this might solve it, but it introduces having
+ // an extra listener (a MouseMotionListnener), which might be wasteful
+ // (i.e. only if a Mouse_dragged event has been initiated, but DragGesture
+ // hasn't been recognized, postpone calling this till finish the DnD event)
+ // But what if do DnD and not exited ??? The mouseExited() is not called
+ // anyway until the DnD event is done.
+
+ ChangeEvent event = new ChangeEvent(this);
+ if (cellEditorListeners == null)
+ return;
// vector's enumeration is not fail-fast
Enumeration e = cellEditorListeners.elements();
-
- while ( e.hasMoreElements() )
- {
- ((CellEditorListener)e.nextElement()).editingCanceled( event );
- }
-
- //DO not nullify this
- lastKnownComponent = null;
- }
-
- /**
- * Adds the specified listener to the list of listeners
- * to be notified when the table receives a double click.
- */
- public void addCellEditorListener( CellEditorListener aListener )
- {
- if ( cellEditorListeners == null )
- {
- cellEditorListeners = new Vector( 2 );
+
+ while (e.hasMoreElements()) {
+ ((CellEditorListener) e.nextElement()).editingCanceled(event);
+ }
+
+ // DO not nullify this
+ lastKnownComponent = null;
+ }
+
+ /**
+ * Adds the specified listener to the list of listeners to be notified when the
+ * table receives a double click.
+ */
+ public void addCellEditorListener(CellEditorListener aListener) {
+ if (cellEditorListeners == null) {
+ cellEditorListeners = new Vector(2);
}
- cellEditorListeners.add( aListener );
+ cellEditorListeners.add(aListener);
}
-
+
/**
- * Removes the specified listener from the list of listeners
- * to be notified when the table receives a double click.
- */
- public void removeCellEditorListener( CellEditorListener aListener )
- {
- cellEditorListeners.remove( aListener );
+ * Removes the specified listener from the list of listeners to be notified when
+ * the table receives a double click.
+ */
+ public void removeCellEditorListener(CellEditorListener aListener) {
+ cellEditorListeners.remove(aListener);
}
-
+
// interface ActionListener
-
- /**
- * Puts ourself on the end of the event queue for
- * firing our action event to all listeners.
- */
- public void actionPerformed( ActionEvent evt )
- {
- //commented out in order NOT to set lastKnownComponent to null, since
- //if this object is inside a table or tree, relying on getCellEditorValue()
- //to return the currently edited object
- //cancelCellEditing();
-
- SwingUtilities.invokeLater( this );
- }
-
+
+ /**
+ * Puts ourself on the end of the event queue for firing our action event to all
+ * listeners.
+ */
+ public void actionPerformed(ActionEvent evt) {
+ // commented out in order NOT to set lastKnownComponent to null, since
+ // if this object is inside a table or tree, relying on getCellEditorValue()
+ // to return the currently edited object
+ // cancelCellEditing();
+
+ SwingUtilities.invokeLater(this);
+ }
+
// interface Runnable
-
+
/**
- * Fires the action event to all listeners.
- * This is triggered by a click on the icon.
- */
- public void run()
- {
- fireActionEvent( new ActionEvent( this, 0, getActionCommand() ) );
+ * Fires the action event to all listeners. This is triggered by a click on the
+ * icon.
+ */
+ public void run() {
+ fireActionEvent(new ActionEvent(this, 0, getActionCommand()));
}
// interface MouseListener
-
- /**
- * Passes through editor mouse clicks to last known component.
- * (left click only)
- */
- public void mouseClicked(MouseEvent e)
- {
- if(lastKnownComponent != null){
- Object source = e.getSource();
- if(source != null)
- {
- if(source == editorPanel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorPanel, e, lastKnownComponent ) );
-
- }
- else if(source == editorLabel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorLabel, e, lastKnownComponent ) );
- }
-
- else if(source == editorButton)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorButton, e, lastKnownComponent ) );
- }
- }
- }
- }
-
- /**
- * Passes through editor right-mouse (popup trigger) mouse events to last known component.
- * Needed for possible displaying of popup menus on right click
- */
- public void mousePressed(MouseEvent e)
- {
- if ( e.isPopupTrigger() )
- {
- if(lastKnownComponent != null)
- {
- Object source = e.getSource();
- if(source != null)
- {
- if(source == editorPanel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorPanel, e, lastKnownComponent ) );
- }
- else if(source == editorLabel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorLabel, e, lastKnownComponent ) );
- }
-
- else if(source == editorButton)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorButton, e, lastKnownComponent ) );
- }
- }
- }
- }
- }
-
- /**
- * Does nothing.
- */
- public void mouseReleased(MouseEvent e)
- {
- if ( e.isPopupTrigger() )
- {
- if(lastKnownComponent != null){
-
- Object source = e.getSource();
- if(source != null)
- {
- if(source == editorPanel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorPanel, e, lastKnownComponent ) );
- }
-
- else if(source == editorLabel)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorLabel, e, lastKnownComponent ) );
- }
-
- else if(source == editorButton)
- {
- lastKnownComponent.dispatchEvent(
- SwingUtilities.convertMouseEvent(
- editorButton, e, lastKnownComponent ) );
- }
- }
- }
- }
- }
-
- /**
- * Does nothing.
- */
- public void mouseEntered(MouseEvent e)
- {
- }
-
- /**
- * Cancels cell editing.
- */
- public void mouseExited(MouseEvent e)
- {
- Object source = e.getSource();
- if(source != null && source instanceof JComponent){
- //need to convert the Point from the source's coordinate system to editorPanel's coordinate system.
- //(note that simple editorPanel.contains(e.getPoint()) fails if source is editorButton)
-
- Point convertedPoint = SwingUtilities.convertPoint((JComponent) source, e.getPoint(), editorPanel);
-
- //check if exited from editorButton, but still inside the editorPanel (works for editorLabel as well)
- if(!editorPanel.contains(convertedPoint)){
-
- //This was getting called before, but it interfers with the DnD operation
- cancelCellEditing();
- }
- }
- }
-
- /* This might be redundant
- public void cleanUp(){
-
- //since cancelCellEditing() was never called call it now
- cancelCellEditing();
- stopCellEditing();
-
- editorButton.removeActionListener( this );
- editorPanel.removeMouseListener( this );
- editorLabel.removeMouseListener( this );
- editorButton.removeMouseListener( this );
- lastKnownComponent = null;
- lastKnownValue = null;
- }
- */
+
+ /**
+ * Passes through editor mouse clicks to last known component. (left click only)
+ */
+ public void mouseClicked(MouseEvent e) {
+ if (lastKnownComponent != null) {
+ Object source = e.getSource();
+ if (source != null) {
+ if (source == editorPanel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorPanel, e, lastKnownComponent));
+
+ } else if (source == editorLabel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorLabel, e, lastKnownComponent));
+ }
+
+ else if (source == editorButton) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorButton, e, lastKnownComponent));
+ }
+ }
+ }
+ }
+
+ /**
+ * Passes through editor right-mouse (popup trigger) mouse events to last known
+ * component. Needed for possible displaying of popup menus on right click
+ */
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ if (lastKnownComponent != null) {
+ Object source = e.getSource();
+ if (source != null) {
+ if (source == editorPanel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorPanel, e, lastKnownComponent));
+ } else if (source == editorLabel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorLabel, e, lastKnownComponent));
+ }
+
+ else if (source == editorButton) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorButton, e, lastKnownComponent));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ if (lastKnownComponent != null) {
+
+ Object source = e.getSource();
+ if (source != null) {
+ if (source == editorPanel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorPanel, e, lastKnownComponent));
+ }
+
+ else if (source == editorLabel) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorLabel, e, lastKnownComponent));
+ }
+
+ else if (source == editorButton) {
+ lastKnownComponent
+ .dispatchEvent(SwingUtilities.convertMouseEvent(editorButton, e, lastKnownComponent));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ /**
+ * Cancels cell editing.
+ */
+ public void mouseExited(MouseEvent e) {
+ Object source = e.getSource();
+ if (source != null && source instanceof JComponent) {
+ // need to convert the Point from the source's coordinate system to
+ // editorPanel's coordinate system.
+ // (note that simple editorPanel.contains(e.getPoint()) fails if source is
+ // editorButton)
+
+ Point convertedPoint = SwingUtilities.convertPoint((JComponent) source, e.getPoint(), editorPanel);
+
+ // check if exited from editorButton, but still inside the editorPanel (works
+ // for editorLabel as well)
+ if (!editorPanel.contains(convertedPoint)) {
+
+ // This was getting called before, but it interfers with the DnD operation
+ cancelCellEditing();
+ }
+ }
+ }
+
+ /*
+ * This might be redundant public void cleanUp(){
+ *
+ * //since cancelCellEditing() was never called call it now cancelCellEditing();
+ * stopCellEditing();
+ *
+ * editorButton.removeActionListener( this ); editorPanel.removeMouseListener(
+ * this ); editorLabel.removeMouseListener( this );
+ * editorButton.removeMouseListener( this ); lastKnownComponent = null;
+ * lastKnownValue = null; }
+ */
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ImagePanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ImagePanel.java
index cdaa218..4fa8e04 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ImagePanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/ImagePanel.java
@@ -26,79 +26,58 @@ import java.awt.image.ImageObserver;
import javax.swing.JPanel;
/**
-* A JPanel that renders an image, tiling as necessary to
-* fill the panel.
-* The preferred size of the panel is the size of the image
-* and will change until the image is fully loaded, so using
-* a media tracker is recommended.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
-public class ImagePanel extends JPanel implements ImageObserver
-{
+ * A JPanel that renders an image, tiling as necessary to fill the panel. The
+ * preferred size of the panel is the size of the image and will change until
+ * the image is fully loaded, so using a media tracker is recommended.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
+public class ImagePanel extends JPanel implements ImageObserver {
protected Image image;
protected int imageWidth, imageHeight;
-
- public ImagePanel()
- {
- this( null );
- }
-
- public ImagePanel( Image anImage )
- {
- image = anImage;
- if ( anImage != null )
- {
- prepareImage( image, this );
+
+ public ImagePanel() {
+ this(null);
+ }
+
+ public ImagePanel(Image anImage) {
+ image = anImage;
+ if (anImage != null) {
+ prepareImage(image, this);
// these may return -1
- imageWidth = image.getWidth( this );
- imageHeight = image.getHeight( this );
- }
- else
- {
+ imageWidth = image.getWidth(this);
+ imageHeight = image.getHeight(this);
+ } else {
imageWidth = 0;
imageHeight = 0;
}
}
-
- protected void paintComponent(Graphics g)
- {
- if ( ( image != null ) && ( imageWidth > 0 ) && ( imageHeight > 0 ) )
- {
+
+ protected void paintComponent(Graphics g) {
+ if ((image != null) && (imageWidth > 0) && (imageHeight > 0)) {
int width = getWidth();
int height = getHeight();
-
- for ( int x = 0; x < width; x += imageWidth )
- {
- for ( int y = 0; y < height; y += imageHeight )
- {
- g.drawImage( image, x, y,
- imageWidth, imageHeight,
- getBackground(), this );
+
+ for (int x = 0; x < width; x += imageWidth) {
+ for (int y = 0; y < height; y += imageHeight) {
+ g.drawImage(image, x, y, imageWidth, imageHeight, getBackground(), this);
}
}
}
}
-
- public boolean imageUpdate(Image img,
- int infoflags,
- int x,
- int y,
- int width,
- int height)
- {
+
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
imageWidth = width;
imageHeight = height;
- setPreferredSize( new Dimension( width, height ) );
- revalidate();
+ setPreferredSize(new Dimension(width, height));
+ revalidate();
repaint();
-
- if ( ( infoflags & ImageObserver.ALLBITS ) == ImageObserver.ALLBITS )
- {
- return false;
+
+ if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
+ return false;
}
return true;
}
-
+
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/InfoPanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/InfoPanel.java
index 55c1e36..a2c0182 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/InfoPanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/InfoPanel.java
@@ -49,1645 +49,1521 @@ import javax.swing.JTextField;
import javax.swing.SwingConstants;
/**
-* InfoPanel uses labels and textfields (or any other component - see below)
-* to display a list of keys and values in a well-aligned and consistent manner,
-* conforming to alignment and pixel spacing in the java look and feel
-* <a href="http://java.sun.com/products/jlf/dg/higg.htm#55417">design guidelines</a>.
-* <BR><BR>
-*
-* Each key is displayed in a label to the left of the component that contains
-* the corresponding value. Each row is displayed starting at the top of the
-* component's available area. Each row's height is the maximum preferred
-* height of its components and the field itself gets as much of the width as
-* it can, dependent on the length of the longest label. <BR><BR>
-*
-* The values in the fields can be editable, and the
-* current value can be retrieved using the key - for this reason, unique keys
-* are recommended. <BR><BR>
-*
-* As a convenience, push buttons may be placed across the
-* bottom of the panel in a manner similar to ButtonPanel. <BR><BR>
-*
-* The panel forwards any ActionEvents generated by the components and
-* buttons on it to all registered listeners. <BR><BR>
-*
-* Optionally, any component can be used instead of a textfield.
-* However, <code>get/setValueForKey()</code> and <code>get/setEditable()</code>
-* may not work for those components. Use <code>getComponentForKey()</code> to
-* access them instead.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class InfoPanel extends JPanel implements ActionListener
-{
-/**
-* Special label for an empty pair - a label and component
-* that take up space but are hidden from view. This might
-* be useful for achieving certain layouts.
-*/
- public static final String HIDDEN = "(hidden)";
-
- /** Cache for the introspectComponent method */
- private static Map _method_cache =
- Collections.synchronizedMap( new HashMap(30) );
-
- protected Container listContainer = null;
- protected int hgap; // set in constructor
- protected int vgap; // set in constructor
- protected int margin; // set in constructor
- protected int columns; // set in constructor
- protected List fields = null;
- protected List labels = null;
- protected List fieldSpacers = null;
- protected ButtonPanel buttonPanel = null;
- protected boolean isEditable = true;
- protected String prefix;
- protected String postfix;
+ * InfoPanel uses labels and textfields (or any other component - see below) to
+ * display a list of keys and values in a well-aligned and consistent manner,
+ * conforming to alignment and pixel spacing in the java look and feel
+ * <a href="http://java.sun.com/products/jlf/dg/higg.htm#55417">design
+ * guidelines</a>. <BR>
+ * <BR>
+ *
+ * Each key is displayed in a label to the left of the component that contains
+ * the corresponding value. Each row is displayed starting at the top of the
+ * component's available area. Each row's height is the maximum preferred height
+ * of its components and the field itself gets as much of the width as it can,
+ * dependent on the length of the longest label. <BR>
+ * <BR>
+ *
+ * The values in the fields can be editable, and the current value can be
+ * retrieved using the key - for this reason, unique keys are recommended. <BR>
+ * <BR>
+ *
+ * As a convenience, push buttons may be placed across the bottom of the panel
+ * in a manner similar to ButtonPanel. <BR>
+ * <BR>
+ *
+ * The panel forwards any ActionEvents generated by the components and buttons
+ * on it to all registered listeners. <BR>
+ * <BR>
+ *
+ * Optionally, any component can be used instead of a textfield. However,
+ * <code>get/setValueForKey()</code> and <code>get/setEditable()</code> may not
+ * work for those components. Use <code>getComponentForKey()</code> to access
+ * them instead.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class InfoPanel extends JPanel implements ActionListener {
+ /**
+ * Special label for an empty pair - a label and component that take up space
+ * but are hidden from view. This might be useful for achieving certain layouts.
+ */
+ public static final String HIDDEN = "(hidden)";
+
+ /** Cache for the introspectComponent method */
+ private static Map _method_cache = Collections.synchronizedMap(new HashMap(30));
+
+ protected Container listContainer = null;
+ protected int hgap; // set in constructor
+ protected int vgap; // set in constructor
+ protected int margin; // set in constructor
+ protected int columns; // set in constructor
+ protected List fields = null;
+ protected List labels = null;
+ protected List fieldSpacers = null;
+ protected ButtonPanel buttonPanel = null;
+ protected boolean isEditable = true;
+ protected String prefix;
+ protected String postfix;
protected int labelAnchor;
protected int labelAlign;
// protected Component marginStrut = null;
- // for action multicasting
- protected ActionListener actionListener = null;
-
-/**
-* Constructs an empty InfoPanel.
-*/
- public InfoPanel()
- {
- hgap = 12; // per java l&f guidelines
- vgap = 6; // java l&f says 11
- columns = 1; // default columns
- margin = 0; // default margin: none
- prefix = ""; // default prefix: none
- postfix = ":"; // per java l&f guidelines
- fields = new ArrayList();
- labels = new ArrayList();
- labelAnchor = GridBagConstraints.NORTHWEST;
- // per java l&f guidelines (CENTER is nicer)
- labelAlign = SwingConstants.LEFT;
- // per java l&f guidelines
-
- doInitialLayout();
- }
+ // for action multicasting
+ protected ActionListener actionListener = null;
+
+ /**
+ * Constructs an empty InfoPanel.
+ */
+ public InfoPanel() {
+ hgap = 12; // per java l&f guidelines
+ vgap = 6; // java l&f says 11
+ columns = 1; // default columns
+ margin = 0; // default margin: none
+ prefix = ""; // default prefix: none
+ postfix = ":"; // per java l&f guidelines
+ fields = new ArrayList();
+ labels = new ArrayList();
+ labelAnchor = GridBagConstraints.NORTHWEST;
+ // per java l&f guidelines (CENTER is nicer)
+ labelAlign = SwingConstants.LEFT;
+ // per java l&f guidelines
+
+ doInitialLayout();
+ }
-/**
-* Constructs an InfoPanel with the specified labels
-* each paired with a blank textfield.
-* @param labelArray An Array containing the labels in the
-* order in which they should appear from top to bottom.
-* A null value produces an empty panel.
-*/
- public InfoPanel( String[] labelArray )
- {
- this();
- setLabels( labelArray );
- }
+ /**
+ * Constructs an InfoPanel with the specified labels each paired with a blank
+ * textfield.
+ *
+ * @param labelArray An Array containing the labels in the order in which they
+ * should appear from top to bottom. A null value produces an
+ * empty panel.
+ */
+ public InfoPanel(String[] labelArray) {
+ this();
+ setLabels(labelArray);
+ }
-/**
-* Creates a set of labels and empty textfields after first
-* clearing all existing components on the panel.
-* @param labelArray An Array containing the labels in the order
-* in which they should appear from top to bottom. A null
-* value will clear the panel.
-*/
- public void setLabels( String[] labelArray )
- {
- removeAll();
- if ( labelArray == null ) return; // null clears panel
- for ( int i = 0; i < labelArray.length; i++ )
- {
- addPair( labelArray[i], new JTextField() );
- }
- }
+ /**
+ * Creates a set of labels and empty textfields after first clearing all
+ * existing components on the panel.
+ *
+ * @param labelArray An Array containing the labels in the order in which they
+ * should appear from top to bottom. A null value will clear
+ * the panel.
+ */
+ public void setLabels(String[] labelArray) {
+ removeAll();
+ if (labelArray == null)
+ return; // null clears panel
+ for (int i = 0; i < labelArray.length; i++) {
+ addPair(labelArray[i], new JTextField());
+ }
+ }
-/**
-* Retrieves the labls for the components on the panel
-* in the order in which they are displayed from top WIDTH bottom.
-* These are the keys used to reference values or to reference
-* the components directly.
-* @return An Array of Strings containing the labels.
-*/
- public String[] getLabels()
- {
- int length = fields.size();
- String[] labelArray = new String[ length ];
- for ( int i = 0; i < length; i++ )
- {
- labelArray[i] = ((Component)fields.get(i)).getName();
- }
- return labelArray;
- }
-
-/**
-* Retrieves the constant used to anchor the labels in place.
-* The default value is GridBagConstraints.NORTHWEST.
-*/
- public int getLabelAnchor()
- {
+ /**
+ * Retrieves the labls for the components on the panel in the order in which
+ * they are displayed from top WIDTH bottom. These are the keys used to
+ * reference values or to reference the components directly.
+ *
+ * @return An Array of Strings containing the labels.
+ */
+ public String[] getLabels() {
+ int length = fields.size();
+ String[] labelArray = new String[length];
+ for (int i = 0; i < length; i++) {
+ labelArray[i] = ((Component) fields.get(i)).getName();
+ }
+ return labelArray;
+ }
+
+ /**
+ * Retrieves the constant used to anchor the labels in place. The default value
+ * is GridBagConstraints.NORTHWEST.
+ */
+ public int getLabelAnchor() {
return labelAnchor;
}
-/**
-* Sets the constant used to anchor the labels in place
-* and reflows the layout.
-* @param anAnchorConstant An anchor constant from
-* GridBagConstraints.
-*/
- public void setLabelAnchor( int anAnchorConstant )
- {
- labelAnchor = anAnchorConstant;
+ /**
+ * Sets the constant used to anchor the labels in place and reflows the layout.
+ *
+ * @param anAnchorConstant An anchor constant from GridBagConstraints.
+ */
+ public void setLabelAnchor(int anAnchorConstant) {
+ labelAnchor = anAnchorConstant;
updateLabels();
}
-/**
-* Retrieves the constant used to align the labels in place.
-* The default value is GridBagConstraints.CENTER.
-*/
- public int getLabelAlignment()
- {
+ /**
+ * Retrieves the constant used to align the labels in place. The default value
+ * is GridBagConstraints.CENTER.
+ */
+ public int getLabelAlignment() {
return labelAlign;
}
-/**
-* Sets the constant used to align the labels in place
-* and reflows the layout.
-* @param anAlignmentConstant LEFT, CENTER, or RIGHT constants
-* from SwingUtilities.
-*/
- public void setLabelAlignment( int anAlignmentConstant )
- {
- labelAlign = anAlignmentConstant;
+ /**
+ * Sets the constant used to align the labels in place and reflows the layout.
+ *
+ * @param anAlignmentConstant LEFT, CENTER, or RIGHT constants from
+ * SwingUtilities.
+ */
+ public void setLabelAlignment(int anAlignmentConstant) {
+ labelAlign = anAlignmentConstant;
updateLabels();
}
-
-/**
-* Factory method for creating panel spacers.
-* This implementation returns a JPanel with
-* opaque set to false. Override to customize.
-*/
- public JPanel createPanel()
- {
- JPanel result = new JPanel();
- result.setOpaque( false );
- return result;
- }
-/**
-* This method is responsible for the initial layout of the panel.
-* All labels and textfields will later added to listContainer.
-* This method is responsible for initializing listContainer.
-*/
- protected void doInitialLayout()
- {
- listContainer = createPanel();
- listContainer.setLayout( new BetterGridBagLayout() );
- this.setLayout( new BorderLayout() );
- this.add( listContainer, BorderLayout.NORTH );
+ /**
+ * Factory method for creating panel spacers. This implementation returns a
+ * JPanel with opaque set to false. Override to customize.
+ */
+ public JPanel createPanel() {
+ JPanel result = new JPanel();
+ result.setOpaque(false);
+ return result;
+ }
- //listContainer.setBackground( Color.blue ); // useful for testing
- //this.setBackground( Color.red );
- }
+ /**
+ * This method is responsible for the initial layout of the panel. All labels
+ * and textfields will later added to listContainer. This method is responsible
+ * for initializing listContainer.
+ */
+ protected void doInitialLayout() {
+ listContainer = createPanel();
+ listContainer.setLayout(new BetterGridBagLayout());
+ this.setLayout(new BorderLayout());
+ this.add(listContainer, BorderLayout.NORTH);
+
+ // listContainer.setBackground( Color.blue ); // useful for testing
+ // this.setBackground( Color.red );
+ }
-/**
-* Changes the horizontal spacing between the label and the components in the panel.
-* Note: Assumes listContainer uses a GridBagLayout.
-* @param newHgap the new spacing, in pixels. May not be negative.
-*/
- public void setHgap( int newHgap )
- {
- if ( newHgap < 0 ) return; // may not be negative
- this.hgap = newHgap;
- updateGaps();
- this.revalidate();
- this.repaint();
+ /**
+ * Changes the horizontal spacing between the label and the components in the
+ * panel. Note: Assumes listContainer uses a GridBagLayout.
+ *
+ * @param newHgap the new spacing, in pixels. May not be negative.
+ */
+ public void setHgap(int newHgap) {
+ if (newHgap < 0)
+ return; // may not be negative
+ this.hgap = newHgap;
+ updateGaps();
+ this.revalidate();
+ this.repaint();
- }
+ }
-/**
-* Gets the current horizontal spacing between components.
-* @return the current horizontal spacing, in pixels.
-*/
- public int getHgap()
- {
- return this.hgap;
- }
+ /**
+ * Gets the current horizontal spacing between components.
+ *
+ * @return the current horizontal spacing, in pixels.
+ */
+ public int getHgap() {
+ return this.hgap;
+ }
-/**
-* Changes the vertical spacing between components in the panel.
-* Note: Assumes listContainer uses a GridBagLayout.
-* @param newVgap the new spacing, in pixels. May not be negative.
-*/
- public void setVgap( int newVgap )
- {
- if ( newVgap < 0 ) return; // may not be negative
- this.vgap = newVgap;
- updateGaps();
- this.revalidate();
- this.repaint();
+ /**
+ * Changes the vertical spacing between components in the panel. Note: Assumes
+ * listContainer uses a GridBagLayout.
+ *
+ * @param newVgap the new spacing, in pixels. May not be negative.
+ */
+ public void setVgap(int newVgap) {
+ if (newVgap < 0)
+ return; // may not be negative
+ this.vgap = newVgap;
+ updateGaps();
+ this.revalidate();
+ this.repaint();
- }
+ }
-/**
-* Gets the current vertical spacing between components.
-* @return the current vertical spacing, in pixels.
-*/
- public int getVgap()
- {
- return this.vgap;
- }
+ /**
+ * Gets the current vertical spacing between components.
+ *
+ * @return the current vertical spacing, in pixels.
+ */
+ public int getVgap() {
+ return this.vgap;
+ }
-/**
-* Sets the minimum width for the labels column.
-* This left margin will grow if one of the labels
-* is wider than this value.
-* Note: assumes GridBagLayout.
-* @param newMargin the new minimum margin in pixels. May not be negative.
-*/
- public void setMargin( int newMargin )
- {
- if ( newMargin < 0 ) return; // may not be negative
- this.margin = newMargin;
-
- if ( listContainer.getLayout() instanceof GridBagLayout )
- {
- GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
- GridBagConstraints constraints = null;
- Component c = null;
- int count = listContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = listContainer.getComponent( i );
- constraints = gridBag.getConstraints( c );
- if ( constraints.gridy == 0 && constraints.gridx % 2 == 0 )
- { // if this is a label spacer
- // replace it with an appropriately sized box
- listContainer.remove( c );
- listContainer.add( Box.createHorizontalStrut( this.margin ), constraints );
- }
- }
- }
-
- this.revalidate();
- this.repaint();
-
- }
+ /**
+ * Sets the minimum width for the labels column. This left margin will grow if
+ * one of the labels is wider than this value. Note: assumes GridBagLayout.
+ *
+ * @param newMargin the new minimum margin in pixels. May not be negative.
+ */
+ public void setMargin(int newMargin) {
+ if (newMargin < 0)
+ return; // may not be negative
+ this.margin = newMargin;
+
+ if (listContainer.getLayout() instanceof GridBagLayout) {
+ GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
+ GridBagConstraints constraints = null;
+ Component c = null;
+ int count = listContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = listContainer.getComponent(i);
+ constraints = gridBag.getConstraints(c);
+ if (constraints.gridy == 0 && constraints.gridx % 2 == 0) { // if this is a label spacer
+ // replace it with an appropriately sized
+ // box
+ listContainer.remove(c);
+ listContainer.add(Box.createHorizontalStrut(this.margin), constraints);
+ }
+ }
+ }
-/**
-* Gets the current minimum margin for the labels column.
-* @return the current minimum margin in pixels.
-*/
- public int getMargin()
- {
- return this.margin;
- }
+ this.revalidate();
+ this.repaint();
-/**
-* Sets the number of columns for the panel.
-* Label/Component pairs will start from the top left
-* and fill in to the right before wrapping to the
-* next row. The default number of columns is one.
-* Note: assumes GridBagLayout.
-* @param newColumns the new number of columns. May not be less than one.
-*/
- public void setColumns( int newColumns )
- {
- if ( newColumns < 1 ) return; // may not be less than one.
- int oldColumns = this.columns;
- this.columns = newColumns;
-
- if ( listContainer.getLayout() instanceof GridBagLayout )
- {
- GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
- int count = listContainer.getComponentCount();
- Component[] components = listContainer.getComponents();
- GridBagConstraints[] constraints = new GridBagConstraints[ components.length ];
- for ( int i = 0; i < components.length; i++ )
- {
- constraints[i] = gridBag.getConstraints( components[i] );
- }
- listContainer.removeAll();
- for ( int i = 0; i < components.length; i++ )
- {
- if ( constraints[i].gridy != 0 )
- { // ignore first row which is reserved for spacers.
-
- // translate component to new position
- // (columns*2 accounts for two grid columns for one "actual" column)
- int index = ( constraints[i].gridy - 1 ) * oldColumns*2 + constraints[i].gridx;
- constraints[i].gridy = ( index / (newColumns*2) ) + 1;
- constraints[i].gridx = index % (newColumns*2) ;
- listContainer.add( components[i], constraints[i] );
- }
- }
- createSpacers(); // replace the spacers
- updateGaps();
- }
-
- this.revalidate();
- this.repaint();
-
- }
+ }
-/**
-* Sets the vertical weight used for determining how to distribute additional
-* vertical space in the component.
-* @param aComponent Key that exists in the layout.
-* @return weighty The weight of the component, or -1.0 if not found.
-*/
- public double getVerticalWeightForKey( String key )
- {
- Container c = getCompositeComponentForKey( key );
- if ( c == null ) return -1.0;
- if ( ! ( listContainer.getLayout() instanceof GridBagLayout ) ) return -1.0;
- GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
- GridBagConstraints gbc = layout.getConstraints( c );
- return gbc.weighty;
- }
-
-/**
-* Sets the vertical weight used for determining how to distribute additional
-* vertical space in the component. By default, all weights are zero, so each
-* component gets its preferred height. If any weights are specified, then
-* additional space is allocated to those components proportionately.
-* @param aComponent Key that exists in the layout.
-* @param weighty The new weight.
-*/
- public void setVerticalWeightForKey( String key, double weighty )
- {
- Container c = getCompositeComponentForKey( key );
- if ( c == null ) return;
- if ( ! ( listContainer.getLayout() instanceof GridBagLayout ) ) return;
- GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
- GridBagConstraints gbc = layout.getConstraints( c );
- gbc.weighty = weighty;
- layout.setConstraints( c, gbc );
- // handle adding on-the-fly
- updateGaps();
- this.revalidate();
- this.repaint();
- }
-
-/**
-* Gets the current number of columns.
-* @return the current number of columns.
-*/
- public int getColumns()
- {
- return this.columns;
- }
+ /**
+ * Gets the current minimum margin for the labels column.
+ *
+ * @return the current minimum margin in pixels.
+ */
+ public int getMargin() {
+ return this.margin;
+ }
+
+ /**
+ * Sets the number of columns for the panel. Label/Component pairs will start
+ * from the top left and fill in to the right before wrapping to the next row.
+ * The default number of columns is one. Note: assumes GridBagLayout.
+ *
+ * @param newColumns the new number of columns. May not be less than one.
+ */
+ public void setColumns(int newColumns) {
+ if (newColumns < 1)
+ return; // may not be less than one.
+ int oldColumns = this.columns;
+ this.columns = newColumns;
+
+ if (listContainer.getLayout() instanceof GridBagLayout) {
+ GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
+ int count = listContainer.getComponentCount();
+ Component[] components = listContainer.getComponents();
+ GridBagConstraints[] constraints = new GridBagConstraints[components.length];
+ for (int i = 0; i < components.length; i++) {
+ constraints[i] = gridBag.getConstraints(components[i]);
+ }
+ listContainer.removeAll();
+ for (int i = 0; i < components.length; i++) {
+ if (constraints[i].gridy != 0) { // ignore first row which is reserved for spacers.
+
+ // translate component to new position
+ // (columns*2 accounts for two grid columns for one "actual" column)
+ int index = (constraints[i].gridy - 1) * oldColumns * 2 + constraints[i].gridx;
+ constraints[i].gridy = (index / (newColumns * 2)) + 1;
+ constraints[i].gridx = index % (newColumns * 2);
+ listContainer.add(components[i], constraints[i]);
+ }
+ }
+ createSpacers(); // replace the spacers
+ updateGaps();
+ }
+
+ this.revalidate();
+ this.repaint();
-/**
-* Appends a label containing a key and the specified component
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the component - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param component A component that will be placed next to the label.
-* If null, a blank JPanel will be used.
-*/
- public void addPair( String key, Component component )
- {
- addRow( key, new Component[] { component } );
}
-
-/**
-* Appends a label containing a key and the specified component
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the component - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param component A component that will be placed next to the label.
-* If null, a blank JPanel will appear.
-*/
- public void addRow( String key, Component component )
- {
- addRow( key, new Component[] { component } );
+
+ /**
+ * Sets the vertical weight used for determining how to distribute additional
+ * vertical space in the component.
+ *
+ * @param aComponent Key that exists in the layout.
+ * @return weighty The weight of the component, or -1.0 if not found.
+ */
+ public double getVerticalWeightForKey(String key) {
+ Container c = getCompositeComponentForKey(key);
+ if (c == null)
+ return -1.0;
+ if (!(listContainer.getLayout() instanceof GridBagLayout))
+ return -1.0;
+ GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
+ GridBagConstraints gbc = layout.getConstraints(c);
+ return gbc.weighty;
}
-
-/**
-* Appends a label containing a key and the specified components
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the component - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param components An array of components that will be placed next to the label.
-* Any nulls in the list will be replaced with blank JPanels.
-*/
- public void addRow(
- String key, Component[] components )
- {
- addCompositeComponent( key, makeCompositeComponent( key, components ) );
+
+ /**
+ * Sets the vertical weight used for determining how to distribute additional
+ * vertical space in the component. By default, all weights are zero, so each
+ * component gets its preferred height. If any weights are specified, then
+ * additional space is allocated to those components proportionately.
+ *
+ * @param aComponent Key that exists in the layout.
+ * @param weighty The new weight.
+ */
+ public void setVerticalWeightForKey(String key, double weighty) {
+ Container c = getCompositeComponentForKey(key);
+ if (c == null)
+ return;
+ if (!(listContainer.getLayout() instanceof GridBagLayout))
+ return;
+ GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
+ GridBagConstraints gbc = layout.getConstraints(c);
+ gbc.weighty = weighty;
+ layout.setConstraints(c, gbc);
+ // handle adding on-the-fly
+ updateGaps();
+ this.revalidate();
+ this.repaint();
}
-/**
-* Appends a label containing a key and the specified components
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the components - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param west A component that will appear to the left of the other components,
-* as wide as its preferred width and as tall as the tallest of the other components.
-* A null will be replaced with a blank JPanel.
-* @param center A component that will appear between the other components,
-* taking up available space.
-* A null will be replaced with a blank JPanel.
-* @param east A component that will appear to the right of the other components,
-* as wide as its preferred width and as tall as the tallest of the other components.
-* A null will be replaced with a blank JPanel.
-*/
- public void addRow(
- String key, Component west, Component center, Component east )
- {
- addCompositeComponent( key,
- makeCompositeComponent( key,
- west, center, east ) );
+ /**
+ * Gets the current number of columns.
+ *
+ * @return the current number of columns.
+ */
+ public int getColumns() {
+ return this.columns;
}
-/**
-* Appends a label containing a key and the specified components
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the components - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param west A component that will appear to the left of the other components,
-* as wide as its preferred width and as tall as the tallest of the other components.
-* A null will be replaced with a blank JPanel.
-* @param north A component that will appear above all the other components,
-* as tall as its preferred height and as wide as the info panel itself.
-* @param center A component that will appear between the other components,
-* taking up available space. A null will be replaced with a blank JPanel.
-* @param south A component that will appear below all the other components,
-* as tall as its preferred height and as wide as the info panel itself.
-* @param east A component that will appear to the right of the other components,
-* as wide as its preferred width and as tall as the tallest of the other components.
-* A null will be replaced with a blank JPanel.
-*/
- public void addRow(
- String key, Component west, Component north,
- Component center, Component south, Component east )
- {
- addCompositeComponent( key,
- makeCompositeComponent( key,
- west, north, center, south, east ) );
+ /**
+ * Appends a label containing a key and the specified component to the bottom of
+ * the panel. Any registered action listeners will receive action events from
+ * the component - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably
+ * unique.
+ * @param component A component that will be placed next to the label. If null,
+ * a blank JPanel will be used.
+ */
+ public void addPair(String key, Component component) {
+ addRow(key, new Component[] { component });
}
-/**
-* Produces a container that contains the specified components,
-* using GridLayout. Nulls are ignored.
-* This implementation returns a JPanel.
-*/
- protected Container makeCompositeComponent(
- String key, Component[] components )
- {
+ /**
+ * Appends a label containing a key and the specified component to the bottom of
+ * the panel. Any registered action listeners will receive action events from
+ * the component - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably
+ * unique.
+ * @param component A component that will be placed next to the label. If null,
+ * a blank JPanel will appear.
+ */
+ public void addRow(String key, Component component) {
+ addRow(key, new Component[] { component });
+ }
+
+ /**
+ * Appends a label containing a key and the specified components to the bottom
+ * of the panel. Any registered action listeners will receive action events from
+ * the component - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably
+ * unique.
+ * @param components An array of components that will be placed next to the
+ * label. Any nulls in the list will be replaced with blank
+ * JPanels.
+ */
+ public void addRow(String key, Component[] components) {
+ addCompositeComponent(key, makeCompositeComponent(key, components));
+ }
+
+ /**
+ * Appends a label containing a key and the specified components to the bottom
+ * of the panel. Any registered action listeners will receive action events from
+ * the components - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably unique.
+ * @param west A component that will appear to the left of the other
+ * components, as wide as its preferred width and as tall as the
+ * tallest of the other components. A null will be replaced with a
+ * blank JPanel.
+ * @param center A component that will appear between the other components,
+ * taking up available space. A null will be replaced with a blank
+ * JPanel.
+ * @param east A component that will appear to the right of the other
+ * components, as wide as its preferred width and as tall as the
+ * tallest of the other components. A null will be replaced with a
+ * blank JPanel.
+ */
+ public void addRow(String key, Component west, Component center, Component east) {
+ addCompositeComponent(key, makeCompositeComponent(key, west, center, east));
+ }
+
+ /**
+ * Appends a label containing a key and the specified components to the bottom
+ * of the panel. Any registered action listeners will receive action events from
+ * the components - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably unique.
+ * @param west A component that will appear to the left of the other
+ * components, as wide as its preferred width and as tall as the
+ * tallest of the other components. A null will be replaced with a
+ * blank JPanel.
+ * @param north A component that will appear above all the other components, as
+ * tall as its preferred height and as wide as the info panel
+ * itself.
+ * @param center A component that will appear between the other components,
+ * taking up available space. A null will be replaced with a blank
+ * JPanel.
+ * @param south A component that will appear below all the other components, as
+ * tall as its preferred height and as wide as the info panel
+ * itself.
+ * @param east A component that will appear to the right of the other
+ * components, as wide as its preferred width and as tall as the
+ * tallest of the other components. A null will be replaced with a
+ * blank JPanel.
+ */
+ public void addRow(String key, Component west, Component north, Component center, Component south, Component east) {
+ addCompositeComponent(key, makeCompositeComponent(key, west, north, center, south, east));
+ }
+
+ /**
+ * Produces a container that contains the specified components, using
+ * GridLayout. Nulls are ignored. This implementation returns a JPanel.
+ */
+ protected Container makeCompositeComponent(String key, Component[] components) {
JPanel panel = createPanel();
- if ( components.length != 0 )
- {
- panel.setLayout( new GridLayout( 1, components.length, hgap, vgap ) );
+ if (components.length != 0) {
+ panel.setLayout(new GridLayout(1, components.length, hgap, vgap));
Component c;
- for ( int i = 0; i < components.length; i++ )
- {
+ for (int i = 0; i < components.length; i++) {
c = components[i];
- if ( c != null )
- {
- introspectComponent( c, key );
- panel.add( c );
+ if (c != null) {
+ introspectComponent(c, key);
+ panel.add(c);
}
}
}
return panel;
}
-/**
-* Produces a container that contains the specified components,
-* using BorderLayout. Nulls are ignored.
-* This implementation returns a JPanel.
-*/
- protected Container makeCompositeComponent(
- String key, Component west, Component center, Component east )
- {
+ /**
+ * Produces a container that contains the specified components, using
+ * BorderLayout. Nulls are ignored. This implementation returns a JPanel.
+ */
+ protected Container makeCompositeComponent(String key, Component west, Component center, Component east) {
JPanel panel = createPanel();
- panel.setLayout( new BorderLayout( hgap, vgap ) );
+ panel.setLayout(new BorderLayout(hgap, vgap));
- if ( west != null )
- {
- introspectComponent( west, key );
- panel.add( west, BorderLayout.WEST );
+ if (west != null) {
+ introspectComponent(west, key);
+ panel.add(west, BorderLayout.WEST);
}
-
- if ( center != null )
- {
- introspectComponent( center, key );
- panel.add( center, BorderLayout.CENTER );
+
+ if (center != null) {
+ introspectComponent(center, key);
+ panel.add(center, BorderLayout.CENTER);
}
-
- if ( east != null )
- {
- introspectComponent( east, key );
- panel.add( east, BorderLayout.EAST );
+
+ if (east != null) {
+ introspectComponent(east, key);
+ panel.add(east, BorderLayout.EAST);
}
-
+
return panel;
}
-/**
-* Produces a container that contains the specified components,
-* using BorderLayout. Nulls are ignored.
-* This implementation returns a JPanel.
-*/
- protected Container makeCompositeComponent(
- String key, Component west, Component north,
- Component center, Component south, Component east )
- {
+ /**
+ * Produces a container that contains the specified components, using
+ * BorderLayout. Nulls are ignored. This implementation returns a JPanel.
+ */
+ protected Container makeCompositeComponent(String key, Component west, Component north, Component center,
+ Component south, Component east) {
JPanel panel = createPanel();
- panel.setLayout( new BorderLayout( hgap, vgap ) );
+ panel.setLayout(new BorderLayout(hgap, vgap));
- if ( west != null )
- {
- introspectComponent( west, key );
- panel.add( west, BorderLayout.WEST );
+ if (west != null) {
+ introspectComponent(west, key);
+ panel.add(west, BorderLayout.WEST);
}
-
- if ( north != null )
- {
- introspectComponent( north, key );
- panel.add( north, BorderLayout.WEST );
+
+ if (north != null) {
+ introspectComponent(north, key);
+ panel.add(north, BorderLayout.WEST);
}
-
- if ( center != null )
- {
- introspectComponent( center, key );
- panel.add( center, BorderLayout.CENTER );
+
+ if (center != null) {
+ introspectComponent(center, key);
+ panel.add(center, BorderLayout.CENTER);
}
-
- if ( south != null )
- {
- introspectComponent( south, key );
- panel.add( south, BorderLayout.CENTER );
+
+ if (south != null) {
+ introspectComponent(south, key);
+ panel.add(south, BorderLayout.CENTER);
}
-
- if ( east != null )
- {
- introspectComponent( east, key );
- panel.add( east, BorderLayout.EAST );
+
+ if (east != null) {
+ introspectComponent(east, key);
+ panel.add(east, BorderLayout.EAST);
}
-
+
return panel;
}
-/**
-* Override to return a specific component to be used
-* as a label. This implementation calls createLabel().
-*/
- protected Component createLabelForKey( String aKey )
- {
- return createLabel();
+ /**
+ * Override to return a specific component to be used as a label. This
+ * implementation calls createLabel().
+ */
+ protected Component createLabelForKey(String aKey) {
+ return createLabel();
}
-/**
-* Provided for backwards compatibility, and called by
-* the default implementation of createLabelForKey.
-* This implementation returns a JLabel.
-*/
- protected JLabel createLabel()
- {
- return new JLabel();
+ /**
+ * Provided for backwards compatibility, and called by the default
+ * implementation of createLabelForKey. This implementation returns a JLabel.
+ */
+ protected JLabel createLabel() {
+ return new JLabel();
}
-/**
-* Appends a label containing a key and the specified component
-* to the bottom of the panel. Any registered action listeners
-* will receive action events from the component - the key corresponding
-* to the component will be used as the action command.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param component A component that will be placed next to the label.
-* If null, a stock JTextField will be used.
-*/
- protected void addCompositeComponent( String key, Component component )
- {
- if ( key == null )
- {
- key = "";
- }
- Component label = createLabelForKey( key );
- Component field = component;
- if ( field == null )
- {
- field = new JTextField( 15 ); // default to 15 columns
- }
- field.setName( key ); // for association and reference
- label.setName( key ); // ditto
- if ( label instanceof JLabel )
- {
- ((JLabel)label).setHorizontalAlignment( labelAlign );
- ((JLabel)label).setLabelFor( field ); // for accessibility
- }
- if ( "".equals( key ) )
- {
- setText( label, "" );
- }
- else
- {
- setText( label, prefix + key + postfix );
- }
- field.setEnabled( this.isEditable ); // was: setEditable
-
- GridBagConstraints gbc = new GridBagConstraints();
-
- if ( listContainer.getComponentCount() == 0 )
- { // we've just initialized or called removeAll
- createSpacers();
- }
-
- gbc.gridx = ( fields.size() % this.columns ) * 2;
- gbc.gridy = ( fields.size() / this.columns ) + 1; // spacer is at index zero
- gbc.weightx = 0.0;
- gbc.weighty = 0.0;
- gbc.anchor = this.labelAnchor;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- listContainer.add( label, gbc );
+ /**
+ * Appends a label containing a key and the specified component to the bottom of
+ * the panel. Any registered action listeners will receive action events from
+ * the component - the key corresponding to the component will be used as the
+ * action command.
+ *
+ * @param key A string that will be displayed in a label, preferrably
+ * unique.
+ * @param component A component that will be placed next to the label. If null,
+ * a stock JTextField will be used.
+ */
+ protected void addCompositeComponent(String key, Component component) {
+ if (key == null) {
+ key = "";
+ }
+ Component label = createLabelForKey(key);
+ Component field = component;
+ if (field == null) {
+ field = new JTextField(15); // default to 15 columns
+ }
+ field.setName(key); // for association and reference
+ label.setName(key); // ditto
+ if (label instanceof JLabel) {
+ ((JLabel) label).setHorizontalAlignment(labelAlign);
+ ((JLabel) label).setLabelFor(field); // for accessibility
+ }
+ if ("".equals(key)) {
+ setText(label, "");
+ } else {
+ setText(label, prefix + key + postfix);
+ }
+ field.setEnabled(this.isEditable); // was: setEditable
+
+ GridBagConstraints gbc = new GridBagConstraints();
+
+ if (listContainer.getComponentCount() == 0) { // we've just initialized or called removeAll
+ createSpacers();
+ }
+
+ gbc.gridx = (fields.size() % this.columns) * 2;
+ gbc.gridy = (fields.size() / this.columns) + 1; // spacer is at index zero
+ gbc.weightx = 0.0;
+ gbc.weighty = 0.0;
+ gbc.anchor = this.labelAnchor;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ listContainer.add(label, gbc);
gbc.fill = GridBagConstraints.BOTH;
- gbc.gridx = gbc.gridx + 1;
- //FIXME: components default to the labelAnchor - should be different?
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
-
- listContainer.add( field, gbc );
-
- if ( key.equals( HIDDEN ) )
- { // these components are not to be shown
- setText( label, " " );
- field.setVisible( false );
- }
-
- fields.add( field ); // using list not map to allow for duplicate keys
- labels.add( label ); // ditto
-
- // handle adding on-the-fly
- updateGaps();
- this.revalidate();
- this.repaint();
- }
+ gbc.gridx = gbc.gridx + 1;
+ // FIXME: components default to the labelAnchor - should be different?
+ gbc.weightx = 1.0;
+ gbc.weighty = 0.0;
-/**
-* Introspects a component to set the action command and to add the
-* InfoPanel to its list of ActionListeners.
-* @param aComponent The Component to be introspected.
-* @param aKey The action command to be set.
-*/
- protected void introspectComponent( Component aComponent, String aKey )
- {
- // try to set properties of whatever component this might be
- try {
- Method [] methods =
- (Method []) _method_cache.get( aComponent.getClass() );
- if (methods == null) {
- Class componentClass = aComponent.getClass();
- BeanInfo info =
- Introspector.getBeanInfo( componentClass );
-
- MethodDescriptor[] descriptors =
- info.getMethodDescriptors();
- Method setMethod = null;
- Method addMethod = null;
- for ( int i = 0;
- ((setMethod == null || addMethod == null) &&
- i < descriptors.length);
- i++ )
- {
- Method m = descriptors[i].getMethod();
- String name = m.getName ();
- if ( setMethod == null &&
- name.equals( "setActionCommand" ) )
- {
- setMethod = m;
- }
- else if ( addMethod == null &&
- name.equals( "addActionListener" ) )
- {
- addMethod = m;
- }
- }
-
- methods = new Method [] {setMethod, addMethod};
- _method_cache.put (componentClass, methods);
- }
- if (methods [0] != null) {
- methods [0].invoke( aComponent, new Object[] { aKey } );
- }
- if (methods [1] != null) {
- methods [1].invoke( aComponent, new Object[] { this } );
- listenedToComponents.add( aComponent );
- }
- }
- catch ( Exception exc )
- { // error occured while introspecting... move along.
- System.out.println( "InfoPanel.introspectComponent: " + exc );
- }
- }
-
-/**
-* Called to populate a label component with the specified text.
-* This implementation attempts to call setText(String) on the component.
-* Override to customize.
-*/
- protected void setText( Component c, String text )
- {
- try
- {
- Method m = c.getClass().getMethod( "setText", new Class[] { String.class } );
- if ( m != null )
- {
- m.invoke( c, new Object[] { text } );
- }
- }
- catch ( Exception exc )
- {
- // no such method: ignore
- }
- }
+ listContainer.add(field, gbc);
-/**
-* Creates spacer components on the reserved first grid row
-* for each column of labels and fields.
-* This allows us to set the margin for those label columns,
-* and set the preferred width of the field columns.
-* A list containing the field spacers should be assigned to
-* the fieldSpacers instance variable.
-*/
- private void createSpacers()
- {
- if ( listContainer.getLayout() instanceof GridBagLayout )
- {
- // insert spacers for labels column
- GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
- GridBagConstraints constraints = new GridBagConstraints();
- constraints.gridy = 0;
- constraints.fill = GridBagConstraints.HORIZONTAL;
-
- fieldSpacers = new LinkedList();
- Component fieldSpacer;
- for ( int i = 0; i < this.columns; i++ )
- {
- constraints.gridx = i * 2;
- listContainer.add( Box.createHorizontalStrut( this.margin ), constraints );
-
- constraints.gridx = i * 2 + 1;
- fieldSpacer = Box.createHorizontalStrut( 0 );
- fieldSpacers.add( fieldSpacer );
- listContainer.add( fieldSpacer, constraints );
- }
- }
- }
+ if (key.equals(HIDDEN)) { // these components are not to be shown
+ setText(label, " ");
+ field.setVisible(false);
+ }
-/**
-* Updates the insets for all components.
-*/
- protected void updateGaps()
- {
- if ( listContainer.getLayout() instanceof GridBagLayout )
- {
- GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
- Component c = null;
- GridBagConstraints gbc = null;
- double totalWeightY = 0.0;
- int count = listContainer.getComponentCount();
- int i;
- for ( i = 0; i < count; i++ )
- {
- c = listContainer.getComponent( i );
- gbc = layout.getConstraints( c );
- totalWeightY += gbc.weighty;
- if ( (gbc.gridx + 1) % ( this.columns * 2 ) == 0 )
- { // if last component in row
- gbc.insets = new Insets( 0, 0, this.vgap, 0 );
- }
- else
- {
- if ( gbc.gridx % 2 == 0 )
- { // is a label column - NOTE: uses eleven pixels before component, per l&f guide
- gbc.insets = new Insets( 0, 0, this.vgap, 11 );
- }
- else
- { // is a component column
- if ( gbc.gridy != 0 )
- {
- if ( c instanceof JPanel ) ((JPanel)c).setPreferredSize( null );
- gbc.insets = new Insets( 0, 0, this.vgap, this.hgap );
- }
- }
- }
- layout.setConstraints( c, gbc );
- }
-
- //hack: gridbag clumps components in center if weighty is zero
- // if sum of weighty is zero, top-justify the list container
- this.remove( listContainer );
- if ( totalWeightY == 0.0 )
- {
- this.add( listContainer, BorderLayout.NORTH );
- }
- else // put list container in center so it will grow
- {
- this.add( listContainer, BorderLayout.CENTER );
- }
- }
- }
+ fields.add(field); // using list not map to allow for duplicate keys
+ labels.add(label); // ditto
-/**
-* Updates the label alignment.
-*/
- protected void updateLabels()
- {
- if ( listContainer.getLayout() instanceof GridBagLayout )
- {
- GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
- Component c = null;
- GridBagConstraints gbc = null;
+ // handle adding on-the-fly
+ updateGaps();
+ this.revalidate();
+ this.repaint();
+ }
+
+ /**
+ * Introspects a component to set the action command and to add the InfoPanel to
+ * its list of ActionListeners.
+ *
+ * @param aComponent The Component to be introspected.
+ * @param aKey The action command to be set.
+ */
+ protected void introspectComponent(Component aComponent, String aKey) {
+ // try to set properties of whatever component this might be
+ try {
+ Method[] methods = (Method[]) _method_cache.get(aComponent.getClass());
+ if (methods == null) {
+ Class componentClass = aComponent.getClass();
+ BeanInfo info = Introspector.getBeanInfo(componentClass);
+
+ MethodDescriptor[] descriptors = info.getMethodDescriptors();
+ Method setMethod = null;
+ Method addMethod = null;
+ for (int i = 0; ((setMethod == null || addMethod == null) && i < descriptors.length); i++) {
+ Method m = descriptors[i].getMethod();
+ String name = m.getName();
+ if (setMethod == null && name.equals("setActionCommand")) {
+ setMethod = m;
+ } else if (addMethod == null && name.equals("addActionListener")) {
+ addMethod = m;
+ }
+ }
+
+ methods = new Method[] { setMethod, addMethod };
+ _method_cache.put(componentClass, methods);
+ }
+ if (methods[0] != null) {
+ methods[0].invoke(aComponent, new Object[] { aKey });
+ }
+ if (methods[1] != null) {
+ methods[1].invoke(aComponent, new Object[] { this });
+ listenedToComponents.add(aComponent);
+ }
+ } catch (Exception exc) { // error occured while introspecting... move along.
+ System.out.println("InfoPanel.introspectComponent: " + exc);
+ }
+ }
+
+ /**
+ * Called to populate a label component with the specified text. This
+ * implementation attempts to call setText(String) on the component. Override to
+ * customize.
+ */
+ protected void setText(Component c, String text) {
+ try {
+ Method m = c.getClass().getMethod("setText", new Class[] { String.class });
+ if (m != null) {
+ m.invoke(c, new Object[] { text });
+ }
+ } catch (Exception exc) {
+ // no such method: ignore
+ }
+ }
+
+ /**
+ * Creates spacer components on the reserved first grid row for each column of
+ * labels and fields. This allows us to set the margin for those label columns,
+ * and set the preferred width of the field columns. A list containing the field
+ * spacers should be assigned to the fieldSpacers instance variable.
+ */
+ private void createSpacers() {
+ if (listContainer.getLayout() instanceof GridBagLayout) {
+ // insert spacers for labels column
+ GridBagLayout gridBag = (GridBagLayout) listContainer.getLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.gridy = 0;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+
+ fieldSpacers = new LinkedList();
+ Component fieldSpacer;
+ for (int i = 0; i < this.columns; i++) {
+ constraints.gridx = i * 2;
+ listContainer.add(Box.createHorizontalStrut(this.margin), constraints);
+
+ constraints.gridx = i * 2 + 1;
+ fieldSpacer = Box.createHorizontalStrut(0);
+ fieldSpacers.add(fieldSpacer);
+ listContainer.add(fieldSpacer, constraints);
+ }
+ }
+ }
+
+ /**
+ * Updates the insets for all components.
+ */
+ protected void updateGaps() {
+ if (listContainer.getLayout() instanceof GridBagLayout) {
+ GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
+ Component c = null;
+ GridBagConstraints gbc = null;
+ double totalWeightY = 0.0;
+ int count = listContainer.getComponentCount();
+ int i;
+ for (i = 0; i < count; i++) {
+ c = listContainer.getComponent(i);
+ gbc = layout.getConstraints(c);
+ totalWeightY += gbc.weighty;
+ if ((gbc.gridx + 1) % (this.columns * 2) == 0) { // if last component in row
+ gbc.insets = new Insets(0, 0, this.vgap, 0);
+ } else {
+ if (gbc.gridx % 2 == 0) { // is a label column - NOTE: uses eleven pixels before component, per l&f
+ // guide
+ gbc.insets = new Insets(0, 0, this.vgap, 11);
+ } else { // is a component column
+ if (gbc.gridy != 0) {
+ if (c instanceof JPanel)
+ ((JPanel) c).setPreferredSize(null);
+ gbc.insets = new Insets(0, 0, this.vgap, this.hgap);
+ }
+ }
+ }
+ layout.setConstraints(c, gbc);
+ }
+
+ // hack: gridbag clumps components in center if weighty is zero
+ // if sum of weighty is zero, top-justify the list container
+ this.remove(listContainer);
+ if (totalWeightY == 0.0) {
+ this.add(listContainer, BorderLayout.NORTH);
+ } else // put list container in center so it will grow
+ {
+ this.add(listContainer, BorderLayout.CENTER);
+ }
+ }
+ }
+
+ /**
+ * Updates the label alignment.
+ */
+ protected void updateLabels() {
+ if (listContainer.getLayout() instanceof GridBagLayout) {
+ GridBagLayout layout = (GridBagLayout) listContainer.getLayout();
+ Component c = null;
+ GridBagConstraints gbc = null;
Iterator it = labels.iterator();
- while ( it.hasNext() )
- {
- c = (Component) it.next();
- if ( c instanceof JLabel )
- {
- ((JLabel)c).setHorizontalAlignment( labelAlign );
- }
- gbc = layout.getConstraints( c );
- gbc.anchor = this.labelAnchor;
- layout.setConstraints( c, gbc );
- }
- }
- }
+ while (it.hasNext()) {
+ c = (Component) it.next();
+ if (c instanceof JLabel) {
+ ((JLabel) c).setHorizontalAlignment(labelAlign);
+ }
+ gbc = layout.getConstraints(c);
+ gbc.anchor = this.labelAnchor;
+ layout.setConstraints(c, gbc);
+ }
+ }
+ }
-/**
-* Convenience method that uses a stock JTextField.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param value A string that will be displayed in a textfield.
-*/
- public void addPair( String key, String value )
- {
- addPair( key, value, null );
- }
+ /**
+ * Convenience method that uses a stock JTextField.
+ *
+ * @param key A string that will be displayed in a label, preferrably unique.
+ * @param value A string that will be displayed in a textfield.
+ */
+ public void addPair(String key, String value) {
+ addPair(key, value, null);
+ }
-/**
-* Convenience method that uses the specified JTextField or subclass
-* and sets it to the specified value.
-* @param key A string that will be displayed in a label, preferrably unique.
-* @param value A string that will be displayed in a textfield.
-* @param textField A JTextField or subclass that will be used to display the value.
-* If null, a stock JTextField will be used.
-*/
- public void addPair( String key, String value, JTextField textField )
- {
- if ( value == null )
- {
- value = "";
- }
- JTextField field = textField;
- if ( field == null )
- {
- field = new JTextField( 15 ); // default to 15 columns
- }
- else
- {
- field = textField;
- }
- field.setText( value );
-
- addPair( key, (Component) field );
- }
+ /**
+ * Convenience method that uses the specified JTextField or subclass and sets it
+ * to the specified value.
+ *
+ * @param key A string that will be displayed in a label, preferrably
+ * unique.
+ * @param value A string that will be displayed in a textfield.
+ * @param textField A JTextField or subclass that will be used to display the
+ * value. If null, a stock JTextField will be used.
+ */
+ public void addPair(String key, String value, JTextField textField) {
+ if (value == null) {
+ value = "";
+ }
+ JTextField field = textField;
+ if (field == null) {
+ field = new JTextField(15); // default to 15 columns
+ } else {
+ field = textField;
+ }
+ field.setText(value);
-/**
-* Removes all components from the list. Buttons, if any,
-* will remain unchanged - use setButtons( null ) to remove
-* them. NOTE: does not call super.removeAll().
-*/
- public void removeAll()
- {
- Object component;
- Method method;
- Class[] paramClasses = new Class[] { ActionListener.class };
- Object[] paramObjects = new Object[] { this };
-
- Iterator iterator = listenedToComponents.iterator();
- while ( iterator.hasNext() )
- {
- component = iterator.next();
- try
- {
- method = component.getClass().getMethod( "removeActionListener", paramClasses );
- if ( method != null )
- {
- method.invoke( component, paramObjects );
- }
- }
- catch ( Exception exception )
- {
- // No removeActionListener() method, move along.
- }
- }
-
- listenedToComponents.clear();
-
- listContainer.removeAll();
- fields.clear();
- labels.clear();
- this.revalidate();
- this.repaint();
-
- //FIXME: It is very confusing that this
- // implementation does not call super.removeAll().
- }
+ addPair(key, (Component) field);
+ }
-/**
-* Adds one or buttons to the bottom of the panel with the specified labels
-* from left to right. Any action listeners will receive action events
-* from clicks on these buttons - the supplied label will be used as the action command.
-* @param buttons A string array containing the strings to be used for the button labels
-* and action commands. A null value will remove the button panel.
-* @see ButtonPanel
-*/
- public void setButtons( String[] buttons )
- {
- if ( buttonPanel == null )
- {
- buttonPanel = new ButtonPanel();
- buttonPanel.setInsets( new Insets( 6, 0, 0, 0 ) );
- // button panel has a 11-pixel top inset
- // and java l&f guide says 17-pixels before command buttons
- buttonPanel.addActionListener( this );
- this.add( buttonPanel, BorderLayout.SOUTH );
- }
- if ( buttons == null )
- {
- this.remove( buttonPanel );
- buttonPanel = null;
- }
- else
- {
- buttonPanel.setLabels( buttons );
- }
-
- this.revalidate();
- this.repaint();
- }
- protected Collection listenedToComponents = new LinkedList();
+ /**
+ * Removes all components from the list. Buttons, if any, will remain unchanged
+ * - use setButtons( null ) to remove them. NOTE: does not call
+ * super.removeAll().
+ */
+ public void removeAll() {
+ Object component;
+ Method method;
+ Class[] paramClasses = new Class[] { ActionListener.class };
+ Object[] paramObjects = new Object[] { this };
+
+ Iterator iterator = listenedToComponents.iterator();
+ while (iterator.hasNext()) {
+ component = iterator.next();
+ try {
+ method = component.getClass().getMethod("removeActionListener", paramClasses);
+ if (method != null) {
+ method.invoke(component, paramObjects);
+ }
+ } catch (Exception exception) {
+ // No removeActionListener() method, move along.
+ }
+ }
-/**
-* Retrieves the names of the buttons that are displayed, if any.
-* @return A string array containing the strings used for the button labels
-* and action commands, or null if no buttons have been created.
-* @see ButtonPanel
-*/
- public String[] getButtons()
- {
- if ( buttonPanel == null )
- {
- return null; // none created
- }
+ listenedToComponents.clear();
- return buttonPanel.getLabels();
- }
+ listContainer.removeAll();
+ fields.clear();
+ labels.clear();
+ this.revalidate();
+ this.repaint();
-/**
-* Retrieves the actual button panel, if any.
-* @return A button panel, or null if none has been created.
-* @see ButtonPanel
-*/
- public ButtonPanel getButtonPanel()
- {
- return buttonPanel;
- }
+ // FIXME: It is very confusing that this
+ // implementation does not call super.removeAll().
+ }
+ /**
+ * Adds one or buttons to the bottom of the panel with the specified labels from
+ * left to right. Any action listeners will receive action events from clicks on
+ * these buttons - the supplied label will be used as the action command.
+ *
+ * @param buttons A string array containing the strings to be used for the
+ * button labels and action commands. A null value will remove
+ * the button panel.
+ * @see ButtonPanel
+ */
+ public void setButtons(String[] buttons) {
+ if (buttonPanel == null) {
+ buttonPanel = new ButtonPanel();
+ buttonPanel.setInsets(new Insets(6, 0, 0, 0));
+ // button panel has a 11-pixel top inset
+ // and java l&f guide says 17-pixels before command buttons
+ buttonPanel.addActionListener(this);
+ this.add(buttonPanel, BorderLayout.SOUTH);
+ }
+ if (buttons == null) {
+ this.remove(buttonPanel);
+ buttonPanel = null;
+ } else {
+ buttonPanel.setLabels(buttons);
+ }
-/**
-* Sets whether the values displayed in the panel should be editable. Defaults to true.
-* @param isEditable Whether the values should be editable.
-*/
- public void setEditable( boolean isEditable )
- {
- this.isEditable = isEditable;
- Iterator enumeration = fields.iterator();
- while ( enumeration.hasNext() )
- {
- ( (Component) enumeration.next() ).setEnabled( isEditable );
- }
- }
+ this.revalidate();
+ this.repaint();
+ }
-/**
-* Gets whether the values displayed in the panel are editable.
-* @return Whether the values should be editable.
-*/
- public boolean isEditable()
- {
- return this.isEditable;
- }
+ protected Collection listenedToComponents = new LinkedList();
+
+ /**
+ * Retrieves the names of the buttons that are displayed, if any.
+ *
+ * @return A string array containing the strings used for the button labels and
+ * action commands, or null if no buttons have been created.
+ * @see ButtonPanel
+ */
+ public String[] getButtons() {
+ if (buttonPanel == null) {
+ return null; // none created
+ }
-/**
-* Sets the field associated with the key to the specified value.
-* Note: If the component does not respond to setText() or setString()
-* or setValue() the value will not be set. JTextFields and the like will work.
-* @param key A string representing the key associated with the field. Nulls are converted to an empty string.
-* @param value A object to be displayed in the specified field. Nulls are converted to an empty string.
-*/
- public void setValueForKey( String key, Object value )
- {
- setValueForKey( key, value, 0 );
+ return buttonPanel.getLabels();
}
-
-/**
-* Sets the field associated with the key to the specified value.
-* Note: If the component does not respond to setText() or setString()
-* or setValue() the value will not be set. JTextFields and the like will work.
-* @param key A string representing the key associated with the field. Nulls are converted to an empty string.
-* @param value A object to be displayed in the specified field. Nulls are converted to an empty string.
-*/
- public void setValueForKey( String key, Object value, int index )
- {
- if ( key == null )
- {
- key = "";
- }
-
- Container field = null;
- for ( int i = 0; i < fields.size(); i++ )
- {
- field = (Container) fields.get(i);
- if ( key.equals( field.getName() ) )
- {
- setValueForIndex( index, i, value );
+
+ /**
+ * Retrieves the actual button panel, if any.
+ *
+ * @return A button panel, or null if none has been created.
+ * @see ButtonPanel
+ */
+ public ButtonPanel getButtonPanel() {
+ return buttonPanel;
+ }
+
+ /**
+ * Sets whether the values displayed in the panel should be editable. Defaults
+ * to true.
+ *
+ * @param isEditable Whether the values should be editable.
+ */
+ public void setEditable(boolean isEditable) {
+ this.isEditable = isEditable;
+ Iterator enumeration = fields.iterator();
+ while (enumeration.hasNext()) {
+ ((Component) enumeration.next()).setEnabled(isEditable);
+ }
+ }
+
+ /**
+ * Gets whether the values displayed in the panel are editable.
+ *
+ * @return Whether the values should be editable.
+ */
+ public boolean isEditable() {
+ return this.isEditable;
+ }
+
+ /**
+ * Sets the field associated with the key to the specified value. Note: If the
+ * component does not respond to setText() or setString() or setValue() the
+ * value will not be set. JTextFields and the like will work.
+ *
+ * @param key A string representing the key associated with the field. Nulls
+ * are converted to an empty string.
+ * @param value A object to be displayed in the specified field. Nulls are
+ * converted to an empty string.
+ */
+ public void setValueForKey(String key, Object value) {
+ setValueForKey(key, value, 0);
+ }
+
+ /**
+ * Sets the field associated with the key to the specified value. Note: If the
+ * component does not respond to setText() or setString() or setValue() the
+ * value will not be set. JTextFields and the like will work.
+ *
+ * @param key A string representing the key associated with the field. Nulls
+ * are converted to an empty string.
+ * @param value A object to be displayed in the specified field. Nulls are
+ * converted to an empty string.
+ */
+ public void setValueForKey(String key, Object value, int index) {
+ if (key == null) {
+ key = "";
+ }
+
+ Container field = null;
+ for (int i = 0; i < fields.size(); i++) {
+ field = (Container) fields.get(i);
+ if (key.equals(field.getName())) {
+ setValueForIndex(index, i, value);
return;
- }
+ }
}
- // else not found - ignore
- }
-
-/**
-* Sets the first field at the specified row index to the specified value.
-* Note: If the component does not respond to setText() or setString()
-* or setValue() the value will not be set. JTextFields and the like will work.
-* @param row The row index of the component.
-* @param value A object to be displayed in the specified field.
-* Nulls are converted to an empty string.
-*/
- public void setValueForIndex( int row, Object value )
- {
- setValueForIndex( row, 0, value );
+ // else not found - ignore
}
-
-/**
-* Sets the field at the specified row index and column index to the specified value.
-* Note: If the component does not respond to setText() or setString()
-* or setValue() the value will not be set. JTextFields and the like will work.
-* @param row The row index of the component.
-* @param index The column index of the component.
-* @param value A object to be displayed in the specified field.
-* Nulls are converted to an empty string.
-*/
- public void setValueForIndex( int row, int col, Object value )
- {
- Container field = (Container) fields.get( row );
- Component c = field.getComponent( col );
- setValueForComponent( c, value );
+
+ /**
+ * Sets the first field at the specified row index to the specified value. Note:
+ * If the component does not respond to setText() or setString() or setValue()
+ * the value will not be set. JTextFields and the like will work.
+ *
+ * @param row The row index of the component.
+ * @param value A object to be displayed in the specified field. Nulls are
+ * converted to an empty string.
+ */
+ public void setValueForIndex(int row, Object value) {
+ setValueForIndex(row, 0, value);
}
-
+ /**
+ * Sets the field at the specified row index and column index to the specified
+ * value. Note: If the component does not respond to setText() or setString() or
+ * setValue() the value will not be set. JTextFields and the like will work.
+ *
+ * @param row The row index of the component.
+ * @param index The column index of the component.
+ * @param value A object to be displayed in the specified field. Nulls are
+ * converted to an empty string.
+ */
+ public void setValueForIndex(int row, int col, Object value) {
+ Container field = (Container) fields.get(row);
+ Component c = field.getComponent(col);
+ setValueForComponent(c, value);
+ }
-/**
-* Sets the value in the field at the specified index.
-* Note: If the component does not respond to setText() or setString()
-* or setValue() this method will return null. JTextFields and the like will work.
-* @param A valid index.
-* @param value A object to be displayed in the specified field.
-*/
- protected void setValueForComponent( Component aComponent, Object value )
- {
- // try to set a text or string property
- try {
- BeanInfo info = Introspector.getBeanInfo( aComponent.getClass() );
- MethodDescriptor[] methods = info.getMethodDescriptors();
- for ( int i = 0; i < methods.length; i++ )
- {
- Method m = methods[i].getMethod();
- Class[] paramTypes = m.getParameterTypes();
- if ( paramTypes.length == 1 )
- {
- if ( m.getName().equals( "setText" ) )
- {
- if ( paramTypes[0].getName().equals( String.class.getName() ) )
- {
- m.invoke( aComponent, new Object[] { value } );
- }
- }
- if ( m.getName().equals( "setString" ) )
- {
- if ( paramTypes[0].getName().equals( String.class.getName() ) )
- {
- m.invoke( aComponent, new Object[] { value } );
- }
- }
- if ( m.getName().equals( "setValue" ) )
- {
- if ( paramTypes[0].getName().equals( Object.class.getName() ) )
- {
- m.invoke( aComponent, new Object[] { value } );
- }
- }
- }
- }
- }
- catch ( Exception exc )
- { // error occured while introspecting... move along.
- // FIXME: should log error in ErrorManager
- System.out.println( "InfoPanel.setValueForComponent: " + exc );
- }
- }
+ /**
+ * Sets the value in the field at the specified index. Note: If the component
+ * does not respond to setText() or setString() or setValue() this method will
+ * return null. JTextFields and the like will work.
+ *
+ * @param A valid index.
+ * @param value A object to be displayed in the specified field.
+ */
+ protected void setValueForComponent(Component aComponent, Object value) {
+ // try to set a text or string property
+ try {
+ BeanInfo info = Introspector.getBeanInfo(aComponent.getClass());
+ MethodDescriptor[] methods = info.getMethodDescriptors();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i].getMethod();
+ Class[] paramTypes = m.getParameterTypes();
+ if (paramTypes.length == 1) {
+ if (m.getName().equals("setText")) {
+ if (paramTypes[0].getName().equals(String.class.getName())) {
+ m.invoke(aComponent, new Object[] { value });
+ }
+ }
+ if (m.getName().equals("setString")) {
+ if (paramTypes[0].getName().equals(String.class.getName())) {
+ m.invoke(aComponent, new Object[] { value });
+ }
+ }
+ if (m.getName().equals("setValue")) {
+ if (paramTypes[0].getName().equals(Object.class.getName())) {
+ m.invoke(aComponent, new Object[] { value });
+ }
+ }
+ }
+ }
+ } catch (Exception exc) { // error occured while introspecting... move along.
+ // FIXME: should log error in ErrorManager
+ System.out.println("InfoPanel.setValueForComponent: " + exc);
+ }
+ }
-/**
-* Gets the value in the field at the specified index.
-* Note: If the component does not respond to getText() or getString()
-* or getSelectedItem() this method will return null. JTextFields and the like will work.
-* @param A valid index.
-* @return An object representing the value in the field at the specified index,
-* or null if the component does not have a text property or if the index is out of bounds.
-*/
- public Object getValueForIndex( int anIndex )
- {
- return getValueForIndex( anIndex, 0 );
- }
+ /**
+ * Gets the value in the field at the specified index. Note: If the component
+ * does not respond to getText() or getString() or getSelectedItem() this method
+ * will return null. JTextFields and the like will work.
+ *
+ * @param A valid index.
+ * @return An object representing the value in the field at the specified index,
+ * or null if the component does not have a text property or if the
+ * index is out of bounds.
+ */
+ public Object getValueForIndex(int anIndex) {
+ return getValueForIndex(anIndex, 0);
+ }
-/**
-* Gets the value in the field at the specified row and column.
-* Note: If the component does not respond to getText() or getString()
-* or getSelectedItem() this method will return null. JTextFields and the like will work.
-* @param A valid index.
-* @return An object representing the value in the field at the specified index,
-* or null if the component does not have a text property or if the index is out of bounds.
-*/
- public Object getValueForIndex( int row, int col )
- {
- if ( ( row >= fields.size() ) || ( row < 0 ) )
- { // out of bounds
- return null;
- }
-
- Container field = (Container) fields.get( row );
- Component c = field.getComponent( col );
- return getValueForComponent( c );
- }
+ /**
+ * Gets the value in the field at the specified row and column. Note: If the
+ * component does not respond to getText() or getString() or getSelectedItem()
+ * this method will return null. JTextFields and the like will work.
+ *
+ * @param A valid index.
+ * @return An object representing the value in the field at the specified index,
+ * or null if the component does not have a text property or if the
+ * index is out of bounds.
+ */
+ public Object getValueForIndex(int row, int col) {
+ if ((row >= fields.size()) || (row < 0)) { // out of bounds
+ return null;
+ }
-/**
-* Gets the value in the field associated with the key.
-* Note: If the component does not respond to getText() or getString()
-* or getSelectedItem() this method will return null. JTextFields and the like will work.
-* @param key An string representing the key associated with the field. Nulls are converted to an empty string.
-* @return An object representing the value in the field associated with the key,
-* or null if the key does not exist or if the component does not have a text property.
-*/
- public Object getValueForKey( String key )
- {
- return getValueForKey( key, 0 );
+ Container field = (Container) fields.get(row);
+ Component c = field.getComponent(col);
+ return getValueForComponent(c);
}
-/**
-* Gets the value in the field associated with the key.
-* Note: If the component does not respond to getText() or getString()
-* or getSelectedItem() this method will return null. JTextFields and the like will work.
-* @param key An string representing the key associated with the field. Nulls are converted to an empty string.
-* @return An object representing the value in the field associated with the key,
-* or null if the key does not exist or if the component does not have a text property.
-*/
- public Object getValueForKey( String key, int index )
- {
- if ( key == null )
- {
- key = "";
- }
-
- Container field = null;
- Iterator enumeration = fields.iterator();
- while ( enumeration.hasNext() )
- { // finds first value in list with specified key
- field = (Container) enumeration.next();
- if ( key.equals( field.getName() ) )
- {
- Component c = field.getComponent( index );
- if ( c != null )
- {
- return getValueForComponent( c );
+ /**
+ * Gets the value in the field associated with the key. Note: If the component
+ * does not respond to getText() or getString() or getSelectedItem() this method
+ * will return null. JTextFields and the like will work.
+ *
+ * @param key An string representing the key associated with the field. Nulls
+ * are converted to an empty string.
+ * @return An object representing the value in the field associated with the
+ * key, or null if the key does not exist or if the component does not
+ * have a text property.
+ */
+ public Object getValueForKey(String key) {
+ return getValueForKey(key, 0);
+ }
+
+ /**
+ * Gets the value in the field associated with the key. Note: If the component
+ * does not respond to getText() or getString() or getSelectedItem() this method
+ * will return null. JTextFields and the like will work.
+ *
+ * @param key An string representing the key associated with the field. Nulls
+ * are converted to an empty string.
+ * @return An object representing the value in the field associated with the
+ * key, or null if the key does not exist or if the component does not
+ * have a text property.
+ */
+ public Object getValueForKey(String key, int index) {
+ if (key == null) {
+ key = "";
+ }
+
+ Container field = null;
+ Iterator enumeration = fields.iterator();
+ while (enumeration.hasNext()) { // finds first value in list with specified key
+ field = (Container) enumeration.next();
+ if (key.equals(field.getName())) {
+ Component c = field.getComponent(index);
+ if (c != null) {
+ return getValueForComponent(c);
}
- }
- }
- // else not found
- return null;
- }
+ }
+ }
+ // else not found
+ return null;
+ }
-/**
-* Gets the value in the specified component.
-* Note: If the component does not respond to getText() or getString()
-* or getSelectedItem() this method will return null. JTextFields and the like will work.
-* @param aComponent The specified component.
-* @return An object representing the value in the component.
-* or null if the component does not have a text property.
-*/
- protected Object getValueForComponent( Component aComponent )
- {
- // try to get a text or string property
- try
- {
- BeanInfo info = Introspector.getBeanInfo( aComponent.getClass() );
- MethodDescriptor[] methods = info.getMethodDescriptors();
- for ( int i = 0; i < methods.length; i++ )
- {
- Method m = methods[i].getMethod();
- Class[] paramTypes = m.getParameterTypes();
- if ( m.getName().equals( "getText" ) )
- {
- if ( paramTypes.length == 0 )
- {
- return m.invoke( aComponent, new Object[] {} );
- }
- }
- if ( m.getName().equals( "getString" ) )
- {
- if ( paramTypes.length == 0 )
- {
- return m.invoke( aComponent, new Object[] {} );
- }
- }
- if ( m.getName().equals( "getSelectedItem" ) )
- {
- if ( paramTypes.length == 0 )
- {
- return m.invoke( aComponent, new Object[] {} );
- }
- }
- // TODO: should also handle variants of setValue()
- }
- }
- catch ( Exception exc )
- { // error occured while introspecting... move along.
- System.out.println( "InfoPanel.getValueFromComponent: " + exc );
- }
-
- // not found
- return null;
- }
+ /**
+ * Gets the value in the specified component. Note: If the component does not
+ * respond to getText() or getString() or getSelectedItem() this method will
+ * return null. JTextFields and the like will work.
+ *
+ * @param aComponent The specified component.
+ * @return An object representing the value in the component. or null if the
+ * component does not have a text property.
+ */
+ protected Object getValueForComponent(Component aComponent) {
+ // try to get a text or string property
+ try {
+ BeanInfo info = Introspector.getBeanInfo(aComponent.getClass());
+ MethodDescriptor[] methods = info.getMethodDescriptors();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i].getMethod();
+ Class[] paramTypes = m.getParameterTypes();
+ if (m.getName().equals("getText")) {
+ if (paramTypes.length == 0) {
+ return m.invoke(aComponent, new Object[] {});
+ }
+ }
+ if (m.getName().equals("getString")) {
+ if (paramTypes.length == 0) {
+ return m.invoke(aComponent, new Object[] {});
+ }
+ }
+ if (m.getName().equals("getSelectedItem")) {
+ if (paramTypes.length == 0) {
+ return m.invoke(aComponent, new Object[] {});
+ }
+ }
+ // TODO: should also handle variants of setValue()
+ }
+ } catch (Exception exc) { // error occured while introspecting... move along.
+ System.out.println("InfoPanel.getValueFromComponent: " + exc);
+ }
-/**
-* Gets the component associated with the key as a JTextField, for backwards compatibility.
-* @param key A string representing the key associated with the component. Nulls are converted to an empty string.
-* @return A JTextField that contains the value associated with the key,
-* or null if the key does not exist or if the component is not a JTextField.
-*/
- public JTextField getFieldForKey( String key )
- {
- Component c = getComponentForKey( key );
- if ( c instanceof JTextField )
- {
- return (JTextField) c;
- }
- return null;
- }
+ // not found
+ return null;
+ }
-/**
-* Gets the component associated with the key. If more than one component is associated
-* with the key, returns the first such component.
-* @param key A string representing the key associated with the component.
-* Nulls are converted to an empty string.
-* @return A component that contains the value associated with the key,
-* or null if the key does not exist.
-*/
- public Component getComponentForKey( String key )
- {
- return getComponentForKey( key, 0 );
+ /**
+ * Gets the component associated with the key as a JTextField, for backwards
+ * compatibility.
+ *
+ * @param key A string representing the key associated with the component. Nulls
+ * are converted to an empty string.
+ * @return A JTextField that contains the value associated with the key, or null
+ * if the key does not exist or if the component is not a JTextField.
+ */
+ public JTextField getFieldForKey(String key) {
+ Component c = getComponentForKey(key);
+ if (c instanceof JTextField) {
+ return (JTextField) c;
+ }
+ return null;
}
-/**
-* Gets the component associated with the key and index.
-* @param key A string representing the key associated with the component.
-* Nulls are converted to an empty string.
-* @return A component that contains the value associated with the key,
-* or null if the key does not exist.
-*/
- public Component getComponentForKey( String key, int index )
- {
- Container c = getCompositeComponentForKey( key );
- if ( c == null ) return null;
- return c.getComponent( index );
- }
+ /**
+ * Gets the component associated with the key. If more than one component is
+ * associated with the key, returns the first such component.
+ *
+ * @param key A string representing the key associated with the component. Nulls
+ * are converted to an empty string.
+ * @return A component that contains the value associated with the key, or null
+ * if the key does not exist.
+ */
+ public Component getComponentForKey(String key) {
+ return getComponentForKey(key, 0);
+ }
-/**
-* Gets the component at the specified row. If more than one component exists
-* on that row, returns the first such component.
-* @return A component or null if the row does not exist.
-*/
- public Object getComponentForIndex( int row )
- {
- return getComponentForIndex( row, 0 );
- }
+ /**
+ * Gets the component associated with the key and index.
+ *
+ * @param key A string representing the key associated with the component. Nulls
+ * are converted to an empty string.
+ * @return A component that contains the value associated with the key, or null
+ * if the key does not exist.
+ */
+ public Component getComponentForKey(String key, int index) {
+ Container c = getCompositeComponentForKey(key);
+ if (c == null)
+ return null;
+ return c.getComponent(index);
+ }
-/**
-* Gets the component at the specified row and column.
-* @return A component or null if the index is out of bounds.
-*/
- public Object getComponentForIndex( int row, int col )
- {
- if ( ( row > fields.size() ) || ( row < 0 ) )
- { // out of bounds
- return null;
- }
-
- Container field = (Container) fields.get( row );
- return field.getComponent( col );
- }
+ /**
+ * Gets the component at the specified row. If more than one component exists on
+ * that row, returns the first such component.
+ *
+ * @return A component or null if the row does not exist.
+ */
+ public Object getComponentForIndex(int row) {
+ return getComponentForIndex(row, 0);
+ }
-/**
-* Gets the container associated with the key.
-* @param key A string representing the key associated with the component.
-* Nulls are converted to an empty string.
-* @return A component that contains the value associated with the key,
-* or null if the key does not exist.
-*/
- protected Container getCompositeComponentForKey( String key )
- {
- if ( key == null )
- {
- key = "";
- }
-
- JPanel field = null;
- Iterator enumeration = fields.iterator();
- while ( enumeration.hasNext() )
- { // finds first value in list with specified key
- field = (JPanel) enumeration.next();
- if ( key.equals( field.getName() ) )
- {
- return field;
- }
- }
-
- // else not found
- return null;
- }
+ /**
+ * Gets the component at the specified row and column.
+ *
+ * @return A component or null if the index is out of bounds.
+ */
+ public Object getComponentForIndex(int row, int col) {
+ if ((row > fields.size()) || (row < 0)) { // out of bounds
+ return null;
+ }
-/**
-* Provided for backwards compatibility: calls getLabelComponentForKey.
-* @param key A string representing the key associated with the compoent.
-* Nulls are converted to an empty string.
-* @return Component label object associated with the key, or null if the key does not exist
-* or if the label component is not an instance of JLabel.
-*/
- public JLabel getLabelForKey( String key )
- {
- Component result = getLabelComponentForKey( key );
- if ( result instanceof JLabel ) return (JLabel) result;
- return null;
- }
-
-/**
-* Get the label component associated with the key.
-* @param key A string representing the key associated with the compoent.
-* Nulls are converted to an empty string.
-* @return Component label object associated with the key, or null if the key does not exist.
-*/
- public Component getLabelComponentForKey( String key )
- {
- if ( key == null )
- {
- key = "";
- }
-
- Component label = null;
- Iterator enumeration = labels.iterator();
- while ( enumeration.hasNext() )
- { // finds first value in list with specified key
- label = (Component) enumeration.next();
- if ( key.equals( label.getName() ) )
- {
- return label;
- }
- }
-
- // else not found
- return null;
- }
+ Container field = (Container) fields.get(row);
+ return field.getComponent(col);
+ }
-/**
-* Replaces the first component associated with the key. Any value in the existing
-* component will be copied to the new component.
-* @param key A string representing the key to be associated with the component.
-* Nulls are converted to an empty string.
-* @param c A component to be placed next to the label corresponding to the key.
-* Nulls are converted to a JTextField.
-*/
- public void setComponentForKey( String key, Component c )
- {
- setComponentForKey( key, c, 0 );
+ /**
+ * Gets the container associated with the key.
+ *
+ * @param key A string representing the key associated with the component. Nulls
+ * are converted to an empty string.
+ * @return A component that contains the value associated with the key, or null
+ * if the key does not exist.
+ */
+ protected Container getCompositeComponentForKey(String key) {
+ if (key == null) {
+ key = "";
+ }
+
+ JPanel field = null;
+ Iterator enumeration = fields.iterator();
+ while (enumeration.hasNext()) { // finds first value in list with specified key
+ field = (JPanel) enumeration.next();
+ if (key.equals(field.getName())) {
+ return field;
+ }
+ }
+
+ // else not found
+ return null;
}
-
-/**
-* Replaces the component associated with the key. Any value in the existing
-* component will be copied to the new component.
-* @param key A string representing the key to be associated with the component.
-* Nulls are converted to an empty string.
-* @param c A component to be placed next to the label corresponding to the key.
-* Nulls are converted to a JTextField.
-*/
- public void setComponentForKey( String key, Component c, int index )
- {
- if ( c == null )
- {
- c = new JTextField( 15 );
- }
- if ( key == null )
- {
- key = "";
- }
-
- Container container = this.getCompositeComponentForKey( key );
- Component field = container.getComponent( index );
- Object value = this.getValueForKey( key, index );
- if ( field != null )
- {
- container.remove( index );
- container.add( c, index );
- c.setEnabled( this.isEditable );
- introspectComponent( c, key );
- setValueForComponent( c, value );
- }
- }
-/**
-* Replaces the first component in the specified row. Any value in the existing
-* component will be copied to the new component.
-* @param row A valid index.
-* @param c A component to be placed next to the label corresponding to the key.
-*/
- public void setComponentForIndex( int row, Component c )
- {
- setComponentForIndex( row, 0, c );
+ /**
+ * Provided for backwards compatibility: calls getLabelComponentForKey.
+ *
+ * @param key A string representing the key associated with the compoent. Nulls
+ * are converted to an empty string.
+ * @return Component label object associated with the key, or null if the key
+ * does not exist or if the label component is not an instance of
+ * JLabel.
+ */
+ public JLabel getLabelForKey(String key) {
+ Component result = getLabelComponentForKey(key);
+ if (result instanceof JLabel)
+ return (JLabel) result;
+ return null;
}
-
-/**
-* Replaces the component associated with the key. Any value in the existing
-* component will be copied to the new component.
-* @param row A valid index.
-* @param c A component to be placed next to the label corresponding to the key.
-*/
- public void setComponentForIndex( int row, int col, Component c )
- {
- setComponentForKey( getLabels()[row], c, col );
- }
-/**
-* Sets the string that appears before each label's text on the panel.
-* @param aString A String to be used as the label prefix.
-*/
- public void setLabelPrefix( String aString )
- {
- prefix = aString;
- setLabels( getLabels() ); // force refresh
- }
+ /**
+ * Get the label component associated with the key.
+ *
+ * @param key A string representing the key associated with the compoent. Nulls
+ * are converted to an empty string.
+ * @return Component label object associated with the key, or null if the key
+ * does not exist.
+ */
+ public Component getLabelComponentForKey(String key) {
+ if (key == null) {
+ key = "";
+ }
-/**
-* Gets the string that appears before each label's text on the panel.
-* Defaults to "", an empty string.
-* @return A String that is currently used as the label prefix.
-*/
- public String getLabelPrefix()
- {
- return prefix;
- }
+ Component label = null;
+ Iterator enumeration = labels.iterator();
+ while (enumeration.hasNext()) { // finds first value in list with specified key
+ label = (Component) enumeration.next();
+ if (key.equals(label.getName())) {
+ return label;
+ }
+ }
-/**
-* Sets the string that appears after each label's text on the panel.
-* Defaults to ": ", a colon followed by a space.
-* @param aString A String to be used as the label postfix.
-*/
- public void setLabelPostfix( String aString )
- {
- postfix = aString;
- setLabels( getLabels() ); // force refresh
- }
+ // else not found
+ return null;
+ }
-/**
-* Gets the string that appears after each label's text on the panel.
-* @return A String that is currently used as the label postfix.
-*/
- public String getLabelPostfix()
- {
- return postfix;
- }
+ /**
+ * Replaces the first component associated with the key. Any value in the
+ * existing component will be copied to the new component.
+ *
+ * @param key A string representing the key to be associated with the component.
+ * Nulls are converted to an empty string.
+ * @param c A component to be placed next to the label corresponding to the
+ * key. Nulls are converted to a JTextField.
+ */
+ public void setComponentForKey(String key, Component c) {
+ setComponentForKey(key, c, 0);
+ }
-/**
-* Adds an action listener to the list that will be
-* notified by events occurring in the panel.
-* @param l An action listener to be notified.
-*/
- public void addActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.add(actionListener, l);
- }
-/**
-* Removes an action listener from the list that will be
-* notified by events occurring in the panel.
-* @param l An action listener to be removed.
-*/
- public void removeActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.remove(actionListener, l);
- }
-/**
-* Notifies all registered action listeners of a pending Action Event.
-* @param e An action event to be broadcast.
-*/
- protected void broadcastEvent(ActionEvent e)
- {
- if (actionListener != null)
- {
- actionListener.actionPerformed(e);
- }
- }
+ /**
+ * Replaces the component associated with the key. Any value in the existing
+ * component will be copied to the new component.
+ *
+ * @param key A string representing the key to be associated with the component.
+ * Nulls are converted to an empty string.
+ * @param c A component to be placed next to the label corresponding to the
+ * key. Nulls are converted to a JTextField.
+ */
+ public void setComponentForKey(String key, Component c, int index) {
+ if (c == null) {
+ c = new JTextField(15);
+ }
+ if (key == null) {
+ key = "";
+ }
- // interface ActionListener
+ Container container = this.getCompositeComponentForKey(key);
+ Component field = container.getComponent(index);
+ Object value = this.getValueForKey(key, index);
+ if (field != null) {
+ container.remove(index);
+ container.add(c, index);
+ c.setEnabled(this.isEditable);
+ introspectComponent(c, key);
+ setValueForComponent(c, value);
+ }
+ }
-/**
-* Called by buttons on panel and by other components that
-* might be set to broadcast events to this listener.
-* Simply forwards the action event unchanged.
-* @param e An action event to be received.
-*/
- public void actionPerformed(ActionEvent e)
- {
+ /**
+ * Replaces the first component in the specified row. Any value in the existing
+ * component will be copied to the new component.
+ *
+ * @param row A valid index.
+ * @param c A component to be placed next to the label corresponding to the
+ * key.
+ */
+ public void setComponentForIndex(int row, Component c) {
+ setComponentForIndex(row, 0, c);
+ }
+
+ /**
+ * Replaces the component associated with the key. Any value in the existing
+ * component will be copied to the new component.
+ *
+ * @param row A valid index.
+ * @param c A component to be placed next to the label corresponding to the
+ * key.
+ */
+ public void setComponentForIndex(int row, int col, Component c) {
+ setComponentForKey(getLabels()[row], c, col);
+ }
+
+ /**
+ * Sets the string that appears before each label's text on the panel.
+ *
+ * @param aString A String to be used as the label prefix.
+ */
+ public void setLabelPrefix(String aString) {
+ prefix = aString;
+ setLabels(getLabels()); // force refresh
+ }
+
+ /**
+ * Gets the string that appears before each label's text on the panel. Defaults
+ * to "", an empty string.
+ *
+ * @return A String that is currently used as the label prefix.
+ */
+ public String getLabelPrefix() {
+ return prefix;
+ }
+
+ /**
+ * Sets the string that appears after each label's text on the panel. Defaults
+ * to ": ", a colon followed by a space.
+ *
+ * @param aString A String to be used as the label postfix.
+ */
+ public void setLabelPostfix(String aString) {
+ postfix = aString;
+ setLabels(getLabels()); // force refresh
+ }
+
+ /**
+ * Gets the string that appears after each label's text on the panel.
+ *
+ * @return A String that is currently used as the label postfix.
+ */
+ public String getLabelPostfix() {
+ return postfix;
+ }
+
+ /**
+ * Adds an action listener to the list that will be notified by events occurring
+ * in the panel.
+ *
+ * @param l An action listener to be notified.
+ */
+ public void addActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.add(actionListener, l);
+ }
+
+ /**
+ * Removes an action listener from the list that will be notified by events
+ * occurring in the panel.
+ *
+ * @param l An action listener to be removed.
+ */
+ public void removeActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.remove(actionListener, l);
+ }
+
+ /**
+ * Notifies all registered action listeners of a pending Action Event.
+ *
+ * @param e An action event to be broadcast.
+ */
+ protected void broadcastEvent(ActionEvent e) {
+ if (actionListener != null) {
+ actionListener.actionPerformed(e);
+ }
+ }
+
+ // interface ActionListener
+
+ /**
+ * Called by buttons on panel and by other components that might be set to
+ * broadcast events to this listener. Simply forwards the action event
+ * unchanged.
+ *
+ * @param e An action event to be received.
+ */
+ public void actionPerformed(ActionEvent e) {
// if ( e.getSource() instanceof AbstractButton )
// {
- broadcastEvent(e);
+ broadcastEvent(e);
// }
- }
-
- /**
- * GridBagLayout allocates weightx only after considering
- * the preferred width of the components in a column.
- * We'd prefer that preferred width wasn't considered,
- * so that the layout worked more like a html-table.
- * GridBagLayout is poorly factored for subclassing,
- * so this code is going to get a little bit ugly.
- * Really, what good is a protected method that returns
- * a private class? Would have liked to just override
- * getLayoutInfo and be done with it.
- */
- private class BetterGridBagLayout extends GridBagLayout
- {
- public Dimension preferredLayoutSize(Container parent)
- {
- preprocess();
- return super.preferredLayoutSize( parent );
- }
-
- public Dimension minimumLayoutSize(Container parent)
- {
- preprocess();
- return super.minimumLayoutSize( parent );
- }
-
-
- public void layoutContainer(Container parent)
- {
- preprocess();
- super.layoutContainer( parent );
- }
-
- protected void preprocess()
- {
- if ( fieldSpacers == null ) return;
- Iterator i;
-
- // find the field with the widest preferred size
- Component c;
- int maxWidth = 0;
- i = fields.iterator();
- while ( i.hasNext() )
- {
- c = (Component) i.next();
- maxWidth = Math.max( maxWidth,
- Math.max( c.getPreferredSize().width, c.getMinimumSize().width ) );
- }
-
- // set each column's spacers to that preferred size
- Dimension min = new Dimension( 0, 0 );
- Dimension pref = new Dimension( maxWidth, 0 );
- i = fieldSpacers.iterator();
- while ( i.hasNext() )
- {
- ((Box.Filler)i.next()).changeShape( min, pref, pref );
- }
- }
- }
-}
+ }
+
+ /**
+ * GridBagLayout allocates weightx only after considering the preferred width of
+ * the components in a column. We'd prefer that preferred width wasn't
+ * considered, so that the layout worked more like a html-table. GridBagLayout
+ * is poorly factored for subclassing, so this code is going to get a little bit
+ * ugly. Really, what good is a protected method that returns a private class?
+ * Would have liked to just override getLayoutInfo and be done with it.
+ */
+ private class BetterGridBagLayout extends GridBagLayout {
+ public Dimension preferredLayoutSize(Container parent) {
+ preprocess();
+ return super.preferredLayoutSize(parent);
+ }
+
+ public Dimension minimumLayoutSize(Container parent) {
+ preprocess();
+ return super.minimumLayoutSize(parent);
+ }
+
+ public void layoutContainer(Container parent) {
+ preprocess();
+ super.layoutContainer(parent);
+ }
+
+ protected void preprocess() {
+ if (fieldSpacers == null)
+ return;
+ Iterator i;
+
+ // find the field with the widest preferred size
+ Component c;
+ int maxWidth = 0;
+ i = fields.iterator();
+ while (i.hasNext()) {
+ c = (Component) i.next();
+ maxWidth = Math.max(maxWidth, Math.max(c.getPreferredSize().width, c.getMinimumSize().width));
+ }
+ // set each column's spacers to that preferred size
+ Dimension min = new Dimension(0, 0);
+ Dimension pref = new Dimension(maxWidth, 0);
+ i = fieldSpacers.iterator();
+ while (i.hasNext()) {
+ ((Box.Filler) i.next()).changeShape(min, pref, pref);
+ }
+ }
+ }
+}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyDelayTimer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyDelayTimer.java
index b73c74d..31bdb70 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyDelayTimer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyDelayTimer.java
@@ -28,161 +28,150 @@ import java.awt.event.KeyListener;
import javax.swing.Timer;
/**
-* KeyDelayTimer is a utility that listens for KeyEvents from one
-* or more components. After receiving a KeyEvents the timer will
-* broadcast an action event if a specified time interval passes without
-* a subsequent KeyEvent.<BR><BR>
-*
-* This utility is useful for implementing any kind of auto-complete
-* feature in a user interface.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class KeyDelayTimer implements ActionListener, KeyListener
-{
- // delay timer for keypress-sensitve events
- protected Timer keyTimer = null;
- protected Component lastFieldTouched = null;
- protected long timeLastFieldTouched = 0;
- protected int interval = 400; // adjust as needed
-
- // for action multicasting
- protected ActionListener actionListener = null;
-
-/**
-* Default constructor.
-*/
- public KeyDelayTimer()
- {
- keyTimer = new Timer( interval, this );
- }
-
-/**
-* Convenience constructor.
-* @param listener An action listener to be notified of delay events.
-*/
- public KeyDelayTimer( ActionListener listener )
- {
- this();
- addActionListener( listener );
- }
-
-/**
-* Returns the last component that generated a KeyEvent.
-* @return The component that sent the most recent KeyEvent.
-*/
- public Component getComponent()
- {
- return lastFieldTouched;
- }
-
-/**
-* Returns the number of milliseconds before an ActionEvent is generated.
-* The default is 400.
-* @return The current delay interval in milliseconds.
-*/
- public int getInterval()
- {
- return interval;
- }
-
-/**
-* Sets the number of milliseconds before an ActionEvent will be generated
-* after a KeyEvent is received.
-* @param millis The new delay interval in milliseconds.
-*/
- public void setInterval( int millis )
- {
- interval = millis;
- keyTimer.setDelay( interval / 2 );
- }
-
- // interface KeyListener
-
- public void keyTyped(KeyEvent e)
- {
- }
- public void keyPressed(KeyEvent e)
- {
- }
-
-/**
-* Receives key events from one or more components.
-* Records the component and the time this event was received,
-* then starts the timer.
-* @param e The key event in question.
-*/
- public void keyReleased(KeyEvent e)
- { // handles keystrokes in the textfields (except ENTER and ESCAPE)
- if ( ( Character.isLetterOrDigit( e.getKeyChar() ) )
- || ( e.getKeyCode() == KeyEvent.VK_SPACE )
- || ( e.getKeyCode() == KeyEvent.VK_DELETE )
- || ( e.getKeyCode() == KeyEvent.VK_BACK_SPACE ) )
- {
- this.lastFieldTouched = e.getComponent();
- this.timeLastFieldTouched = System.currentTimeMillis();
- this.keyTimer.start();
- return;
- }
- }
-
- // interface ActionListener
-
-/**
-* Receives ActionEvents from the internal timer.
-* If the interval has passed without another KeyEvent,
-* an ActionEvent is broadcast, with the name of this class
-* as the ActionCommand, and the internal timer is stopped.
-* @param e The action event in question.
-*/
- public void actionPerformed(ActionEvent e)
- {
- if ( e.getSource() == keyTimer )
- {
- if ( System.currentTimeMillis() - this.timeLastFieldTouched > interval )
- {
- this.keyTimer.stop();
- broadcastEvent( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, this.getClass().getName() ) );
- }
- return;
- }
- }
-
- // Action Multicast methods
-
-/**
-* Adds an action listener to the list that will be
-* notified by button events and changes in button state.
-* @param l An action listener to be notified.
-*/
- public void addActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.add(actionListener, l);
- }
-/**
-* Removes an action listener from the list that will be
-* notified by button events and changes in button state.
-* @param l An action listener to be removed.
-*/
- public void removeActionListener(ActionListener l)
- {
- actionListener = AWTEventMulticaster.remove(actionListener, l);
- }
-/**
-* Notifies all registered action listeners of a pending Action Event.
-* @param e An action event to be broadcast.
-*/
- protected void broadcastEvent(ActionEvent e)
- {
- if (actionListener != null)
- {
- actionListener.actionPerformed(e);
- }
- }
+ * KeyDelayTimer is a utility that listens for KeyEvents from one or more
+ * components. After receiving a KeyEvents the timer will broadcast an action
+ * event if a specified time interval passes without a subsequent KeyEvent.<BR>
+ * <BR>
+ *
+ * This utility is useful for implementing any kind of auto-complete feature in
+ * a user interface.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class KeyDelayTimer implements ActionListener, KeyListener {
+ // delay timer for keypress-sensitve events
+ protected Timer keyTimer = null;
+ protected Component lastFieldTouched = null;
+ protected long timeLastFieldTouched = 0;
+ protected int interval = 400; // adjust as needed
+
+ // for action multicasting
+ protected ActionListener actionListener = null;
+
+ /**
+ * Default constructor.
+ */
+ public KeyDelayTimer() {
+ keyTimer = new Timer(interval, this);
+ }
+
+ /**
+ * Convenience constructor.
+ *
+ * @param listener An action listener to be notified of delay events.
+ */
+ public KeyDelayTimer(ActionListener listener) {
+ this();
+ addActionListener(listener);
+ }
+
+ /**
+ * Returns the last component that generated a KeyEvent.
+ *
+ * @return The component that sent the most recent KeyEvent.
+ */
+ public Component getComponent() {
+ return lastFieldTouched;
+ }
+
+ /**
+ * Returns the number of milliseconds before an ActionEvent is generated. The
+ * default is 400.
+ *
+ * @return The current delay interval in milliseconds.
+ */
+ public int getInterval() {
+ return interval;
+ }
+
+ /**
+ * Sets the number of milliseconds before an ActionEvent will be generated after
+ * a KeyEvent is received.
+ *
+ * @param millis The new delay interval in milliseconds.
+ */
+ public void setInterval(int millis) {
+ interval = millis;
+ keyTimer.setDelay(interval / 2);
+ }
+
+ // interface KeyListener
+
+ public void keyTyped(KeyEvent e) {
+ }
+
+ public void keyPressed(KeyEvent e) {
+ }
+
+ /**
+ * Receives key events from one or more components. Records the component and
+ * the time this event was received, then starts the timer.
+ *
+ * @param e The key event in question.
+ */
+ public void keyReleased(KeyEvent e) { // handles keystrokes in the textfields (except ENTER and ESCAPE)
+ if ((Character.isLetterOrDigit(e.getKeyChar())) || (e.getKeyCode() == KeyEvent.VK_SPACE)
+ || (e.getKeyCode() == KeyEvent.VK_DELETE) || (e.getKeyCode() == KeyEvent.VK_BACK_SPACE)) {
+ this.lastFieldTouched = e.getComponent();
+ this.timeLastFieldTouched = System.currentTimeMillis();
+ this.keyTimer.start();
+ return;
+ }
+ }
+
+ // interface ActionListener
+
+ /**
+ * Receives ActionEvents from the internal timer. If the interval has passed
+ * without another KeyEvent, an ActionEvent is broadcast, with the name of this
+ * class as the ActionCommand, and the internal timer is stopped.
+ *
+ * @param e The action event in question.
+ */
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == keyTimer) {
+ if (System.currentTimeMillis() - this.timeLastFieldTouched > interval) {
+ this.keyTimer.stop();
+ broadcastEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, this.getClass().getName()));
+ }
+ return;
+ }
+ }
+
+ // Action Multicast methods
+
+ /**
+ * Adds an action listener to the list that will be notified by button events
+ * and changes in button state.
+ *
+ * @param l An action listener to be notified.
+ */
+ public void addActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.add(actionListener, l);
+ }
+
+ /**
+ * Removes an action listener from the list that will be notified by button
+ * events and changes in button state.
+ *
+ * @param l An action listener to be removed.
+ */
+ public void removeActionListener(ActionListener l) {
+ actionListener = AWTEventMulticaster.remove(actionListener, l);
+ }
+
+ /**
+ * Notifies all registered action listeners of a pending Action Event.
+ *
+ * @param e An action event to be broadcast.
+ */
+ protected void broadcastEvent(ActionEvent e) {
+ if (actionListener != null) {
+ actionListener.actionPerformed(e);
+ }
+ }
}
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyableCellEditor.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyableCellEditor.java
index 95b8a19..f64e607 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyableCellEditor.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/KeyableCellEditor.java
@@ -40,311 +40,265 @@ import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
/**
-* A table cell editor customized for keyboard navigation, much like
-* working with a spreadsheet. The default cell editor unfortunately
-* does none of these things:
-* <ul>
-* <li> Selects text on start of editing.
-* <li> Up and down keys move edit cell up and down.
-* <li> Right and left keys move cell when selection caret is at end of text.
-* <li> Escape cancels editing.
-* <li> Enter commits edit.
-* <li> Edits are properly committed on lost focus.
-* <li> Tab and shift-tab work as expected.
-* <li> Cell selection moves with the edit cell.
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class KeyableCellEditor implements TableCellEditor, FocusListener,
- KeyListener, Serializable
-{
- List listeners;
- JTextField textField;
- Object lastValue;
- Format currentFormat;
-
- JTable table;
-
-/**
-* Default constructor - a standard JTextField will be used for editing.
-*/
- public KeyableCellEditor()
- {
- this( (JTextField) null );
- }
-
-/**
-* Constructor specifying a type of JTextField to be used for editing.
-* The JTextField will have its border replaced with a black line border.
-* @param aTextField A JTextField or subclass for editing values.
-*/
- public KeyableCellEditor( JTextField aTextField )
- {
- listeners = new Vector();
- lastValue = null;
-
- // default to stock JTextField
- textField = aTextField;
- if ( textField == null )
- {
- textField = new JTextField();
- }
-
- textField.setBorder(new LineBorder(Color.black));
-
- // handle arrow keys while caret is showing
- textField.addKeyListener( this );
-
- // handle lost focus
- textField.addFocusListener( this );
- }
-
- public Component getTableCellEditorComponent(JTable table,
- Object value,
- boolean isSelected,
- int row,
- int column)
- {
- this.table = table;
- table.removeKeyListener( this ); // if any
- table.addKeyListener( this );
- return getEditorComponent( value );
- }
-
- protected Component getEditorComponent( Object value )
- {
- if ( value != null )
- {
- textField.setText( value.toString() );
- }
- else
- {
- textField.setText( "" );
- }
-
- if ( value instanceof Number )
- {
- textField.setHorizontalAlignment(JTextField.RIGHT);
- }
- else
- {
- textField.setHorizontalAlignment(JTextField.LEFT);
- }
-
- // remember original value
- lastValue = value;
-
- // select all text and get focus
- textField.selectAll();
- textField.requestFocus();
-
- return textField;
- }
-
- public Object getCellEditorValue()
- {
- return lastValue;
- }
-
- public boolean isCellEditable(EventObject anEvent)
- {
- // key events should replace the selection
- // NOTE: For whatever reason, key events trigger result in a null parameter
- if ( anEvent == null )
- {
- textField.setText("");
- textField.requestFocus();
- return true;
- }
-
- return true;
- }
-
- public boolean shouldSelectCell(EventObject anEvent)
- { // System.out.println( "KeyableCellEditor.shouldSelectCell: " + anEvent );
-
- // key events should replace the selection
- // NOTE: For whatever reason, key events are not generated
- if ( anEvent instanceof KeyEvent )
- {
- textField.setText("");
- textField.requestFocus();
- return true;
- }
-
- // otherwise, select all text and continue
- textField.selectAll();
- textField.requestFocus();
-
- return true;
- }
-
- public boolean stopCellEditing()
- {
- lastValue = textField.getText();
- fireEditingStopped();
- table.removeKeyListener( this ); // if any
- return true;
- }
-
- public void cancelCellEditing()
- {
- fireEditingCanceled();
- table.removeKeyListener( this ); // if any
- }
-
- public void addCellEditorListener(CellEditorListener l)
- {
- listeners.add( l );
- }
-
- public void removeCellEditorListener(CellEditorListener l)
- {
- listeners.remove( l );
- }
-
- protected void fireEditingCanceled()
- {
- ChangeEvent event = new ChangeEvent( this );
- Iterator it = new ArrayList( listeners ).iterator(); // copy to prevent modification exception
- while ( it.hasNext() )
- {
- ((CellEditorListener)it.next()).editingCanceled( event );
- }
- }
-
- protected void fireEditingStopped()
- {
- ChangeEvent event = new ChangeEvent( this );
- Iterator it = new ArrayList( listeners ).iterator(); // copy to prevent modification exception
- while ( it.hasNext() )
- {
- ((CellEditorListener)it.next()).editingStopped( event );
- }
- }
-
- protected void onEnterKey()
- {
- stopCellEditing();
- }
-
- protected void onEscapeKey()
- {
- cancelCellEditing();
- }
-
- protected void moveEditCell( int dRow, int dCol )
- {
- if ( table == null ) return;
- int row = table.getSelectedRow() + dRow;
- int col = table.getSelectedColumn() + dCol;
-
- row = Math.max( 0, row );
- row = Math.min( row, table.getRowCount() - 1 );
- col = Math.max( 0, col );
- col = Math.min( col, table.getColumnCount() - 1 );
-
- stopCellEditing();
- table.setRowSelectionInterval( row, row );
- table.setColumnSelectionInterval( col, col );
- table.editCellAt( row, col );
- textField.selectAll();
- textField.requestFocus();
- }
-
- // interface KeyListener
-
- public void keyTyped(KeyEvent e)
- { // System.out.println( "KeyableCellEditor.keyTyped: " + KeyEvent.getKeyText( e.getKeyCode() ) );
- }
-
- public void keyPressed(KeyEvent e)
- { // System.out.println( "KeyableCellEditor.keyPressed: " + KeyEvent.getKeyText( e.getKeyCode() ) );
-
- // catch LEFT and RIGHT here before JTextField consumes them
-
- int keyCode = e.getKeyCode();
- if ( keyCode == KeyEvent.VK_LEFT )
- {
- if ( textField.getSelectionStart() == 0 )
- {
- moveEditCell( 0, -1 );
- e.consume();
- return;
- }
- }
- if ( keyCode == KeyEvent.VK_RIGHT )
- {
- if ( textField.getSelectionEnd() == textField.getText().length() )
- {
- moveEditCell( 0, 1 );
- e.consume();
- return;
- }
- }
- if ( keyCode == KeyEvent.VK_UP )
- {
- moveEditCell( -1, 0 );
- e.consume();
- return;
- }
- if ( keyCode == KeyEvent.VK_DOWN )
- {
- moveEditCell( 1, 0 );
- e.consume();
- return;
- }
- }
-
- public void keyReleased(KeyEvent e)
- { // System.out.println( "KeyableCellEditor.keyReleased: " + KeyEvent.getKeyText( e.getKeyCode() ) );
-
- // catch ENTER here to allow JTextField to process it as well
-
- int keyCode = e.getKeyCode();
- if ( keyCode == KeyEvent.VK_ENTER )
- {
- onEnterKey();
- return;
- }
- if ( keyCode == KeyEvent.VK_ESCAPE )
- {
- onEscapeKey();
- return;
- }
-
- // tabs are apparently only received on key release
- if ( keyCode == KeyEvent.VK_TAB )
- {
- if ( e.isShiftDown() )
- {
- moveEditCell( 0, -1 );
- }
- else
- {
- moveEditCell( 0, 1 );
- }
- e.consume();
- return;
- }
-
- }
-
- // interface FocusListener
-
- public void focusGained(FocusEvent e)
- { // System.out.println( "focusGained: " );
- }
-
- public void focusLost(FocusEvent e)
- { // System.out.println( "focusLost: " );
- stopCellEditing();
- }
+ * A table cell editor customized for keyboard navigation, much like working
+ * with a spreadsheet. The default cell editor unfortunately does none of these
+ * things:
+ * <ul>
+ * <li>Selects text on start of editing.
+ * <li>Up and down keys move edit cell up and down.
+ * <li>Right and left keys move cell when selection caret is at end of text.
+ * <li>Escape cancels editing.
+ * <li>Enter commits edit.
+ * <li>Edits are properly committed on lost focus.
+ * <li>Tab and shift-tab work as expected.
+ * <li>Cell selection moves with the edit cell.
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class KeyableCellEditor implements TableCellEditor, FocusListener, KeyListener, Serializable {
+ List listeners;
+ JTextField textField;
+ Object lastValue;
+ Format currentFormat;
+
+ JTable table;
+
+ /**
+ * Default constructor - a standard JTextField will be used for editing.
+ */
+ public KeyableCellEditor() {
+ this((JTextField) null);
+ }
+
+ /**
+ * Constructor specifying a type of JTextField to be used for editing. The
+ * JTextField will have its border replaced with a black line border.
+ *
+ * @param aTextField A JTextField or subclass for editing values.
+ */
+ public KeyableCellEditor(JTextField aTextField) {
+ listeners = new Vector();
+ lastValue = null;
+
+ // default to stock JTextField
+ textField = aTextField;
+ if (textField == null) {
+ textField = new JTextField();
+ }
+
+ textField.setBorder(new LineBorder(Color.black));
+
+ // handle arrow keys while caret is showing
+ textField.addKeyListener(this);
+
+ // handle lost focus
+ textField.addFocusListener(this);
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+ this.table = table;
+ table.removeKeyListener(this); // if any
+ table.addKeyListener(this);
+ return getEditorComponent(value);
+ }
+
+ protected Component getEditorComponent(Object value) {
+ if (value != null) {
+ textField.setText(value.toString());
+ } else {
+ textField.setText("");
+ }
+
+ if (value instanceof Number) {
+ textField.setHorizontalAlignment(JTextField.RIGHT);
+ } else {
+ textField.setHorizontalAlignment(JTextField.LEFT);
+ }
+
+ // remember original value
+ lastValue = value;
+
+ // select all text and get focus
+ textField.selectAll();
+ textField.requestFocus();
+
+ return textField;
+ }
+
+ public Object getCellEditorValue() {
+ return lastValue;
+ }
+
+ public boolean isCellEditable(EventObject anEvent) {
+ // key events should replace the selection
+ // NOTE: For whatever reason, key events trigger result in a null parameter
+ if (anEvent == null) {
+ textField.setText("");
+ textField.requestFocus();
+ return true;
+ }
+
+ return true;
+ }
+
+ public boolean shouldSelectCell(EventObject anEvent) { // System.out.println( "KeyableCellEditor.shouldSelectCell: "
+ // + anEvent );
+
+ // key events should replace the selection
+ // NOTE: For whatever reason, key events are not generated
+ if (anEvent instanceof KeyEvent) {
+ textField.setText("");
+ textField.requestFocus();
+ return true;
+ }
+
+ // otherwise, select all text and continue
+ textField.selectAll();
+ textField.requestFocus();
+
+ return true;
+ }
+
+ public boolean stopCellEditing() {
+ lastValue = textField.getText();
+ fireEditingStopped();
+ table.removeKeyListener(this); // if any
+ return true;
+ }
+
+ public void cancelCellEditing() {
+ fireEditingCanceled();
+ table.removeKeyListener(this); // if any
+ }
+
+ public void addCellEditorListener(CellEditorListener l) {
+ listeners.add(l);
+ }
+
+ public void removeCellEditorListener(CellEditorListener l) {
+ listeners.remove(l);
+ }
+
+ protected void fireEditingCanceled() {
+ ChangeEvent event = new ChangeEvent(this);
+ Iterator it = new ArrayList(listeners).iterator(); // copy to prevent modification exception
+ while (it.hasNext()) {
+ ((CellEditorListener) it.next()).editingCanceled(event);
+ }
+ }
+
+ protected void fireEditingStopped() {
+ ChangeEvent event = new ChangeEvent(this);
+ Iterator it = new ArrayList(listeners).iterator(); // copy to prevent modification exception
+ while (it.hasNext()) {
+ ((CellEditorListener) it.next()).editingStopped(event);
+ }
+ }
+
+ protected void onEnterKey() {
+ stopCellEditing();
+ }
+
+ protected void onEscapeKey() {
+ cancelCellEditing();
+ }
+
+ protected void moveEditCell(int dRow, int dCol) {
+ if (table == null)
+ return;
+ int row = table.getSelectedRow() + dRow;
+ int col = table.getSelectedColumn() + dCol;
+
+ row = Math.max(0, row);
+ row = Math.min(row, table.getRowCount() - 1);
+ col = Math.max(0, col);
+ col = Math.min(col, table.getColumnCount() - 1);
+
+ stopCellEditing();
+ table.setRowSelectionInterval(row, row);
+ table.setColumnSelectionInterval(col, col);
+ table.editCellAt(row, col);
+ textField.selectAll();
+ textField.requestFocus();
+ }
+
+ // interface KeyListener
+
+ public void keyTyped(KeyEvent e) { // System.out.println( "KeyableCellEditor.keyTyped: " + KeyEvent.getKeyText(
+ // e.getKeyCode() ) );
+ }
+
+ public void keyPressed(KeyEvent e) { // System.out.println( "KeyableCellEditor.keyPressed: " + KeyEvent.getKeyText(
+ // e.getKeyCode() ) );
+
+ // catch LEFT and RIGHT here before JTextField consumes them
+
+ int keyCode = e.getKeyCode();
+ if (keyCode == KeyEvent.VK_LEFT) {
+ if (textField.getSelectionStart() == 0) {
+ moveEditCell(0, -1);
+ e.consume();
+ return;
+ }
+ }
+ if (keyCode == KeyEvent.VK_RIGHT) {
+ if (textField.getSelectionEnd() == textField.getText().length()) {
+ moveEditCell(0, 1);
+ e.consume();
+ return;
+ }
+ }
+ if (keyCode == KeyEvent.VK_UP) {
+ moveEditCell(-1, 0);
+ e.consume();
+ return;
+ }
+ if (keyCode == KeyEvent.VK_DOWN) {
+ moveEditCell(1, 0);
+ e.consume();
+ return;
+ }
+ }
+
+ public void keyReleased(KeyEvent e) { // System.out.println( "KeyableCellEditor.keyReleased: " +
+ // KeyEvent.getKeyText( e.getKeyCode() ) );
+
+ // catch ENTER here to allow JTextField to process it as well
+
+ int keyCode = e.getKeyCode();
+ if (keyCode == KeyEvent.VK_ENTER) {
+ onEnterKey();
+ return;
+ }
+ if (keyCode == KeyEvent.VK_ESCAPE) {
+ onEscapeKey();
+ return;
+ }
+
+ // tabs are apparently only received on key release
+ if (keyCode == KeyEvent.VK_TAB) {
+ if (e.isShiftDown()) {
+ moveEditCell(0, -1);
+ } else {
+ moveEditCell(0, 1);
+ }
+ e.consume();
+ return;
+ }
+
+ }
+
+ // interface FocusListener
+
+ public void focusGained(FocusEvent e) { // System.out.println( "focusGained: " );
+ }
+
+ public void focusLost(FocusEvent e) { // System.out.println( "focusLost: " );
+ stopCellEditing();
+ }
}
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/LineWrappingRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/LineWrappingRenderer.java
index 4a7f07e..326d825 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/LineWrappingRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/LineWrappingRenderer.java
@@ -31,124 +31,111 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
-* A list cell renderer that wraps its text to subsequent lines
-* depending on the length of text string and the width of the
-* parent list.
-*
-* This renderer depends on listening to the parent list's viewport
-* and fixing the list's width to match the viewport's size.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @date $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-* @revision $Revision: 904 $
-*/
-public class LineWrappingRenderer extends MultiLineLabel
- implements ListCellRenderer, ChangeListener
-{
- protected static Border noFocusBorder;
-
- protected JList list;
- protected JViewport viewport;
- protected int preferredWidth;
-
-/**
-* Required constructor. The renderer keeps a reference to
-* the list in which it is used and its viewport. This list
-* is the only list that may use this renderer. The renderer
-* will use the current size of the list to determine where
-* lines will initially break.
-* @param containerList The list that will be using this renderer.
-*/
- public LineWrappingRenderer( JList containerList )
- {
- super();
- setLineWrap(true);
- noFocusBorder = new EmptyBorder(1, 1, 1, 1);
-
- list = containerList;
- preferredWidth = 400;
- if ( list.getParent() instanceof JViewport )
- {
- viewport = (JViewport) list.getParent();
- viewport.addChangeListener( this );
- int newWidth = viewport.getExtentSize().width;
- if ( newWidth > 0 ) preferredWidth = newWidth;
- }
- else
- {
- // should function adequately in absence of a viewport
- // System.err.println( "LineWrappingRenderer.init: list.getParent = " + list.getParent() );
- }
- }
-
-/**
-* Returns the preferred size of the label, with width
-* constrained to the current width.
-* @return the size
-*/
- public Dimension getPreferredSize()
- {
- int width = getWidth();
- if ( width != preferredWidth )
- {
- // if component has not yet been placed within the list
- if ( width < list.getWidth() / 2 ) width = list.getWidth();
- preferredWidth = width;
- }
- return new Dimension( preferredWidth, super.getPreferredSize().height );
- }
-
-/**
-* Returns this component with the width set to the
-* width of the specified JList.
-* @return this component.
-*/
- public Component getListCellRendererComponent (
- JList list,
- Object value,
- int index,
- boolean isSelected,
- boolean cellHasFocus )
- { // System.out.println( "LineWrappingRenderer.getListCellRendererComponent:" );
-
- if ( list != this.list )
- {
- System.err.println( "LineWrappingRenderer.getListCellRendererComponent: " +
- "warning: the list using the renderer is not the list specified in the constructor." );
- }
-
- if (isSelected)
- {
- setBackground(this.list.getSelectionBackground());
- setForeground(this.list.getSelectionForeground());
- }
- else
- {
- setBackground(this.list.getBackground());
- setForeground(this.list.getForeground());
- }
-
- setText((value == null) ? "" : value.toString());
-
- setEnabled(this.list.isEnabled());
- setFont(this.list.getFont());
- setBorder( (cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder );
-
- return this;
- }
-
-/**
-* Overridden to respond to viewport changes.
-*/
- public void stateChanged(ChangeEvent e)
- {
- int newWidth = viewport.getExtentSize().width;
- if ( newWidth > 0 ) preferredWidth = newWidth;
-
- // set fixed width on list
- list.setFixedCellWidth( preferredWidth );
- setSize( preferredWidth, super.getSize().height );
- }
+ * A list cell renderer that wraps its text to subsequent lines depending on the
+ * length of text string and the width of the parent list.
+ *
+ * This renderer depends on listening to the parent list's viewport and fixing
+ * the list's width to match the viewport's size.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @date $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
+ * @revision $Revision: 904 $
+ */
+public class LineWrappingRenderer extends MultiLineLabel implements ListCellRenderer, ChangeListener {
+ protected static Border noFocusBorder;
+
+ protected JList list;
+ protected JViewport viewport;
+ protected int preferredWidth;
+
+ /**
+ * Required constructor. The renderer keeps a reference to the list in which it
+ * is used and its viewport. This list is the only list that may use this
+ * renderer. The renderer will use the current size of the list to determine
+ * where lines will initially break.
+ *
+ * @param containerList The list that will be using this renderer.
+ */
+ public LineWrappingRenderer(JList containerList) {
+ super();
+ setLineWrap(true);
+ noFocusBorder = new EmptyBorder(1, 1, 1, 1);
+
+ list = containerList;
+ preferredWidth = 400;
+ if (list.getParent() instanceof JViewport) {
+ viewport = (JViewport) list.getParent();
+ viewport.addChangeListener(this);
+ int newWidth = viewport.getExtentSize().width;
+ if (newWidth > 0)
+ preferredWidth = newWidth;
+ } else {
+ // should function adequately in absence of a viewport
+ // System.err.println( "LineWrappingRenderer.init: list.getParent = " +
+ // list.getParent() );
+ }
+ }
+
+ /**
+ * Returns the preferred size of the label, with width constrained to the
+ * current width.
+ *
+ * @return the size
+ */
+ public Dimension getPreferredSize() {
+ int width = getWidth();
+ if (width != preferredWidth) {
+ // if component has not yet been placed within the list
+ if (width < list.getWidth() / 2)
+ width = list.getWidth();
+ preferredWidth = width;
+ }
+ return new Dimension(preferredWidth, super.getPreferredSize().height);
+ }
+
+ /**
+ * Returns this component with the width set to the width of the specified
+ * JList.
+ *
+ * @return this component.
+ */
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+ boolean cellHasFocus) { // System.out.println( "LineWrappingRenderer.getListCellRendererComponent:" );
+
+ if (list != this.list) {
+ System.err.println("LineWrappingRenderer.getListCellRendererComponent: "
+ + "warning: the list using the renderer is not the list specified in the constructor.");
+ }
+
+ if (isSelected) {
+ setBackground(this.list.getSelectionBackground());
+ setForeground(this.list.getSelectionForeground());
+ } else {
+ setBackground(this.list.getBackground());
+ setForeground(this.list.getForeground());
+ }
+
+ setText((value == null) ? "" : value.toString());
+
+ setEnabled(this.list.isEnabled());
+ setFont(this.list.getFont());
+ setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
+
+ return this;
+ }
+
+ /**
+ * Overridden to respond to viewport changes.
+ */
+ public void stateChanged(ChangeEvent e) {
+ int newWidth = viewport.getExtentSize().width;
+ if (newWidth > 0)
+ preferredWidth = newWidth;
+
+ // set fixed width on list
+ list.setFixedCellWidth(preferredWidth);
+ setSize(preferredWidth, super.getSize().height);
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/MultiLineLabel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/MultiLineLabel.java
index b5f8a9b..ce362c9 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/MultiLineLabel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/MultiLineLabel.java
@@ -23,113 +23,100 @@ import javax.swing.LookAndFeel;
import javax.swing.text.Highlighter;
/**
-* A custom JTextArea that looks and feels like a JLabel, but supports
-* line wrapping. This works a lot more like the IFC label component.
-* NOTE: doesn't support icons (yet).
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @date $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-* @revision $Revision: 904 $
-*/
-public class MultiLineLabel extends JTextArea
-{
+ * A custom JTextArea that looks and feels like a JLabel, but supports line
+ * wrapping. This works a lot more like the IFC label component. NOTE: doesn't
+ * support icons (yet).
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @date $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
+ * @revision $Revision: 904 $
+ */
+public class MultiLineLabel extends JTextArea {
/**
- * Saves a reference to the original highlighter
- * to enable/disable text selection.
- */
+ * Saves a reference to the original highlighter to enable/disable text
+ * selection.
+ */
protected Highlighter originalHighlighter;
-
-/*
-* Creates a MultiLineLabel instance with an empty string for the title.
-*/
- public MultiLineLabel()
- {
- super();
- // turn on wrapping and disable editing and highlighting
+ /*
+ * Creates a MultiLineLabel instance with an empty string for the title.
+ */
+ public MultiLineLabel() {
+ super();
- setLineWrap(true);
- setWrapStyleWord(true);
- setEditable(false);
- setSelectable( false );
- }
+ // turn on wrapping and disable editing and highlighting
-/*
-* Creates a MultiLineLabel instance with the specified text.
-* @param text The specified text.
-*/
- public MultiLineLabel( String text )
- {
- super( text );
+ setLineWrap(true);
+ setWrapStyleWord(true);
+ setEditable(false);
+ setSelectable(false);
+ }
- // turn on wrapping and disable editing and highlighting
+ /*
+ * Creates a MultiLineLabel instance with the specified text.
+ *
+ * @param text The specified text.
+ */
+ public MultiLineLabel(String text) {
+ super(text);
- setLineWrap(true);
- setWrapStyleWord(true);
- setEditable(false);
- setSelectable( false );
- }
+ // turn on wrapping and disable editing and highlighting
-/*
-* Overridden to look like a label.
-* @param text The specified text.
-*/
- public void updateUI()
- {
- // got the implementation idea from usenet
+ setLineWrap(true);
+ setWrapStyleWord(true);
+ setEditable(false);
+ setSelectable(false);
+ }
- super.updateUI();
+ /*
+ * Overridden to look like a label.
+ *
+ * @param text The specified text.
+ */
+ public void updateUI() {
+ // got the implementation idea from usenet
- // turn on wrapping and disable editing and highlighting
+ super.updateUI();
- setLineWrap(true);
- setWrapStyleWord(true);
- setEditable(false);
- setSelectable( false );
+ // turn on wrapping and disable editing and highlighting
- // Set the text area's border, colors and font to
- // that of a label
+ setLineWrap(true);
+ setWrapStyleWord(true);
+ setEditable(false);
+ setSelectable(false);
- LookAndFeel.installBorder(this, "Label.border");
+ // Set the text area's border, colors and font to
+ // that of a label
- LookAndFeel.installColorsAndFont(this,
- "Label.background",
- "Label.foreground",
- "Label.font");
- }
+ LookAndFeel.installBorder(this, "Label.border");
-/**
-* Sets whether text is selectable.
-* Default is non-selectable text.
-*/
- public void setSelectable( boolean selectable )
- {
- if ( selectable )
- {
- setHighlighter( originalHighlighter );
- }
- else
- {
+ LookAndFeel.installColorsAndFont(this, "Label.background", "Label.foreground", "Label.font");
+ }
+
+ /**
+ * Sets whether text is selectable. Default is non-selectable text.
+ */
+ public void setSelectable(boolean selectable) {
+ if (selectable) {
+ setHighlighter(originalHighlighter);
+ } else {
originalHighlighter = getHighlighter();
- setHighlighter( null );
+ setHighlighter(null);
}
}
-
-/**
-* Gets whether text is selectable.
-* Default is non-selectable text.
-*/
- public boolean isSelectable()
- {
- return ( getHighlighter() != null );
+
+ /**
+ * Gets whether text is selectable. Default is non-selectable text.
+ */
+ public boolean isSelectable() {
+ return (getHighlighter() != null);
}
-/**
-* Overridden to return false.
-*/
- public boolean isFocusTraversable()
- {
+ /**
+ * Overridden to return false.
+ */
+ public boolean isFocusTraversable() {
return false;
- }
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/NumericTextField.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/NumericTextField.java
index b3d2d03..dee8f27 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/NumericTextField.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/NumericTextField.java
@@ -19,416 +19,346 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.ui.swing.components;
/**
-* NumericTextField is a "smart" text field that restricts the user's input. The
-* input is restructed to numeric only wich can be of two types: integer and real
-* numbers. A range can also be placed on the text field. The default type is
-* integer, with the being (Integer.MIN_VALUE, Integer.MAX_VALUE).
-*
-* @author rob@straylight.princeton.com
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class NumericTextField extends SmartTextField
-{
-
-/*******************************
-* CONSTANTS
-*******************************/
-
-/**
-* Restrict the text input to integers (whole numbers) only.
-*/
- public final static int INTEGER = 0;
-
-/**
-* Restrict the text input to floating-point numbers only.
-*/
- public final static int FLOAT = 1;
-
- private Number maximumValue = null;
- private Number minimumValue = null;
-
- private boolean sign = false;
- private int newCaretPosition = 0;
- private int valueType = INTEGER;
-
-
-/*******************************
-* PUBLIC METHODS
-*******************************/
-
-/**
-* Default constructor.
-*/
- public NumericTextField()
- {
- this("", 0);
- }
-
-/**
-* Constructor.
-* @param text The initial string the text field is set to.
-*/
- public NumericTextField(String text)
- {
- this(text, 0);
- }
-
-/**
-* Constructor.
-* @param columns Width of the text field (in characters).
-*/
- public NumericTextField(int columns)
- {
- this("", columns);
- }
-
-/**
-* Constructor.
-* @param text The initial string the text field is set to.
-* @param columns Width of the text field (in characters).
-*/
- public NumericTextField(String text, int columns)
- {
- super(text, columns);
- }
-
-/**
-* Sets the upper limit of the range of numbers to accept.
-* @param newMaximumValue The maximum number accepted by the text field.
-*/
- public void setMaximumValue(double newMaximumValue)
- {
- if (newMaximumValue >= 0)
- {
- maximumValue = new Double( newMaximumValue );
- }
- else
- {
- maximumValue = null;
- }
- }
-
-/**
-* Returns the upper limit of the range of numbers to accept.
-* @return The maximum number accepted by this text field.
-*/
- public double getMaximumValue()
- {
- if ( valueType == INTEGER )
- {
- return (maximumValue == null) ? (double) Integer.MAX_VALUE : maximumValue.doubleValue();
- }
- else
- {
- return (maximumValue == null) ? Double.MAX_VALUE : maximumValue.doubleValue();
- }
- }
-
-/**
-* Sets the lower limit of the range of numbers to accept.
-* @param newMinimumValue The minimum number accepted by the text field.
-*/
- public void setMinimumValue(double newMinimumValue)
- {
- if (newMinimumValue <= 0)
- {
- minimumValue = new Double( newMinimumValue );
- }
- else
- {
- minimumValue = null;
- }
- }
-
-/**
-* Returns the lower limit of the range of numbers to accept.
-* @return The minimum number accepted by this text field.
-*/
- public double getMinimumValue()
- {
- if ( valueType == INTEGER )
- {
- return (minimumValue == null) ? (double) Integer.MIN_VALUE : minimumValue.doubleValue();
- }
- else
- {
- return (minimumValue == null) ? -1.0*Double.MAX_VALUE : minimumValue.doubleValue();
- // NOTE: Double.MIN_VALUE returns the smallest positive value - oooops.
- }
- }
-
-/**
-* Sets which type of number this text field can accept.
-* @see #INTEGER
-* @see #FLOAT
-* @param newValueType The type of number to accept.
-*/
- public void setValueType(int newValueType)
- {
- if ((newValueType != INTEGER) && (newValueType != FLOAT))
- {
- valueType = INTEGER;
- }
- else
- {
- valueType = newValueType;
- }
- }
-
-/**
-* Returns which type of number this text field accepts. The default is
-* integer.
-* @see #INTEGER
-* @see #FLOAT
-* @return The type of number to accept.
-*/
- public int getValueType()
- {
- return valueType;
- }
-
-/**
-* Returns the integer numeric value of the string in the text field. The type
-* can be either integer of float.
-* @return The current value in the text field.
-*/
- public int getIntValue()
- {
- int value = 0;
-
- try
- {
- value = Integer.parseInt(getText());
- }
- catch (NumberFormatException e)
- {
- try
- {
- Double dValue = Double.valueOf(getText());
- value = dValue.intValue();
- }
- catch (NumberFormatException ignored) {}
- }
-
- return value;
- }
-
-/**
-* Sets the text field to integer value specified.
-* @param aValue An integer value to display in the text field.
-*/
- public void setIntValue(int aValue)
- {
- setText(Integer.toString(aValue));
- }
-
-/**
-* Returns the real number numeric value of the string in the text field. The type
-* can be either integer of float.
-* @return The current value in the text field.
-*/
- public double getDoubleValue()
- {
- Double value = new Double(0);
-
- try
- {
- value = Double.valueOf(getText());
- }
- catch (NumberFormatException ignored) {}
-
- return value.doubleValue();
- }
-
-/**
-* Sets the text field to the double value specified. If the text field type is
-* FLOAT then the the number is display as a real number. If the text field
-* type is INTEGER then the number is converted to a whole number for displaying.
-* @param aValue A double value to display in the text field.
-*/
- public void setDoubleValue(double aValue)
- {
- Double temp = new Double(aValue);
-
- if (valueType == FLOAT)
- {
- setText(temp.toString());
- }
- else
- {
- setText(Integer.toString(temp.intValue()));
- }
- }
-
-/*******************************
-* PROTECTED METHODS
-*******************************/
-
- protected boolean isValidCharacter(char aChar)
- {
- if (((aChar >= ' ') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~')))
- {
- if (aChar == '.')
- {
- if ( valueType == FLOAT )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else if (aChar == '-')
- {
- if ( getMinimumValue() < 0 )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else if (aChar == '+')
- {
- if ( getMaximumValue() >= 0 )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- return false;
- }
- return true;
- }
-
- protected boolean isValidString(String aString)
- {
- int iValue = 0;
- double dValue = 0.0;
-
- String tempString = new String(scanForSignChar(aString));
-
- if ( valueType == INTEGER )
- {
- try
- {
- iValue = Integer.parseInt(tempString);
- }
- catch (NumberFormatException e1)
- {
- if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
- {
- iValue = 0;
- }
- else
- {
- return false;
- }
- }
- if ((((double)iValue) < getMinimumValue()) || (((double)iValue) > getMaximumValue()))
- {
- return false;
- }
- }
- else
- {
- // Double.valueOf requires a zero before the decimal point
- if ( tempString.startsWith( "." ) )
- {
- tempString = "0" + tempString;
- }
- try
- {
- dValue = Double.valueOf(tempString).doubleValue();
- }
- catch (NumberFormatException e2)
- {
- if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
- {
- dValue = 0.0;
- }
- else
- {
- return false;
- }
- }
-
- if ((dValue < getMinimumValue()) || (dValue > getMaximumValue()))
- {
- return false;
- }
- }
-
- return true;
- }
-
- protected void postProcessing()
- {
- if (sign)
- {
- setText(scanForSignChar(getText()));
- setCaretPosition(newCaretPosition);
- }
- sign = false;
- }
-
-
-/*******************************
-* PRIVATE METHODS
-*******************************/
-
- private String scanForSignChar(String aString)
- {
- String newString = "";
- boolean positive = false;
- boolean negative = false;
- int oldCaretPosition = getCaretPosition();
- int charactersAdded = 0;
-
- newCaretPosition = 0;
-
- if (aString.length() <= 0)
- {
- return aString;
- }
-
- for (int i = 0; i < aString.length(); ++i)
- {
- switch (aString.charAt(i))
- {
- case '+': positive = true;
- break;
- case '-': negative = true;
- break;
- default: newString += aString.charAt(i);
- charactersAdded++;
- break;
- }
-
- if ((i + 1) == oldCaretPosition)
- {
- newCaretPosition = charactersAdded;
- }
- }
-
- if ((!(positive)) && (negative))
- {
- newString = "-" + newString;
- newCaretPosition++;
- }
-
- if (positive || negative)
- {
- sign = true;
- }
-
- return newString;
- }
+ * NumericTextField is a "smart" text field that restricts the user's input. The
+ * input is restructed to numeric only wich can be of two types: integer and
+ * real numbers. A range can also be placed on the text field. The default type
+ * is integer, with the being (Integer.MIN_VALUE, Integer.MAX_VALUE).
+ *
+ * @author rob@straylight.princeton.com
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class NumericTextField extends SmartTextField {
+
+ /*******************************
+ * CONSTANTS
+ *******************************/
+
+ /**
+ * Restrict the text input to integers (whole numbers) only.
+ */
+ public final static int INTEGER = 0;
+
+ /**
+ * Restrict the text input to floating-point numbers only.
+ */
+ public final static int FLOAT = 1;
+
+ private Number maximumValue = null;
+ private Number minimumValue = null;
+
+ private boolean sign = false;
+ private int newCaretPosition = 0;
+ private int valueType = INTEGER;
+
+ /*******************************
+ * PUBLIC METHODS
+ *******************************/
+
+ /**
+ * Default constructor.
+ */
+ public NumericTextField() {
+ this("", 0);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text The initial string the text field is set to.
+ */
+ public NumericTextField(String text) {
+ this(text, 0);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param columns Width of the text field (in characters).
+ */
+ public NumericTextField(int columns) {
+ this("", columns);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text The initial string the text field is set to.
+ * @param columns Width of the text field (in characters).
+ */
+ public NumericTextField(String text, int columns) {
+ super(text, columns);
+ }
+
+ /**
+ * Sets the upper limit of the range of numbers to accept.
+ *
+ * @param newMaximumValue The maximum number accepted by the text field.
+ */
+ public void setMaximumValue(double newMaximumValue) {
+ if (newMaximumValue >= 0) {
+ maximumValue = new Double(newMaximumValue);
+ } else {
+ maximumValue = null;
+ }
+ }
+
+ /**
+ * Returns the upper limit of the range of numbers to accept.
+ *
+ * @return The maximum number accepted by this text field.
+ */
+ public double getMaximumValue() {
+ if (valueType == INTEGER) {
+ return (maximumValue == null) ? (double) Integer.MAX_VALUE : maximumValue.doubleValue();
+ } else {
+ return (maximumValue == null) ? Double.MAX_VALUE : maximumValue.doubleValue();
+ }
+ }
+
+ /**
+ * Sets the lower limit of the range of numbers to accept.
+ *
+ * @param newMinimumValue The minimum number accepted by the text field.
+ */
+ public void setMinimumValue(double newMinimumValue) {
+ if (newMinimumValue <= 0) {
+ minimumValue = new Double(newMinimumValue);
+ } else {
+ minimumValue = null;
+ }
+ }
+
+ /**
+ * Returns the lower limit of the range of numbers to accept.
+ *
+ * @return The minimum number accepted by this text field.
+ */
+ public double getMinimumValue() {
+ if (valueType == INTEGER) {
+ return (minimumValue == null) ? (double) Integer.MIN_VALUE : minimumValue.doubleValue();
+ } else {
+ return (minimumValue == null) ? -1.0 * Double.MAX_VALUE : minimumValue.doubleValue();
+ // NOTE: Double.MIN_VALUE returns the smallest positive value - oooops.
+ }
+ }
+
+ /**
+ * Sets which type of number this text field can accept.
+ *
+ * @see #INTEGER
+ * @see #FLOAT
+ * @param newValueType The type of number to accept.
+ */
+ public void setValueType(int newValueType) {
+ if ((newValueType != INTEGER) && (newValueType != FLOAT)) {
+ valueType = INTEGER;
+ } else {
+ valueType = newValueType;
+ }
+ }
+
+ /**
+ * Returns which type of number this text field accepts. The default is integer.
+ *
+ * @see #INTEGER
+ * @see #FLOAT
+ * @return The type of number to accept.
+ */
+ public int getValueType() {
+ return valueType;
+ }
+
+ /**
+ * Returns the integer numeric value of the string in the text field. The type
+ * can be either integer of float.
+ *
+ * @return The current value in the text field.
+ */
+ public int getIntValue() {
+ int value = 0;
+
+ try {
+ value = Integer.parseInt(getText());
+ } catch (NumberFormatException e) {
+ try {
+ Double dValue = Double.valueOf(getText());
+ value = dValue.intValue();
+ } catch (NumberFormatException ignored) {
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Sets the text field to integer value specified.
+ *
+ * @param aValue An integer value to display in the text field.
+ */
+ public void setIntValue(int aValue) {
+ setText(Integer.toString(aValue));
+ }
+
+ /**
+ * Returns the real number numeric value of the string in the text field. The
+ * type can be either integer of float.
+ *
+ * @return The current value in the text field.
+ */
+ public double getDoubleValue() {
+ Double value = new Double(0);
+
+ try {
+ value = Double.valueOf(getText());
+ } catch (NumberFormatException ignored) {
+ }
+
+ return value.doubleValue();
+ }
+
+ /**
+ * Sets the text field to the double value specified. If the text field type is
+ * FLOAT then the the number is display as a real number. If the text field type
+ * is INTEGER then the number is converted to a whole number for displaying.
+ *
+ * @param aValue A double value to display in the text field.
+ */
+ public void setDoubleValue(double aValue) {
+ Double temp = new Double(aValue);
+
+ if (valueType == FLOAT) {
+ setText(temp.toString());
+ } else {
+ setText(Integer.toString(temp.intValue()));
+ }
+ }
+
+ /*******************************
+ * PROTECTED METHODS
+ *******************************/
+
+ protected boolean isValidCharacter(char aChar) {
+ if (((aChar >= ' ') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~'))) {
+ if (aChar == '.') {
+ if (valueType == FLOAT) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (aChar == '-') {
+ if (getMinimumValue() < 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (aChar == '+') {
+ if (getMaximumValue() >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ protected boolean isValidString(String aString) {
+ int iValue = 0;
+ double dValue = 0.0;
+
+ String tempString = new String(scanForSignChar(aString));
+
+ if (valueType == INTEGER) {
+ try {
+ iValue = Integer.parseInt(tempString);
+ } catch (NumberFormatException e1) {
+ if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0)) {
+ iValue = 0;
+ } else {
+ return false;
+ }
+ }
+ if ((((double) iValue) < getMinimumValue()) || (((double) iValue) > getMaximumValue())) {
+ return false;
+ }
+ } else {
+ // Double.valueOf requires a zero before the decimal point
+ if (tempString.startsWith(".")) {
+ tempString = "0" + tempString;
+ }
+ try {
+ dValue = Double.valueOf(tempString).doubleValue();
+ } catch (NumberFormatException e2) {
+ if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0)) {
+ dValue = 0.0;
+ } else {
+ return false;
+ }
+ }
+
+ if ((dValue < getMinimumValue()) || (dValue > getMaximumValue())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected void postProcessing() {
+ if (sign) {
+ setText(scanForSignChar(getText()));
+ setCaretPosition(newCaretPosition);
+ }
+ sign = false;
+ }
+
+ /*******************************
+ * PRIVATE METHODS
+ *******************************/
+
+ private String scanForSignChar(String aString) {
+ String newString = "";
+ boolean positive = false;
+ boolean negative = false;
+ int oldCaretPosition = getCaretPosition();
+ int charactersAdded = 0;
+
+ newCaretPosition = 0;
+
+ if (aString.length() <= 0) {
+ return aString;
+ }
+
+ for (int i = 0; i < aString.length(); ++i) {
+ switch (aString.charAt(i)) {
+ case '+':
+ positive = true;
+ break;
+ case '-':
+ negative = true;
+ break;
+ default:
+ newString += aString.charAt(i);
+ charactersAdded++;
+ break;
+ }
+
+ if ((i + 1) == oldCaretPosition) {
+ newCaretPosition = charactersAdded;
+ }
+ }
+
+ if ((!(positive)) && (negative)) {
+ newString = "-" + newString;
+ newCaretPosition++;
+ }
+
+ if (positive || negative) {
+ sign = true;
+ }
+
+ return newString;
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTable.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTable.java
index 9db2834..996f8e0 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTable.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTable.java
@@ -47,233 +47,235 @@ import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
-* PropertyEditorTable is a table designed to display and edit the properties
-* of an object. Because JTable assumes all cells in a column display
-* the same data type, we have to subclass to determine the class
-* based on the cell contents.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * PropertyEditorTable is a table designed to display and edit the properties of
+ * an object. Because JTable assumes all cells in a column display the same data
+ * type, we have to subclass to determine the class based on the cell contents.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class PropertyEditorTable extends JTable {
//
// Constructors
//
- /**
- * Constructs a default JTable which is initialized with a default
- * data model, a default column model, and a default selection
- * model.
- *
- * @see #createDefaultDataModel
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public PropertyEditorTable() {
- super(null, null, null);
- }
-
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, a default column model, and a default selection
- * model.
- *
- * @param dm The data model for the table
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public PropertyEditorTable(TableModel dm) {
- super(dm, null, null);
- }
-
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, <i>cm</i> as the column model, and a default selection
- * model.
- *
- * @param dm The data model for the table
- * @param cm The column model for the table
- * @see #createDefaultSelectionModel
- */
- public PropertyEditorTable(TableModel dm, TableColumnModel cm) {
- super(dm, cm, null);
- }
-
- /**
- * Constructs a JTable which is initialized with <i>dm</i> as the
- * data model, <i>cm</i> as the column model, and <i>sm</i> as the
- * selection model. If any of the parameters are <b>null</b> this
- * method will initialize the table with the corresponding
- * default model. The <i>autoCreateColumnsFromModel</i> flag is set
- * to false if <i>cm</i> is non-null, otherwise it is set to true
- * and the column model is populated with suitable TableColumns
- * for the columns in <i>dm</i>.
- *
- * @param dm The data model for the table
- * @param cm The column model for the table
- * @param sm The row selection model for the table
- * @see #createDefaultDataModel
- * @see #createDefaultColumnModel
- * @see #createDefaultSelectionModel
- */
- public PropertyEditorTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
- super( dm, cm, sm );
+ /**
+ * Constructs a default JTable which is initialized with a default data model, a
+ * default column model, and a default selection model.
+ *
+ * @see #createDefaultDataModel
+ * @see #createDefaultColumnModel
+ * @see #createDefaultSelectionModel
+ */
+ public PropertyEditorTable() {
+ super(null, null, null);
}
- /**
- * Constructs a JTable with <i>numRows</i> and <i>numColumns</i> of
- * empty cells using the DefaultTableModel. The columns will have
- * names of the form "A", "B", "C", etc.
- *
- * @param numRows The number of rows the table holds
- * @param numColumns The number of columns the table holds
- */
- public PropertyEditorTable(int numRows, int numColumns) {
- super( numRows, numColumns );
- }
-
- /**
- * Constructs a JTable to display the values in the Vector of Vectors,
- * <i>rowData</i>, with column names, <i>columnNames</i>.
- * The Vectors contained in <i>rowData</i> should contain the values
- * for that row. In other words, the value of the cell at row 1,
- * column 5 can be obtained with the following code:
- * <p>
- * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
- * <p>
- * All rows must be of the same length as <i>columnNames</i>.
- * <p>
- * @param rowData The data for the new table
- * @param columnNames Names of each column
- */
- public PropertyEditorTable(final Vector rowData, final Vector columnNames) {
- super( rowData, columnNames );
- }
-
- /**
- * Constructs a JTable to display the values in the two dimensional array,
- * <i>rowData</i>, with column names, <i>columnNames</i>.
- * <i>rowData</i> is an Array of rows, so the value of the cell at row 1,
- * column 5 can be obtained with the following code:
- * <p>
- * <pre> rowData[1][5]; </pre>
- * <p>
- * All rows must be of the same length as <i>columnNames</i>.
- * <p>
- * @param rowData The data for the new table
- * @param columnNames Names of each column
- */
- public PropertyEditorTable(final Object[][] rowData, final Object[] columnNames) {
- super( rowData, columnNames );
+ /**
+ * Constructs a JTable which is initialized with <i>dm</i> as the data model, a
+ * default column model, and a default selection model.
+ *
+ * @param dm The data model for the table
+ * @see #createDefaultColumnModel
+ * @see #createDefaultSelectionModel
+ */
+ public PropertyEditorTable(TableModel dm) {
+ super(dm, null, null);
}
- /**
- * Returns the type of the column at the specified view position.
- *
- * @return the type of the column at position <I>column</I> in the view
- * where the first column is column 0.
+ /**
+ * Constructs a JTable which is initialized with <i>dm</i> as the data model,
+ * <i>cm</i> as the column model, and a default selection model.
*
- * Modified mln: now a wrapper for getCellClass()
+ * @param dm The data model for the table
+ * @param cm The column model for the table
+ * @see #createDefaultSelectionModel
+ */
+ public PropertyEditorTable(TableModel dm, TableColumnModel cm) {
+ super(dm, cm, null);
+ }
+
+ /**
+ * Constructs a JTable which is initialized with <i>dm</i> as the data model,
+ * <i>cm</i> as the column model, and <i>sm</i> as the selection model. If any
+ * of the parameters are <b>null</b> this method will initialize the table with
+ * the corresponding default model. The <i>autoCreateColumnsFromModel</i> flag
+ * is set to false if <i>cm</i> is non-null, otherwise it is set to true and the
+ * column model is populated with suitable TableColumns for the columns in
+ * <i>dm</i>.
*
- */
- public Class getColumnClass(int column) {
- return getCellClass( 0, column );
- }
-
- /**
- * Returns the type of the cell at the specified view position.
- *
- * @return the type of the cell at position <I>row</I>, <I>column</I> in the view
- * where the first column is column 0.
+ * @param dm The data model for the table
+ * @param cm The column model for the table
+ * @param sm The row selection model for the table
+ * @see #createDefaultDataModel
+ * @see #createDefaultColumnModel
+ * @see #createDefaultSelectionModel
+ */
+ public PropertyEditorTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
+ super(dm, cm, sm);
+ }
+
+ /**
+ * Constructs a JTable with <i>numRows</i> and <i>numColumns</i> of empty cells
+ * using the DefaultTableModel. The columns will have names of the form "A",
+ * "B", "C", etc.
*
- * Modified mln: new methods
+ * @param numRows The number of rows the table holds
+ * @param numColumns The number of columns the table holds
+ */
+ public PropertyEditorTable(int numRows, int numColumns) {
+ super(numRows, numColumns);
+ }
+
+ /**
+ * Constructs a JTable to display the values in the Vector of Vectors,
+ * <i>rowData</i>, with column names, <i>columnNames</i>. The Vectors contained
+ * in <i>rowData</i> should contain the values for that row. In other words, the
+ * value of the cell at row 1, column 5 can be obtained with the following code:
+ * <p>
+ *
+ * <pre>
+ * ((Vector) rowData.elementAt(1)).elementAt(5);
+ * </pre>
+ * <p>
+ * All rows must be of the same length as <i>columnNames</i>.
+ * <p>
+ *
+ * @param rowData The data for the new table
+ * @param columnNames Names of each column
+ */
+ public PropertyEditorTable(final Vector rowData, final Vector columnNames) {
+ super(rowData, columnNames);
+ }
+
+ /**
+ * Constructs a JTable to display the values in the two dimensional array,
+ * <i>rowData</i>, with column names, <i>columnNames</i>. <i>rowData</i> is an
+ * Array of rows, so the value of the cell at row 1, column 5 can be obtained
+ * with the following code:
+ * <p>
+ *
+ * <pre>
+ * rowData[1][5];
+ * </pre>
+ * <p>
+ * All rows must be of the same length as <i>columnNames</i>.
+ * <p>
+ *
+ * @param rowData The data for the new table
+ * @param columnNames Names of each column
+ */
+ public PropertyEditorTable(final Object[][] rowData, final Object[] columnNames) {
+ super(rowData, columnNames);
+ }
+
+ /**
+ * Returns the type of the column at the specified view position.
+ *
+ * @return the type of the column at position <I>column</I> in the view where
+ * the first column is column 0.
+ *
+ * Modified mln: now a wrapper for getCellClass()
+ *
+ */
+ public Class getColumnClass(int column) {
+ return getCellClass(0, column);
+ }
+
+ /**
+ * Returns the type of the cell at the specified view position.
+ *
+ * @return the type of the cell at position <I>row</I>, <I>column</I> in the
+ * view where the first column is column 0.
*
- */
- public Class getCellClass(int row, int column) {
+ * Modified mln: new methods
+ *
+ */
+ public Class getCellClass(int row, int column) {
TableModel model = getModel();
- if ( model instanceof PropertyEditorTableModel )
- return ((PropertyEditorTableModel)model).getCellClass( row, column );
- else
+ if (model instanceof PropertyEditorTableModel)
+ return ((PropertyEditorTableModel) model).getCellClass(row, column);
+ else
return model.getColumnClass(convertColumnIndexToModel(column));
- }
-
- /**
- * Return an appropriate renderer for the cell specified by this this row and
- * column. If the TableColumn for this column has a non-null renderer, return that.
- * If not, find the class of the data in this column (using getColumnClass())
- * and return the default renderer for this type of data.
- *
- * @param row the row of the cell to render, where 0 is the first
- * @param column the column of the cell to render, where 0 is the first
+ }
+
+ /**
+ * Return an appropriate renderer for the cell specified by this this row and
+ * column. If the TableColumn for this column has a non-null renderer, return
+ * that. If not, find the class of the data in this column (using
+ * getColumnClass()) and return the default renderer for this type of data.
+ *
+ * @param row the row of the cell to render, where 0 is the first
+ * @param column the column of the cell to render, where 0 is the first
+ *
+ * Modified mln: calls getCellClass if there's no column model
*
- * Modified mln: calls getCellClass if there's no column model
+ */
+ public TableCellRenderer getCellRenderer(int row, int column) {
+ TableColumn tableColumn = getColumnModel().getColumn(column);
+ TableCellRenderer renderer = tableColumn.getCellRenderer();
+ if (renderer == null) {
+ renderer = getDefaultRenderer(getCellClass(row, column));
+ }
+ return renderer;
+ }
+
+ /**
+ * Return an appropriate editor for the cell specified by this this row and
+ * column. If the TableColumn for this column has a non-null editor, return
+ * that. If not, find the class of the data in this column (using
+ * getColumnClass()) and return the default editor for this type of data.
*
- */
- public TableCellRenderer getCellRenderer(int row, int column) {
- TableColumn tableColumn = getColumnModel().getColumn(column);
- TableCellRenderer renderer = tableColumn.getCellRenderer();
- if (renderer == null) {
- renderer = getDefaultRenderer(getCellClass(row, column));
- }
- return renderer;
- }
-
-
- /**
- * Return an appropriate editor for the cell specified by this this row and
- * column. If the TableColumn for this column has a non-null editor, return that.
- * If not, find the class of the data in this column (using getColumnClass())
- * and return the default editor for this type of data.
- *
- * @param row the row of the cell to edit, where 0 is the first
- * @param column the column of the cell to edit, where 0 is the first
+ * @param row the row of the cell to edit, where 0 is the first
+ * @param column the column of the cell to edit, where 0 is the first
*
- * Modified mp: calls getCellClass if there's no column model
+ * Modified mp: calls getCellClass if there's no column model
*
- */
- public TableCellEditor getCellEditor(int row, int column) {
- TableColumn tableColumn = getColumnModel().getColumn(column);
- TableCellEditor editor = tableColumn.getCellEditor();
- if (editor == null) {
- editor = getDefaultEditor(getCellClass(row, column));
- }
- return editor;
- }
+ */
+ public TableCellEditor getCellEditor(int row, int column) {
+ TableColumn tableColumn = getColumnModel().getColumn(column);
+ TableCellEditor editor = tableColumn.getCellEditor();
+ if (editor == null) {
+ editor = getDefaultEditor(getCellClass(row, column));
+ }
+ return editor;
+ }
protected void createDefaultRenderers() {
super.createDefaultRenderers();
-/* // copying this code here as a sample of creating a renderer
- // Dates
- DefaultTableCellRenderer dateRenderer = new DefaultTableCellRenderer() {
- DateFormat formatter = DateFormat.getDateInstance();
- public void setValue(Object value) {
- setText((value == null) ? "" : formatter.format(value)); }
- };
- dateRenderer.setHorizontalAlignment(JLabel.RIGHT);
- setDefaultRenderer(Date.class, dateRenderer);
-*/
-
- DefaultTableCellRenderer fontRenderer = new DefaultTableCellRenderer() {
- public void setValue(Object value) {
- setText( getFontDescription( (Font) value ) );
+ /*
+ * // copying this code here as a sample of creating a renderer // Dates
+ * DefaultTableCellRenderer dateRenderer = new DefaultTableCellRenderer() {
+ * DateFormat formatter = DateFormat.getDateInstance(); public void
+ * setValue(Object value) { setText((value == null) ? "" :
+ * formatter.format(value)); } };
+ * dateRenderer.setHorizontalAlignment(JLabel.RIGHT);
+ * setDefaultRenderer(Date.class, dateRenderer);
+ */
+
+ DefaultTableCellRenderer fontRenderer = new DefaultTableCellRenderer() {
+ public void setValue(Object value) {
+ setText(getFontDescription((Font) value));
}
};
- fontRenderer.setHorizontalAlignment(JLabel.RIGHT);
- setDefaultRenderer(Font.class, fontRenderer);
+ fontRenderer.setHorizontalAlignment(JLabel.RIGHT);
+ setDefaultRenderer(Font.class, fontRenderer);
- setUpColorRenderer( this );
- setUpMethodRenderer( this );
- }
+ setUpColorRenderer(this);
+ setUpMethodRenderer(this);
+ }
- protected String getFontDescription( Font f ) {
+ protected String getFontDescription(Font f) {
String s;
- if ( f != null ) {
+ if (f != null) {
s = f.getName();
- if ( f.isBold() ) s += " Bold";
- if ( f.isItalic() ) s += " Italic";
+ if (f.isBold())
+ s += " Bold";
+ if (f.isItalic())
+ s += " Italic";
s += " " + f.getSize();
} else {
s = "";
@@ -281,292 +283,263 @@ public class PropertyEditorTable extends JTable {
return s;
}
- protected void createDefaultEditors() {
+ protected void createDefaultEditors() {
super.createDefaultEditors();
-/* // copying this code here as a sample of creating an editor
- // Numbers
- JTextField rightAlignedTextField = new JTextField();
- rightAlignedTextField.setHorizontalAlignment(JTextField.RIGHT);
- rightAlignedTextField.setBorder(new LineBorder(Color.black));
- setDefaultEditor(Number.class, new DefaultCellEditor(rightAlignedTextField));
-
- // Booleans
- JCheckBox centeredCheckBox = new JCheckBox();
- centeredCheckBox.setHorizontalAlignment(JCheckBox.CENTER);
- setDefaultEditor(Boolean.class, new DefaultCellEditor(centeredCheckBox));
-*/
- setUpColorEditor( this );
- setUpMethodEditor( this );
+ /*
+ * // copying this code here as a sample of creating an editor // Numbers
+ * JTextField rightAlignedTextField = new JTextField();
+ * rightAlignedTextField.setHorizontalAlignment(JTextField.RIGHT);
+ * rightAlignedTextField.setBorder(new LineBorder(Color.black));
+ * setDefaultEditor(Number.class, new DefaultCellEditor(rightAlignedTextField));
+ *
+ * // Booleans JCheckBox centeredCheckBox = new JCheckBox();
+ * centeredCheckBox.setHorizontalAlignment(JCheckBox.CENTER);
+ * setDefaultEditor(Boolean.class, new DefaultCellEditor(centeredCheckBox));
+ */
+ setUpColorEditor(this);
+ setUpMethodEditor(this);
}
-
- // following code lifted from:
+ // following code lifted from:
// http://java.sun.com/docs/books/tutorial/ui/swing/example-swing/TableDialogEditDemo.java
- class ColorRenderer extends JLabel
- implements TableCellRenderer {
- Border unselectedBorder = null;
- Border selectedBorder = null;
- boolean isBordered = true;
-
- public ColorRenderer(boolean isBordered) {
- super();
- this.isBordered = isBordered;
- this.setOpaque(true); //MUST do this for background to show up.
- }
-
- public Component getTableCellRendererComponent(
- JTable table, Object color,
- boolean isSelected, boolean hasFocus,
- int row, int column) {
- this.setBackground((Color)color);
- if (isBordered) {
- if (isSelected) {
- if (selectedBorder == null) {
- selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
- table.getSelectionBackground());
- }
- this.setBorder(selectedBorder);
- } else {
- if (unselectedBorder == null) {
- unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
- table.getBackground());
- }
- this.setBorder(unselectedBorder);
- }
- }
- return this;
- }
- }
-
- private void setUpColorRenderer(JTable table) {
- table.setDefaultRenderer(Color.class,
- new ColorRenderer(true));
- }
-
- //Set up the editor for the Color cells.
- private void setUpColorEditor(JTable table) {
- //First, set up the button that brings up the dialog.
- final JButton button = new JButton("") {
- public void setText(String s) {
- //Button never shows text -- only color.
- }
- };
- button.setBackground(Color.white);
- button.setBorderPainted(false);
- button.setMargin(new Insets(0,0,0,0));
-
- //Now create an editor to encapsulate the button, and
- //set it up as the editor for all Color cells.
- final ColorEditor colorEditor = new ColorEditor(button);
- table.setDefaultEditor(Color.class, colorEditor);
-
- //Set up the dialog that the button brings up.
- final JColorChooser colorChooser = new JColorChooser();
- //XXX: PENDING: add the following when setPreviewPanel
- //XXX: starts working.
- //JComponent preview = new ColorRenderer(false);
- //preview.setPreferredSize(new Dimension(50, 10));
- //colorChooser.setPreviewPanel(preview);
- ActionListener okListener = new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- colorEditor.currentColor = colorChooser.getColor();
- }
- };
- final JDialog dialog = JColorChooser.createDialog(button,
- "Pick a Color",
- true,
- colorChooser,
- okListener,
- null); //XXXDoublecheck this is OK
-
- //Here's the code that brings up the dialog.
- button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- button.setBackground(colorEditor.currentColor);
- colorChooser.setColor(colorEditor.currentColor);
- //Without the following line, the dialog comes up
- //in the middle of the screen.
- //dialog.setLocationRelativeTo(button);
- dialog.show();
- }
- });
- }
-
- /*
- * The editor button that brings up the dialog.
- * We extend DefaultCellEditor for convenience,
- * even though it mean we have to create a dummy
- * check box. Another approach would be to copy
- * the implementation of TableCellEditor methods
- * from the source code for DefaultCellEditor.
- */
- class ColorEditor extends DefaultCellEditor {
- Color currentColor = null;
-
- public ColorEditor(JButton b) {
- super(new JCheckBox()); //Unfortunately, the constructor
- //expects a check box, combo box,
- //or text field.
- editorComponent = b;
- setClickCountToStart(1); //This is usually 1 or 2.
-
- //Must do this so that editing stops when appropriate.
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- fireEditingStopped();
- }
- });
- }
-
- protected void fireEditingStopped() {
- super.fireEditingStopped();
- }
-
- public Object getCellEditorValue() {
- return currentColor;
- }
-
- public Component getTableCellEditorComponent(JTable table,
- Object value,
- boolean isSelected,
- int row,
- int column) {
- ((JButton)editorComponent).setText(value.toString());
- currentColor = (Color)value;
- return editorComponent;
- }
- }
-
- class MethodRenderer extends JLabel
- implements TableCellRenderer {
-
- Method theMethod = null;
- JTable theTable = null;
-
- public MethodRenderer() {
- super();
- }
-
- public Component getTableCellRendererComponent(
- JTable table, Object method,
- boolean isSelected, boolean hasFocus,
- int row, int column) {
- theMethod = (Method) method;
- theTable = table;
- setText( " " + theMethod.getReturnType().getName() );
- return this;
- }
- }
-
- private void setUpMethodRenderer(JTable table) {
- table.setDefaultRenderer(Method.class,
- new MethodRenderer());
- }
-
- /*
- * We extend DefaultCellEditor for convenience,
- * as with ColorEditor.
- */
- class MethodEditor extends DefaultCellEditor {
- Method theMethod = null;
- JTable theTable = null;
-
- public MethodEditor(JButton b) {
- super(new JCheckBox()); //Unfortunately, the constructor
- //expects a check box, combo box,
- //or text field.
- editorComponent = b;
- setClickCountToStart(1); //This is usually 1 or 2.
-
- //Must do this so that editing stops when appropriate.
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- fireEditingStopped();
- }
- });
- }
-
- protected void fireEditingStopped() {
- super.fireEditingStopped();
- }
-
- public Object getCellEditorValue() {
- return theMethod;
- }
-
- public Component getTableCellEditorComponent(JTable table,
- Object value,
- boolean isSelected,
- int row,
- int column) {
- ((JButton)editorComponent).setText(value.toString());
- theMethod = (Method)value;
- theTable = table;
- return editorComponent;
- }
- }
-
- //Set up the editor for the Method cells.
- private void setUpMethodEditor(PropertyEditorTable table) {
- //First, set up the button that brings up the dialog.
- final JButton button = new JButton("invoking method") {
- public void setText(String s) {
- //Button never shows text -- only color.
- }
- };
- button.setBackground(Color.white);
- button.setBorderPainted(false);
- button.setMargin(new Insets(0,0,0,0));
-
- //Now create an editor to encapsulate the button, and
- //set it up as the editor for all Color cells.
- final MethodEditor methodEditor = new MethodEditor(button);
- table.setDefaultEditor(Method.class, methodEditor);
-
- // handle the button-click
- final PropertyEditorTable theTable = table;
- button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
-
- Component parent = SwingUtilities.getRoot( theTable );
- if ( parent == null ) parent = theTable;
-
- Cursor oldCursor = parent.getCursor();
- parent.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
-
- Object result = null;
- Object inspectedObject = ((PropertyEditorTableModel)
- methodEditor.theTable.getModel()).inspectedObject;
- try
- {
- methodEditor.theMethod.setAccessible( true );
- result = methodEditor.theMethod.invoke(
- inspectedObject, (Object[])null );
- }
- catch ( Exception exc )
- {
- System.err.println( "PropertyEditorTable.MethodRenderer.actionPerformed: " +
- "Error occurred: " + exc );
- }
- theTable.methodInvoked( inspectedObject, methodEditor.theMethod, result );
-
- parent.setCursor( oldCursor );
- }
- });
- }
+ class ColorRenderer extends JLabel implements TableCellRenderer {
+ Border unselectedBorder = null;
+ Border selectedBorder = null;
+ boolean isBordered = true;
-/**
-* Called by the method cell editor when a method is invoked.
-* @param anObject The object upon which the method was invoked.
-* @param aMethod The method that was invoked.
-* @param aResult The result of the method invocation; may be null.
-*/
- public void methodInvoked( Object anObject, Method aMethod, Object aResult )
- {
- System.out.println( aMethod.getName() + ": " + aResult );
- }
-}
+ public ColorRenderer(boolean isBordered) {
+ super();
+ this.isBordered = isBordered;
+ this.setOpaque(true); // MUST do this for background to show up.
+ }
+ public Component getTableCellRendererComponent(JTable table, Object color, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ this.setBackground((Color) color);
+ if (isBordered) {
+ if (isSelected) {
+ if (selectedBorder == null) {
+ selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5, table.getSelectionBackground());
+ }
+ this.setBorder(selectedBorder);
+ } else {
+ if (unselectedBorder == null) {
+ unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5, table.getBackground());
+ }
+ this.setBorder(unselectedBorder);
+ }
+ }
+ return this;
+ }
+ }
+
+ private void setUpColorRenderer(JTable table) {
+ table.setDefaultRenderer(Color.class, new ColorRenderer(true));
+ }
+ // Set up the editor for the Color cells.
+ private void setUpColorEditor(JTable table) {
+ // First, set up the button that brings up the dialog.
+ final JButton button = new JButton("") {
+ public void setText(String s) {
+ // Button never shows text -- only color.
+ }
+ };
+ button.setBackground(Color.white);
+ button.setBorderPainted(false);
+ button.setMargin(new Insets(0, 0, 0, 0));
+
+ // Now create an editor to encapsulate the button, and
+ // set it up as the editor for all Color cells.
+ final ColorEditor colorEditor = new ColorEditor(button);
+ table.setDefaultEditor(Color.class, colorEditor);
+
+ // Set up the dialog that the button brings up.
+ final JColorChooser colorChooser = new JColorChooser();
+ // XXX: PENDING: add the following when setPreviewPanel
+ // XXX: starts working.
+ // JComponent preview = new ColorRenderer(false);
+ // preview.setPreferredSize(new Dimension(50, 10));
+ // colorChooser.setPreviewPanel(preview);
+ ActionListener okListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ colorEditor.currentColor = colorChooser.getColor();
+ }
+ };
+ final JDialog dialog = JColorChooser.createDialog(button, "Pick a Color", true, colorChooser, okListener, null); // XXXDoublecheck
+ // this
+ // is
+ // OK
+
+ // Here's the code that brings up the dialog.
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ button.setBackground(colorEditor.currentColor);
+ colorChooser.setColor(colorEditor.currentColor);
+ // Without the following line, the dialog comes up
+ // in the middle of the screen.
+ // dialog.setLocationRelativeTo(button);
+ dialog.show();
+ }
+ });
+ }
+
+ /*
+ * The editor button that brings up the dialog. We extend DefaultCellEditor for
+ * convenience, even though it mean we have to create a dummy check box. Another
+ * approach would be to copy the implementation of TableCellEditor methods from
+ * the source code for DefaultCellEditor.
+ */
+ class ColorEditor extends DefaultCellEditor {
+ Color currentColor = null;
+
+ public ColorEditor(JButton b) {
+ super(new JCheckBox()); // Unfortunately, the constructor
+ // expects a check box, combo box,
+ // or text field.
+ editorComponent = b;
+ setClickCountToStart(1); // This is usually 1 or 2.
+
+ // Must do this so that editing stops when appropriate.
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ fireEditingStopped();
+ }
+ });
+ }
+
+ protected void fireEditingStopped() {
+ super.fireEditingStopped();
+ }
+
+ public Object getCellEditorValue() {
+ return currentColor;
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
+ int column) {
+ ((JButton) editorComponent).setText(value.toString());
+ currentColor = (Color) value;
+ return editorComponent;
+ }
+ }
+
+ class MethodRenderer extends JLabel implements TableCellRenderer {
+
+ Method theMethod = null;
+ JTable theTable = null;
+
+ public MethodRenderer() {
+ super();
+ }
+
+ public Component getTableCellRendererComponent(JTable table, Object method, boolean isSelected,
+ boolean hasFocus, int row, int column) {
+ theMethod = (Method) method;
+ theTable = table;
+ setText(" " + theMethod.getReturnType().getName());
+ return this;
+ }
+ }
+
+ private void setUpMethodRenderer(JTable table) {
+ table.setDefaultRenderer(Method.class, new MethodRenderer());
+ }
+
+ /*
+ * We extend DefaultCellEditor for convenience, as with ColorEditor.
+ */
+ class MethodEditor extends DefaultCellEditor {
+ Method theMethod = null;
+ JTable theTable = null;
+
+ public MethodEditor(JButton b) {
+ super(new JCheckBox()); // Unfortunately, the constructor
+ // expects a check box, combo box,
+ // or text field.
+ editorComponent = b;
+ setClickCountToStart(1); // This is usually 1 or 2.
+
+ // Must do this so that editing stops when appropriate.
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ fireEditingStopped();
+ }
+ });
+ }
+
+ protected void fireEditingStopped() {
+ super.fireEditingStopped();
+ }
+
+ public Object getCellEditorValue() {
+ return theMethod;
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
+ int column) {
+ ((JButton) editorComponent).setText(value.toString());
+ theMethod = (Method) value;
+ theTable = table;
+ return editorComponent;
+ }
+ }
+
+ // Set up the editor for the Method cells.
+ private void setUpMethodEditor(PropertyEditorTable table) {
+ // First, set up the button that brings up the dialog.
+ final JButton button = new JButton("invoking method") {
+ public void setText(String s) {
+ // Button never shows text -- only color.
+ }
+ };
+ button.setBackground(Color.white);
+ button.setBorderPainted(false);
+ button.setMargin(new Insets(0, 0, 0, 0));
+
+ // Now create an editor to encapsulate the button, and
+ // set it up as the editor for all Color cells.
+ final MethodEditor methodEditor = new MethodEditor(button);
+ table.setDefaultEditor(Method.class, methodEditor);
+
+ // handle the button-click
+ final PropertyEditorTable theTable = table;
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+
+ Component parent = SwingUtilities.getRoot(theTable);
+ if (parent == null)
+ parent = theTable;
+
+ Cursor oldCursor = parent.getCursor();
+ parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+ Object result = null;
+ Object inspectedObject = ((PropertyEditorTableModel) methodEditor.theTable.getModel()).inspectedObject;
+ try {
+ methodEditor.theMethod.setAccessible(true);
+ result = methodEditor.theMethod.invoke(inspectedObject, (Object[]) null);
+ } catch (Exception exc) {
+ System.err
+ .println("PropertyEditorTable.MethodRenderer.actionPerformed: " + "Error occurred: " + exc);
+ }
+ theTable.methodInvoked(inspectedObject, methodEditor.theMethod, result);
+
+ parent.setCursor(oldCursor);
+ }
+ });
+ }
+
+ /**
+ * Called by the method cell editor when a method is invoked.
+ *
+ * @param anObject The object upon which the method was invoked.
+ * @param aMethod The method that was invoked.
+ * @param aResult The result of the method invocation; may be null.
+ */
+ public void methodInvoked(Object anObject, Method aMethod, Object aResult) {
+ System.out.println(aMethod.getName() + ": " + aResult);
+ }
+}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTableModel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTableModel.java
index f6a2a8d..f6f80f2 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTableModel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/PropertyEditorTableModel.java
@@ -31,30 +31,28 @@ import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;
/**
-* PropertyEditorTableModel introspects an object to facilitate
-* editing it in a PropertyTable.
-*
-* Because the model always reflects the current state of the
-* inspected object, it is useful to have a table update at
-* automated intervals. By default, this feature is turned off.
-* If you turn it on, you'll want to remember to turn it off
-* when you're done with the table model.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class PropertyEditorTableModel extends AbstractTableModel implements ActionListener
-{
+ * PropertyEditorTableModel introspects an object to facilitate editing it in a
+ * PropertyTable.
+ *
+ * Because the model always reflects the current state of the inspected object,
+ * it is useful to have a table update at automated intervals. By default, this
+ * feature is turned off. If you turn it on, you'll want to remember to turn it
+ * off when you're done with the table model.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class PropertyEditorTableModel extends AbstractTableModel implements ActionListener {
protected Object inspectedObject = null;
final String[] columnNames = { "Property", "Value" };
- static final String METHOD_TAG = " ";
+ static final String METHOD_TAG = " ";
Vector properties = new Vector();
Hashtable methods = new Hashtable(0);
- public void setObject( Object o ) {
+ public void setObject(Object o) {
inspectedObject = o;
Class c = o.getClass();
Method[] m = c.getMethods();
@@ -62,67 +60,56 @@ public class PropertyEditorTableModel extends AbstractTableModel implements Acti
properties = new Vector();
methods = new Hashtable(m.length, 1F);
String name, propertyName;
- for ( int i = 0; i < m.length; i++ ) {
+ for (int i = 0; i < m.length; i++) {
// if ( m[i].getName().startsWith( "get" ) )
// System.out.println( m[i].getName() + ": " + m[i].getReturnType().getName() );
// get methods
- if (
- ( ( m[i].getName().startsWith( "get" ) ) || ( m[i].getName().startsWith( "is" ) ) )
- && ( m[i].getParameterTypes().length == 0 )
- ) {
- name = m[i].getName();
- if ( m[i].getName().startsWith( "is" ) ) {
- propertyName = name.substring( 2, name.length() );
- // probably should only add "is" methods if accompanied by "set" method
- } else { // "get"
- propertyName = name.substring( 3, name.length() );
- }
- if (
- ( m[i].getReturnType().getName().equals( String.class.getName() ) )
- || ( m[i].getReturnType().getName().equals( "boolean" ) )
- || ( m[i].getReturnType().getName().equals( "int" ) )
- || ( m[i].getReturnType().getName().equals( "float" ) )
- || ( m[i].getReturnType().getName().equals( "char" ) )
- || ( m[i].getReturnType().getName().equals( Color.class.getName() ) )
- || ( m[i].getReturnType().getName().equals( Font.class.getName() ) )
- ) {
- properties.addElement( propertyName ); // put property
- methods.put( name, m[i] ); // put method
+ if (((m[i].getName().startsWith("get")) || (m[i].getName().startsWith("is")))
+ && (m[i].getParameterTypes().length == 0)) {
+ name = m[i].getName();
+ if (m[i].getName().startsWith("is")) {
+ propertyName = name.substring(2, name.length());
+ // probably should only add "is" methods if accompanied by "set" method
+ } else { // "get"
+ propertyName = name.substring(3, name.length());
}
- else
- {
- // handle unknown types as invokable methods:
- properties.addElement( propertyName + METHOD_TAG );
- methods.put( propertyName + METHOD_TAG, m[i] );
- }
- }
- else
+ if ((m[i].getReturnType().getName().equals(String.class.getName()))
+ || (m[i].getReturnType().getName().equals("boolean"))
+ || (m[i].getReturnType().getName().equals("int"))
+ || (m[i].getReturnType().getName().equals("float"))
+ || (m[i].getReturnType().getName().equals("char"))
+ || (m[i].getReturnType().getName().equals(Color.class.getName()))
+ || (m[i].getReturnType().getName().equals(Font.class.getName()))) {
+ properties.addElement(propertyName); // put property
+ methods.put(name, m[i]); // put method
+ } else {
+ // handle unknown types as invokable methods:
+ properties.addElement(propertyName + METHOD_TAG);
+ methods.put(propertyName + METHOD_TAG, m[i]);
+ }
+ } else
// set methods
- if ( ( m[i].getName().startsWith( "set" ) ) &&
- ( m[i].getParameterTypes().length == 1 ) ) {
+ if ((m[i].getName().startsWith("set")) && (m[i].getParameterTypes().length == 1)) {
name = m[i].getName();
- if (
- ( m[i].getParameterTypes()[0].getName().equals( String.class.getName() ) )
- || ( m[i].getParameterTypes()[0].getName().equals( "boolean" ) )
- || ( m[i].getParameterTypes()[0].getName().equals( "int" ) )
- || ( m[i].getParameterTypes()[0].getName().equals( "float" ) )
- || ( m[i].getParameterTypes()[0].getName().equals( Color.class.getName() ) )
+ if ((m[i].getParameterTypes()[0].getName().equals(String.class.getName()))
+ || (m[i].getParameterTypes()[0].getName().equals("boolean"))
+ || (m[i].getParameterTypes()[0].getName().equals("int"))
+ || (m[i].getParameterTypes()[0].getName().equals("float"))
+ || (m[i].getParameterTypes()[0].getName().equals(Color.class.getName()))
// || ( m[i].getParameterTypes()[0].getName().equals( Font.class.getName() ) )
) {
// System.out.println( "Accepted: " + name + ": " + m[i].getParameterTypes()[0].getName() );
- methods.put( name, m[i] ); // set method
+ methods.put(name, m[i]); // set method
} else {
// System.out.println( "Rejected: " + name + ": " + m[i].getParameterTypes()[0].getName() );
}
+ } else
+ // zero-parameter methods to be invoked on click
+ if (m[i].getParameterTypes().length == 0) {
+ properties.addElement(m[i].getName() + METHOD_TAG);
+ methods.put(m[i].getName() + METHOD_TAG, m[i]);
}
- else
- // zero-parameter methods to be invoked on click
- if ( m[i].getParameterTypes().length == 0 )
- {
- properties.addElement( m[i].getName() + METHOD_TAG );
- methods.put( m[i].getName() + METHOD_TAG, m[i] );
- }
}
@@ -131,288 +118,259 @@ public class PropertyEditorTableModel extends AbstractTableModel implements Acti
}
public int getColumnCount() {
- return columnNames.length;
+ return columnNames.length;
}
public int getRowCount() {
- return properties.size();
+ return properties.size();
}
public String getColumnName(int col) {
- return columnNames[col];
+ return columnNames[col];
}
public Object getValueAt(int row, int col) {
- if ( col == 0 )
- return properties.elementAt( row );
- else
- {
+ if (col == 0)
+ return properties.elementAt(row);
+ else {
Method m = null;
- m = (Method) methods.get( "get" + ( (String) properties.elementAt( row ) ) ) ;
- if ( m == null ) // try "is"
- m = (Method) methods.get( "is" + ( (String) properties.elementAt( row ) ) ) ;
- if ( m == null ) { // try entire method name
- m = (Method) methods.get( (String) properties.elementAt( row ) ) ;
- if ( m != null ) return m;
- }
+ m = (Method) methods.get("get" + ((String) properties.elementAt(row)));
+ if (m == null) // try "is"
+ m = (Method) methods.get("is" + ((String) properties.elementAt(row)));
+ if (m == null) { // try entire method name
+ m = (Method) methods.get((String) properties.elementAt(row));
+ if (m != null)
+ return m;
+ }
try {
- return m.invoke( inspectedObject, (Object[])null );
- } catch ( Exception exc ) {
- System.out.println( "InspectorFrame.tableModel.getValueAt: error occured while reflecting: " );
- System.out.println( exc );
+ return m.invoke(inspectedObject, (Object[]) null);
+ } catch (Exception exc) {
+ System.out.println("InspectorFrame.tableModel.getValueAt: error occured while reflecting: ");
+ System.out.println(exc);
}
return null;
}
}
- public Class getColumnClass( int col ) {
+ public Class getColumnClass(int col) {
// System.out.println( "getColumnClass" );
-/* try {
- throw new Exception();
- } catch ( Exception exc ) {
- exc.printStackTrace( System.out );
- }
-*/ return new String().getClass();
+ /*
+ * try { throw new Exception(); } catch ( Exception exc ) { exc.printStackTrace(
+ * System.out ); }
+ */ return new String().getClass();
}
public Class getCellClass(int row, int col) {
// System.out.println( "getCellClass" );
-/*
-
- Class c;
- Method m = (Method) methods.get( "set" + ( (String) properties.elementAt( row ) ) ) ;
- if ( m == null )
- c = new Object().getClass();
- else {
- c = m.getParameterTypes()[0];
-
- // special case for boolean
- if ( c.getName().equals( "boolean" ) )
- c = new Boolean(true).getClass();
-
- // special case for int
- if ( c.getName().equals( "int" ) )
- c = new Integer(0).getClass();
- }
- System.out.println( row + ": " + c.getName() );
- return c;
-*/
+ /*
+ *
+ * Class c; Method m = (Method) methods.get( "set" + ( (String)
+ * properties.elementAt( row ) ) ) ; if ( m == null ) c = new
+ * Object().getClass(); else { c = m.getParameterTypes()[0];
+ *
+ * // special case for boolean if ( c.getName().equals( "boolean" ) ) c = new
+ * Boolean(true).getClass();
+ *
+ * // special case for int if ( c.getName().equals( "int" ) ) c = new
+ * Integer(0).getClass(); } System.out.println( row + ": " + c.getName() );
+ * return c;
+ */
// return new String().getClass();
- Object o = getValueAt( row, col );
- if ( o == null ) o = "null";
+ Object o = getValueAt(row, col);
+ if (o == null)
+ o = "null";
return o.getClass();
}
/*
- * Don't need to implement this method unless your table's
- * editable.
- */
+ * Don't need to implement this method unless your table's editable.
+ */
public boolean isCellEditable(int row, int col) {
- //Note that the data/cell address is constant,
- //no matter where the cell appears onscreen.
- if (col < 1) {
- return false;
- } else {
- // handle method invocation
- if ( ((String)properties.elementAt(row)).endsWith(METHOD_TAG) ) return true;
- // handle read-only properties
- Method m = (Method) methods.get( "set" + ( (String) properties.elementAt( row ) ) ) ;
- if ( m == null )
+ // Note that the data/cell address is constant,
+ // no matter where the cell appears onscreen.
+ if (col < 1) {
return false;
- else
- return true;
- }
+ } else {
+ // handle method invocation
+ if (((String) properties.elementAt(row)).endsWith(METHOD_TAG))
+ return true;
+ // handle read-only properties
+ Method m = (Method) methods.get("set" + ((String) properties.elementAt(row)));
+ if (m == null)
+ return false;
+ else
+ return true;
+ }
}
/*
- * Don't need to implement this method unless your table's
- * data can change.
- */
+ * Don't need to implement this method unless your table's data can change.
+ */
public void setValueAt(Object value, int row, int col) {
- // test for inspected object
- if ( inspectedObject == null ) return;
- // handle method invocation - no need to update values
- if ( ((String)properties.elementAt(row)).endsWith( METHOD_TAG ) )
- {
- fireTableDataChanged();
- return;
- };
-
- // handle writable properties
- Method m = (Method) methods.get( "set" + ( (String) properties.elementAt( row ) ) ) ;
+ // test for inspected object
+ if (inspectedObject == null)
+ return;
+ // handle method invocation - no need to update values
+ if (((String) properties.elementAt(row)).endsWith(METHOD_TAG)) {
+ fireTableDataChanged();
+ return;
+ }
+ ;
+
+ // handle writable properties
+ Method m = (Method) methods.get("set" + ((String) properties.elementAt(row)));
String parameterType = m.getParameterTypes()[0].getName();
// ugly cast code
- if (
- ( parameterType.equals( "int" ) )
- || ( parameterType.equals( "java.lang.Integer" ) )
- )
- {
- try {
- value = new Integer((String)value);
- } catch (NumberFormatException e) {
- System.out.println("PropertyEditorTableModel.setValueAt: User attempted to enter non-integer"
- + " value (" + value
- + ") into an integer-only column.");
- }
+ if ((parameterType.equals("int")) || (parameterType.equals("java.lang.Integer"))) {
+ try {
+ value = new Integer((String) value);
+ } catch (NumberFormatException e) {
+ System.out.println("PropertyEditorTableModel.setValueAt: User attempted to enter non-integer"
+ + " value (" + value + ") into an integer-only column.");
+ }
}
Object[] parameters = { value };
try {
- m.invoke( inspectedObject, parameters );
- if ( inspectedObject instanceof Component ) {
- Component c = (Component)inspectedObject;
- if ( c.getParent() != null )
+ m.invoke(inspectedObject, parameters);
+ if (inspectedObject instanceof Component) {
+ Component c = (Component) inspectedObject;
+ if (c.getParent() != null)
c.getParent().repaint();
}
- } catch ( Exception exc ) {
- System.out.println( "PropertyEditorTableModel.setValueAt: error occured while reflecting: " );
- System.out.println( exc );
+ } catch (Exception exc) {
+ System.out.println("PropertyEditorTableModel.setValueAt: error occured while reflecting: ");
+ System.out.println(exc);
}
fireTableDataChanged();
}
+ protected void sort(Vector v) {
+ quickSort(v, 0, v.size() - 1);
+ }
- protected void sort(Vector v){
- quickSort(v, 0, v.size()-1);
- }
-
-
- // Liberated from the BasicDirectoryModel which was...
- // Liberated from the 1.1 SortDemo
-
- // This is a generic version of C.A.R Hoare's Quick Sort
- // algorithm. This will handle arrays that are already
- // sorted, and arrays with duplicate keys.<BR>
- //
- // If you think of a one dimensional array as going from
- // the lowest index on the left to the highest index on the right
- // then the parameters to this function are lowest index or
- // left and highest index or right. The first time you call
- // this function it will be with the parameters 0, a.length - 1.
- //
- // @param a an integer array
- // @param lo0 left boundary of array partition
- // @param hi0 right boundary of array partition
- private void quickSort(Vector v, int lo0, int hi0) {
- int lo = lo0;
- int hi = hi0;
- String mid;
-
- if (hi0 > lo0) {
- // Arbitrarily establishing partition element as the midpoint of
- // the array.
- mid = (String) v.elementAt((lo0 + hi0) / 2);
-
- // loop through the array until indices cross
- while(lo <= hi) {
- // find the first element that is greater than or equal to
- // the partition element starting from the left Index.
- //
- // Nasty to have to cast here. Would it be quicker
- // to copy the vectors into arrays and sort the arrays?
- while((lo < hi0) && lt((String)v.elementAt(lo), mid)) {
- ++lo;
- }
+ // Liberated from the BasicDirectoryModel which was...
+ // Liberated from the 1.1 SortDemo
+
+ // This is a generic version of C.A.R Hoare's Quick Sort
+ // algorithm. This will handle arrays that are already
+ // sorted, and arrays with duplicate keys.<BR>
+ //
+ // If you think of a one dimensional array as going from
+ // the lowest index on the left to the highest index on the right
+ // then the parameters to this function are lowest index or
+ // left and highest index or right. The first time you call
+ // this function it will be with the parameters 0, a.length - 1.
+ //
+ // @param a an integer array
+ // @param lo0 left boundary of array partition
+ // @param hi0 right boundary of array partition
+ private void quickSort(Vector v, int lo0, int hi0) {
+ int lo = lo0;
+ int hi = hi0;
+ String mid;
+
+ if (hi0 > lo0) {
+ // Arbitrarily establishing partition element as the midpoint of
+ // the array.
+ mid = (String) v.elementAt((lo0 + hi0) / 2);
+
+ // loop through the array until indices cross
+ while (lo <= hi) {
+ // find the first element that is greater than or equal to
+ // the partition element starting from the left Index.
+ //
+ // Nasty to have to cast here. Would it be quicker
+ // to copy the vectors into arrays and sort the arrays?
+ while ((lo < hi0) && lt((String) v.elementAt(lo), mid)) {
+ ++lo;
+ }
+
+ // find an element that is smaller than or equal to
+ // the partition element starting from the right Index.
+ while ((hi > lo0) && lt(mid, (String) v.elementAt(hi))) {
+ --hi;
+ }
+
+ // if the indexes have not crossed, swap
+ if (lo <= hi) {
+ swap(v, lo, hi);
+ ++lo;
+ --hi;
+ }
+ }
+
+ // If the right index has not reached the left side of array
+ // must now sort the left partition.
+ if (lo0 < hi) {
+ quickSort(v, lo0, hi);
+ }
+
+ // If the left index has not reached the right side of array
+ // must now sort the right partition.
+ if (lo < hi0) {
+ quickSort(v, lo, hi0);
+ }
- // find an element that is smaller than or equal to
- // the partition element starting from the right Index.
- while((hi > lo0) && lt(mid, (String)v.elementAt(hi))) {
- --hi;
}
+ }
+
+ private void swap(Vector a, int i, int j) {
+ Object T = a.elementAt(i);
+ a.setElementAt(a.elementAt(j), i);
+ a.setElementAt(T, j);
+ }
+
+ protected boolean lt(String a, String b) {
+ return a.compareTo(b) < 0;
+ }
+
+ // automated updates
- // if the indexes have not crossed, swap
- if(lo <= hi) {
- swap(v, lo, hi);
- ++lo;
- --hi;
+ private boolean autoUpdating = false;
+ private int updateInterval = 2000; // one-second delay on average
+ protected Timer timer = null;
+
+ public boolean isAutoUpdating() {
+ return autoUpdating;
+ }
+
+ public void setAutoUpdating(boolean shouldAutoUpdate) {
+ if (shouldAutoUpdate) {
+ if (timer == null) {
+ timer = new Timer(updateInterval, this);
+ timer.setRepeats(true);
+ timer.start();
+ }
+ } else {
+ if (timer != null) {
+ timer.stop();
+ timer = null;
+ }
}
- }
+ autoUpdating = shouldAutoUpdate;
+ }
+
+ public int getUpdateInterval() {
+ return updateInterval;
+ }
- // If the right index has not reached the left side of array
- // must now sort the left partition.
- if(lo0 < hi) {
- quickSort(v, lo0, hi);
- }
+ public void setUpdateInterval(int anInterval) {
+ if (timer != null) {
+ timer.setDelay(anInterval);
+ }
- // If the left index has not reached the right side of array
- // must now sort the right partition.
- if(lo < hi0) {
- quickSort(v, lo, hi0);
- }
+ updateInterval = anInterval;
+ }
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == timer) {
+ fireTableDataChanged();
+ }
}
- }
-
- private void swap(Vector a, int i, int j) {
- Object T = a.elementAt(i);
- a.setElementAt(a.elementAt(j), i);
- a.setElementAt(T, j);
- }
-
- protected boolean lt(String a, String b) {
- return a.compareTo(b) < 0;
- }
-
- // automated updates
-
- private boolean autoUpdating = false;
- private int updateInterval = 2000; // one-second delay on average
- protected Timer timer = null;
-
- public boolean isAutoUpdating()
- {
- return autoUpdating;
- }
-
- public void setAutoUpdating( boolean shouldAutoUpdate )
- {
- if ( shouldAutoUpdate )
- {
- if ( timer == null )
- {
- timer = new Timer( updateInterval, this );
- timer.setRepeats( true );
- timer.start();
- }
- }
- else
- {
- if ( timer != null )
- {
- timer.stop();
- timer = null;
- }
- }
-
- autoUpdating = shouldAutoUpdate;
- }
-
- public int getUpdateInterval()
- {
- return updateInterval;
- }
-
- public void setUpdateInterval( int anInterval )
- {
- if ( timer != null )
- {
- timer.setDelay( anInterval );
- }
-
- updateInterval = anInterval;
- }
-
- public void actionPerformed( ActionEvent evt )
- {
- if ( evt.getSource() == timer )
- {
- fireTableDataChanged();
- }
- }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/RadioButtonPanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/RadioButtonPanel.java
index 2956c71..62cbc2c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/RadioButtonPanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/RadioButtonPanel.java
@@ -26,149 +26,139 @@ import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;
/**
-* RadioButtonPanel is a simple extension of ButtonPanel.
-* Differences are that it uses radio buttons and the
-* default alignment is vertical. The radio buttons are
-* placed in a ButtonGroup and the panel defaults to having
-* no buttons selected.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class RadioButtonPanel extends ButtonPanel
-{
-/**
-* A ButtonGroup to help manage button state.
-*/
- protected ButtonGroup buttonGroup;
-
-/**
-* ButtonGroup does not make it easy to unselect all buttons.
-* The preferred way to do it is actually to create a hidden button.
-*/
- protected JRadioButton hiddenButton;
-
-/**
-* Constructs a RadioButtonPanel. Three buttons are created
-* so the panel is filled when used in a GUI-builder environment.
-*/
- public RadioButtonPanel()
- {
- super();
- }
-
-/**
-* Constructs a ButtonPanel using specified buttons.
-* @param buttonList An array containing the strings to be used in labeling the buttons.
-*/
- public RadioButtonPanel( String[] buttonList )
- {
- super( buttonList );
- }
-
-/**
-* Overridden to set vertical-center alignment and 2-pixel vgap.
-*/
- protected void initLayout()
- {
- super.initLayout();
- buttonPanelLayout.setAlignment( BetterFlowLayout.CENTER_VERTICAL );
- buttonPanelLayout.setVgap( 2 ); // looks nicer than java l&f recommendation (imho)
- }
-
-/**
-* Overridden to return a JRadioButton.
-* @param aLabel The label for the component that will be created.
-* @return The newly created component.
-*/
- protected Component createComponentWithLabel( String aLabel )
- {
- String buttonLabel = aLabel;
- JRadioButton newButton = new JRadioButton();
- newButton.setName( aLabel );
- newButton.setText( buttonLabel );
- newButton.setActionCommand( aLabel );
- newButton.addActionListener( this );
-
- // reduce insets per java l&f guidelines (was 4 on each side)
- newButton.setBorder( new EmptyBorder( 0, 4, 0, 4 ) );
-
- if ( buttonGroup == null )
- {
- buttonGroup = new ButtonGroup();
-
- // cheesy hack to allow a buttongroup to have no items selected.
- // note that the button is not added to container or buttonList.
- hiddenButton = new JRadioButton( "Hidden Button" );
- buttonGroup.add( hiddenButton );
- }
- buttonGroup.add( newButton );
-
- return newButton;
- }
-
-/**
-* Selects the button whose name matches the given text value.
-* @param newText A String matching the name of one of the buttons.
-* If null, empty, or not matching, all buttons are deselected.
-*/
- public void setValue(String aName)
- {
- if ( aName != null )
- {
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( c instanceof AbstractButton )
- {
- if ( c.getName().equals( aName ) )
- {
- ((AbstractButton)c).setSelected( true );
- return;
- }
- }
- }
- }
-
- // null, empty, or not matching - deselect all
- hiddenButton.setSelected( true );
- }
-
-/**
-* Gets the name of the currently selected button.
-* @return A string matching the name of the currently selected button,
-* or null of no button is selected.
-*/
- public String getValue()
- {
- String result = null;
- Component c = null;
- int count = buttonContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = buttonContainer.getComponent( i );
- if ( ( c instanceof AbstractButton ) && ( ((AbstractButton)c).isSelected() ) )
- {
- return c.getName();
- }
- }
- return result;
- }
-
-/**
-* Tests whether the specified value is checked.
-* @param aValue A value to be tested.
-* @return True if the specified value is checked, otherwise false.
-*/
- public boolean getValue( String aValue )
- {
- if ( aValue == null ) return false;
- return aValue.equals( getValue() );
- }
+ * RadioButtonPanel is a simple extension of ButtonPanel. Differences are that
+ * it uses radio buttons and the default alignment is vertical. The radio
+ * buttons are placed in a ButtonGroup and the panel defaults to having no
+ * buttons selected.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class RadioButtonPanel extends ButtonPanel {
+ /**
+ * A ButtonGroup to help manage button state.
+ */
+ protected ButtonGroup buttonGroup;
+
+ /**
+ * ButtonGroup does not make it easy to unselect all buttons. The preferred way
+ * to do it is actually to create a hidden button.
+ */
+ protected JRadioButton hiddenButton;
+
+ /**
+ * Constructs a RadioButtonPanel. Three buttons are created so the panel is
+ * filled when used in a GUI-builder environment.
+ */
+ public RadioButtonPanel() {
+ super();
+ }
+
+ /**
+ * Constructs a ButtonPanel using specified buttons.
+ *
+ * @param buttonList An array containing the strings to be used in labeling the
+ * buttons.
+ */
+ public RadioButtonPanel(String[] buttonList) {
+ super(buttonList);
+ }
+
+ /**
+ * Overridden to set vertical-center alignment and 2-pixel vgap.
+ */
+ protected void initLayout() {
+ super.initLayout();
+ buttonPanelLayout.setAlignment(BetterFlowLayout.CENTER_VERTICAL);
+ buttonPanelLayout.setVgap(2); // looks nicer than java l&f recommendation (imho)
+ }
+
+ /**
+ * Overridden to return a JRadioButton.
+ *
+ * @param aLabel The label for the component that will be created.
+ * @return The newly created component.
+ */
+ protected Component createComponentWithLabel(String aLabel) {
+ String buttonLabel = aLabel;
+ JRadioButton newButton = new JRadioButton();
+ newButton.setName(aLabel);
+ newButton.setText(buttonLabel);
+ newButton.setActionCommand(aLabel);
+ newButton.addActionListener(this);
+
+ // reduce insets per java l&f guidelines (was 4 on each side)
+ newButton.setBorder(new EmptyBorder(0, 4, 0, 4));
+
+ if (buttonGroup == null) {
+ buttonGroup = new ButtonGroup();
+
+ // cheesy hack to allow a buttongroup to have no items selected.
+ // note that the button is not added to container or buttonList.
+ hiddenButton = new JRadioButton("Hidden Button");
+ buttonGroup.add(hiddenButton);
+ }
+ buttonGroup.add(newButton);
+
+ return newButton;
+ }
+
+ /**
+ * Selects the button whose name matches the given text value.
+ *
+ * @param newText A String matching the name of one of the buttons. If null,
+ * empty, or not matching, all buttons are deselected.
+ */
+ public void setValue(String aName) {
+ if (aName != null) {
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if (c instanceof AbstractButton) {
+ if (c.getName().equals(aName)) {
+ ((AbstractButton) c).setSelected(true);
+ return;
+ }
+ }
+ }
+ }
+
+ // null, empty, or not matching - deselect all
+ hiddenButton.setSelected(true);
+ }
+
+ /**
+ * Gets the name of the currently selected button.
+ *
+ * @return A string matching the name of the currently selected button, or null
+ * of no button is selected.
+ */
+ public String getValue() {
+ String result = null;
+ Component c = null;
+ int count = buttonContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = buttonContainer.getComponent(i);
+ if ((c instanceof AbstractButton) && (((AbstractButton) c).isSelected())) {
+ return c.getName();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Tests whether the specified value is checked.
+ *
+ * @param aValue A value to be tested.
+ * @return True if the specified value is checked, otherwise false.
+ */
+ public boolean getValue(String aValue) {
+ if (aValue == null)
+ return false;
+ return aValue.equals(getValue());
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartPasswordField.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartPasswordField.java
index 6914cf6..55ba2f7 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartPasswordField.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartPasswordField.java
@@ -26,249 +26,227 @@ import java.awt.event.KeyEvent;
import javax.swing.JPasswordField;
/**
- * SmartPasswordField is an extention of JPasswordField. It does everything
- * a JPassword does, as well as limit the number of characters. The user
- * of this class can specify that a password can only have a maximum of
- * 10 characters for instance.
+ * SmartPasswordField is an extention of JPasswordField. It does everything a
+ * JPassword does, as well as limit the number of characters. The user of this
+ * class can specify that a password can only have a maximum of 10 characters
+ * for instance.
*
* @author rob@straylight.princeton.com
* @author $Author: cgruber $
* @version $Revision: 904 $
*/
-public class SmartPasswordField extends JPasswordField
-{
-
-/*******************************
-* CONSTANTS
-*******************************/
- private static final int BACKSPACE = 8;
- private static final int DELETE = 127;
- private static final int SPACE = 32;
- private static final int DASH = 45;
- private static final int UNDERSCORE = 95;
- private static final int PERIOD = 46;
- private static final int PASTE = 22; // Ctl-V
-
- private int passwordLength = Integer.MAX_VALUE;
-
-/*******************************
-* PUBLIC METHODS
-*******************************/
-
-/**
-* Default constructor.
-*/
- public SmartPasswordField()
- {
- super();
- }
-
-/**
-* This constructor allows the user to set the maximum length of the password.
-* @param aLength The maximum length of the password.
-*/
- public SmartPasswordField( int aLength )
- {
- this();
- setPasswordLength( aLength );
- }
-
-/**
-* Sets the maximum lenght of the password. The value must be 0 or greater.
-* If the length specified is less than 0, then no action occurs.
-* @param aLength The maximum lenght of the password.
-*/
- public void setPasswordLength( int aLength )
- {
- if ( aLength >= 0 )
- {
- passwordLength = aLength;
- }
- }
-
-/**
-* Returns the current maximum length of the password.
-* @return The current maximum length of the password.
-*/
- public int getPasswordLength()
- {
- return passwordLength;
- }
-
-/**
-* This method processes a key event. This event is generated by input from the
-* keyboard when this text field has the focus. This method is called for every
-* key that is pressed and released on the keyboard. This includes modifier
-* keys like the shift and alt keys. This class looks at the key and determines
-* if the key is valid input given the restrictions of this class. <BR> <BR>
-* @param e A key event generated by a keyboard action.
-*/
- public void processKeyEvent(KeyEvent e)
- {
- String currentText = "";
- String testString = "";
- char newChar = e.getKeyChar();
- int currentLength = 0;
- int selectionStart = 0;
- int selectionEnd = 0;
- int endOfHead = 0;
- int startOfTail = 0;
- boolean backspace = false;
- boolean delete = false;
- boolean paste = false;
- boolean insertionPoint = false;
- boolean selectionAtStart = false;
- boolean selectionAtEnd = false;
-
- backspace = (newChar == BACKSPACE);
- delete = (newChar == DELETE);
- paste = (newChar == PASTE);
-
- if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste))) // A "key-typed" event
- {
- if (isValidCharacter(newChar))
- {
-
- if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste))
- {
- // Analyze the current contents of the field
- currentText = new String( getPassword() );
- currentLength = currentText.length();
-
- selectionStart = getSelectionStart();
- selectionEnd = getSelectionEnd();
-
- insertionPoint = (selectionStart == selectionEnd);
- selectionAtStart = (selectionStart == 0);
- selectionAtEnd = (selectionEnd >= currentLength);
- if (selectionEnd > currentLength)
- {
- setSelectionEnd(currentLength);
- }
-
- // Generate new string
- if (selectionStart > 0) // Create head of test string
- {
- endOfHead = selectionStart;
- if (insertionPoint && backspace)
- {
- endOfHead -= 1;
- }
- testString += currentText.substring(0, endOfHead);
- }
-
- if (!(backspace || delete || paste)) // Add the new character
- {
- testString += newChar;
- }
-
- if (paste) // Add the string from the clipboard
- {
- Transferable data = getToolkit().getSystemClipboard().getContents(this);
- if (data != null)
- {
- try
- {
- String clipString = (String)data.getTransferData(DataFlavor.stringFlavor);
- testString += clipString;
- }
- catch (java.io.IOException ioe)
- {
- // Do nothing
- }
- catch (UnsupportedFlavorException ufe)
- {
- // Do nothing
- }
- }
- }
-
- if (selectionEnd < currentLength) // Add the tail of the string
- {
- startOfTail = selectionEnd;
- if (insertionPoint && delete)
- {
- startOfTail += 1;
- }
- testString += currentText.substring(startOfTail);
- }
-
- }
-
- if (testString.compareTo("") != 0) // Null string is OK
- {
- if (!(isValidString(testString)))
- {
- e.consume();
- }
- }
- }
- else
- {
- e.consume();
- }
- }
- super.processKeyEvent(e);
-
- postProcessing();
- }
-
-
-/*******************************
-* PROTECTED METHODS
-*******************************/
-
-/**
-* Returns whether the inputted character is valid or not. In this case all
-* characters are valid input.
-* @param aChar A character to perform the validity test with.
-* @return True if the character is valid for this subclassed text field. <BR>
-* False is the character is not valid.
-*/
- protected boolean isValidCharacter(char aChar)
- {
- return true;
- }
-
-/**
-* Returns whether a string is valid for this text field. As the user types from
-* the keyboard, this method is called to determine if the new string in the text
-* field is valid based upon the restriction of this class. The length of the
-* new string is checked against the maximum password length.
-* @param aString The string to perform the validity check with.
-* @return True if the length of the string is less than or equal to the maximum length.
-* False if the character is not valud.
-*/
- protected boolean isValidString(String aString)
- {
- if ( aString.length() > passwordLength )
- {
- return false;
- }
-
- return true;
- }
-
-/**
-* This class does not need any post processing.
-*/
- protected void postProcessing()
- {
- /* Do Nothing */
- }
-
-
-/*******************************
-* PRIVATE METHODS
-*******************************/
-
- private boolean isPrintableCharacter(char inputChar)
- {
- if ((inputChar >= ' ') && (inputChar <= '~'))
- {
- return true;
- }
- return false;
- }
+public class SmartPasswordField extends JPasswordField {
+
+ /*******************************
+ * CONSTANTS
+ *******************************/
+ private static final int BACKSPACE = 8;
+ private static final int DELETE = 127;
+ private static final int SPACE = 32;
+ private static final int DASH = 45;
+ private static final int UNDERSCORE = 95;
+ private static final int PERIOD = 46;
+ private static final int PASTE = 22; // Ctl-V
+
+ private int passwordLength = Integer.MAX_VALUE;
+
+ /*******************************
+ * PUBLIC METHODS
+ *******************************/
+
+ /**
+ * Default constructor.
+ */
+ public SmartPasswordField() {
+ super();
+ }
+
+ /**
+ * This constructor allows the user to set the maximum length of the password.
+ *
+ * @param aLength The maximum length of the password.
+ */
+ public SmartPasswordField(int aLength) {
+ this();
+ setPasswordLength(aLength);
+ }
+
+ /**
+ * Sets the maximum lenght of the password. The value must be 0 or greater. If
+ * the length specified is less than 0, then no action occurs.
+ *
+ * @param aLength The maximum lenght of the password.
+ */
+ public void setPasswordLength(int aLength) {
+ if (aLength >= 0) {
+ passwordLength = aLength;
+ }
+ }
+
+ /**
+ * Returns the current maximum length of the password.
+ *
+ * @return The current maximum length of the password.
+ */
+ public int getPasswordLength() {
+ return passwordLength;
+ }
+
+ /**
+ * This method processes a key event. This event is generated by input from the
+ * keyboard when this text field has the focus. This method is called for every
+ * key that is pressed and released on the keyboard. This includes modifier keys
+ * like the shift and alt keys. This class looks at the key and determines if
+ * the key is valid input given the restrictions of this class. <BR>
+ * <BR>
+ *
+ * @param e A key event generated by a keyboard action.
+ */
+ public void processKeyEvent(KeyEvent e) {
+ String currentText = "";
+ String testString = "";
+ char newChar = e.getKeyChar();
+ int currentLength = 0;
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ int endOfHead = 0;
+ int startOfTail = 0;
+ boolean backspace = false;
+ boolean delete = false;
+ boolean paste = false;
+ boolean insertionPoint = false;
+ boolean selectionAtStart = false;
+ boolean selectionAtEnd = false;
+
+ backspace = (newChar == BACKSPACE);
+ delete = (newChar == DELETE);
+ paste = (newChar == PASTE);
+
+ if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste))) // A "key-typed" event
+ {
+ if (isValidCharacter(newChar)) {
+
+ if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste)) {
+ // Analyze the current contents of the field
+ currentText = new String(getPassword());
+ currentLength = currentText.length();
+
+ selectionStart = getSelectionStart();
+ selectionEnd = getSelectionEnd();
+
+ insertionPoint = (selectionStart == selectionEnd);
+ selectionAtStart = (selectionStart == 0);
+ selectionAtEnd = (selectionEnd >= currentLength);
+ if (selectionEnd > currentLength) {
+ setSelectionEnd(currentLength);
+ }
+
+ // Generate new string
+ if (selectionStart > 0) // Create head of test string
+ {
+ endOfHead = selectionStart;
+ if (insertionPoint && backspace) {
+ endOfHead -= 1;
+ }
+ testString += currentText.substring(0, endOfHead);
+ }
+
+ if (!(backspace || delete || paste)) // Add the new character
+ {
+ testString += newChar;
+ }
+
+ if (paste) // Add the string from the clipboard
+ {
+ Transferable data = getToolkit().getSystemClipboard().getContents(this);
+ if (data != null) {
+ try {
+ String clipString = (String) data.getTransferData(DataFlavor.stringFlavor);
+ testString += clipString;
+ } catch (java.io.IOException ioe) {
+ // Do nothing
+ } catch (UnsupportedFlavorException ufe) {
+ // Do nothing
+ }
+ }
+ }
+
+ if (selectionEnd < currentLength) // Add the tail of the string
+ {
+ startOfTail = selectionEnd;
+ if (insertionPoint && delete) {
+ startOfTail += 1;
+ }
+ testString += currentText.substring(startOfTail);
+ }
+
+ }
+
+ if (testString.compareTo("") != 0) // Null string is OK
+ {
+ if (!(isValidString(testString))) {
+ e.consume();
+ }
+ }
+ } else {
+ e.consume();
+ }
+ }
+ super.processKeyEvent(e);
+
+ postProcessing();
+ }
+
+ /*******************************
+ * PROTECTED METHODS
+ *******************************/
+
+ /**
+ * Returns whether the inputted character is valid or not. In this case all
+ * characters are valid input.
+ *
+ * @param aChar A character to perform the validity test with.
+ * @return True if the character is valid for this subclassed text field. <BR>
+ * False is the character is not valid.
+ */
+ protected boolean isValidCharacter(char aChar) {
+ return true;
+ }
+
+ /**
+ * Returns whether a string is valid for this text field. As the user types from
+ * the keyboard, this method is called to determine if the new string in the
+ * text field is valid based upon the restriction of this class. The length of
+ * the new string is checked against the maximum password length.
+ *
+ * @param aString The string to perform the validity check with.
+ * @return True if the length of the string is less than or equal to the maximum
+ * length. False if the character is not valud.
+ */
+ protected boolean isValidString(String aString) {
+ if (aString.length() > passwordLength) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * This class does not need any post processing.
+ */
+ protected void postProcessing() {
+ /* Do Nothing */
+ }
+
+ /*******************************
+ * PRIVATE METHODS
+ *******************************/
+
+ private boolean isPrintableCharacter(char inputChar) {
+ if ((inputChar >= ' ') && (inputChar <= '~')) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartTextField.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartTextField.java
index cee37e1..5092179 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartTextField.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/SmartTextField.java
@@ -27,218 +27,204 @@ import javax.swing.JTextField;
/**
* SmartTextField is an abstract class for that allows the text field to
- * intelligently analyze the user's input in real-time. As the user enters
+ * intelligently analyze the user's input in real-time. As the user enters
* keystrokes, the generated string is analyzed to determine if the new string
* is valid based on the criteria of the concrete classes that extend this
- * class. An invalid keystroke is rejected and not displayed in the text
- * field. This class can be extended to to create smart text fields that only
- * accept integers or floating points number or alphabetic strings of maximum
- * length. These are several examples.
+ * class. An invalid keystroke is rejected and not displayed in the text field.
+ * This class can be extended to to create smart text fields that only accept
+ * integers or floating points number or alphabetic strings of maximum length.
+ * These are several examples.
*
* @author rob@straylight.princeton.com
* @author $Author: cgruber $
* @version $Revision: 904 $
*/
-public abstract class SmartTextField extends JTextField
-{
-
-/*******************************
-* CONSTANTS
-*******************************/
- private static final int BACKSPACE = 8;
- private static final int DELETE = 127;
- private static final int SPACE = 32;
- private static final int DASH = 45;
- private static final int UNDERSCORE = 95;
- private static final int PERIOD = 46;
- private static final int PASTE = 22; // Ctl-V
-
-
-/*******************************
-* PUBLIC METHODS
-*******************************/
-
-/**
-* This method processes a key event. This event is generated by input from the
-* keyboard when this text field has the focus. This method is called for every
-* key that is pressed and released on the keyboard. This includes modifier
-* keys like the shift and alt keys. This class looks at the key and determines
-* if the key is valid input given the restrictions of the concrete sub-classes. <BR> <BR>
-* Example - A smart text field only allows alphabetic characters. If the key
-* pressed is a "2" then this method will determine that the key is invalid and
-* "consume" the key event. <BR> <BR>
-* Note - Every printable character has a "TYPED" key event. Currentlt under
-* Java 1.2.1 this does not happen. Bug 4186905 relating this bug has been
-* fixed and is awaiting release.
-* @param e A key event generated by a keyboard action.
-*/
- public void processKeyEvent(KeyEvent e)
- {
- String currentText = "";
- String testString = "";
- char newChar = e.getKeyChar();
- int currentLength = 0;
- int selectionStart = 0;
- int selectionEnd = 0;
- int endOfHead = 0;
- int startOfTail = 0;
- boolean backspace = false;
- boolean delete = false;
- boolean paste = false;
- boolean insertionPoint = false;
- boolean selectionAtStart = false;
- boolean selectionAtEnd = false;
-
- backspace = (newChar == BACKSPACE);
- delete = (newChar == DELETE);
- paste = (newChar == PASTE);
-
- if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste))) // A "key-typed" event
- {
- if (isValidCharacter(newChar))
- {
-
- if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste))
- {
- // Analyze the current contents of the field
- currentText = getText();
- currentLength = currentText.length();
-
- selectionStart = getSelectionStart();
- selectionEnd = getSelectionEnd();
-
- insertionPoint = (selectionStart == selectionEnd);
- selectionAtStart = (selectionStart == 0);
- selectionAtEnd = (selectionEnd >= currentLength);
- if (selectionEnd > currentLength)
- {
- setSelectionEnd(currentLength);
- }
-
- // Generate new string
- if (selectionStart > 0) // Create head of test string
- {
- endOfHead = selectionStart;
- if (insertionPoint && backspace)
- {
- endOfHead -= 1;
- }
- testString += currentText.substring(0, endOfHead);
- }
-
- if (!(backspace || delete || paste)) // Add the new character
- {
- testString += newChar;
- }
-
- if (paste) // Add the string from the clipboard
- {
- Transferable data = getToolkit().getSystemClipboard().getContents(this);
- if (data != null)
- {
- try
- {
- String clipString = (String)data.getTransferData(DataFlavor.stringFlavor);
- testString += clipString;
- }
- catch (java.io.IOException ioe)
- {
- // Do nothing
- }
- catch (UnsupportedFlavorException ufe)
- {
- // Do nothing
- }
- }
- }
-
- if (selectionEnd < currentLength) // Add the tail of the string
- {
- startOfTail = selectionEnd;
- if (insertionPoint && delete)
- {
- startOfTail += 1;
- }
- testString += currentText.substring(startOfTail);
- }
-
- }
-
- if (testString.compareTo("") != 0) // Null string is OK
- {
- if (!(isValidString(testString)))
- {
- e.consume();
- }
- }
- }
- else
- {
- e.consume();
- }
- }
- super.processKeyEvent(e);
-
- postProcessing();
- }
-
-
-/*******************************
-* PROTECTED METHODS
-*******************************/
-
-/**
-* Default constructor for this class. The initial text of the smart text field
-* can be specified as well as the size (in characters) of the text field.
-* @param text The initial string that is displayed in the text field.
-* @param columns THe width of the text field in characters.
-*/
- protected SmartTextField(String text, int columns)
- {
- super(text, columns);
- }
-
-/**
-* Returns whether a character is valid for this text field. As the user types
-* from the keyboard, this method is called to determine if the character is a
-* valid character based in the restrictions of the subclass.
-* @param aChar A character to perform the validity test with.
-* @return True if the character is valid for this subclassed text field. <BR>
-* False is the character is not valid.
-*/
- abstract protected boolean isValidCharacter(char aChar);
-
-/**
-* Returns whether a string is valid for this text field. As the user types from
-* the keyboard, this method is called to determine if the new string in the text
-* field is valid based upon the restriction of the subclass. This is done after
-* the character has been determined to be valid since there can be restrictions
-* placed on the text string as a whole, such a maximum length or date format.
-* @param aString The string to perform the validity check with.
-* @return True if the string is valid for this subclassed text field. <BR>
-* False if the character is not valud.
-*/
- abstract protected boolean isValidString(String aString);
-
-/**
-* This method is used by the any subclass that need to complete any processing
-* of the text string in the text field after all the requirement checks have
-* been performed.
-*/
- abstract protected void postProcessing();
-
-
-/*******************************
-* PRIVATE METHODS
-*******************************/
-
- private boolean isPrintableCharacter(char inputChar)
- {
- if ((inputChar >= ' ') && (inputChar <= '~'))
- {
- return true;
- }
- return false;
- }
+public abstract class SmartTextField extends JTextField {
+
+ /*******************************
+ * CONSTANTS
+ *******************************/
+ private static final int BACKSPACE = 8;
+ private static final int DELETE = 127;
+ private static final int SPACE = 32;
+ private static final int DASH = 45;
+ private static final int UNDERSCORE = 95;
+ private static final int PERIOD = 46;
+ private static final int PASTE = 22; // Ctl-V
+
+ /*******************************
+ * PUBLIC METHODS
+ *******************************/
+
+ /**
+ * This method processes a key event. This event is generated by input from the
+ * keyboard when this text field has the focus. This method is called for every
+ * key that is pressed and released on the keyboard. This includes modifier keys
+ * like the shift and alt keys. This class looks at the key and determines if
+ * the key is valid input given the restrictions of the concrete sub-classes.
+ * <BR>
+ * <BR>
+ * Example - A smart text field only allows alphabetic characters. If the key
+ * pressed is a "2" then this method will determine that the key is invalid and
+ * "consume" the key event. <BR>
+ * <BR>
+ * Note - Every printable character has a "TYPED" key event. Currentlt under
+ * Java 1.2.1 this does not happen. Bug 4186905 relating this bug has been fixed
+ * and is awaiting release.
+ *
+ * @param e A key event generated by a keyboard action.
+ */
+ public void processKeyEvent(KeyEvent e) {
+ String currentText = "";
+ String testString = "";
+ char newChar = e.getKeyChar();
+ int currentLength = 0;
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ int endOfHead = 0;
+ int startOfTail = 0;
+ boolean backspace = false;
+ boolean delete = false;
+ boolean paste = false;
+ boolean insertionPoint = false;
+ boolean selectionAtStart = false;
+ boolean selectionAtEnd = false;
+
+ backspace = (newChar == BACKSPACE);
+ delete = (newChar == DELETE);
+ paste = (newChar == PASTE);
+
+ if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste))) // A "key-typed" event
+ {
+ if (isValidCharacter(newChar)) {
+
+ if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste)) {
+ // Analyze the current contents of the field
+ currentText = getText();
+ currentLength = currentText.length();
+
+ selectionStart = getSelectionStart();
+ selectionEnd = getSelectionEnd();
+
+ insertionPoint = (selectionStart == selectionEnd);
+ selectionAtStart = (selectionStart == 0);
+ selectionAtEnd = (selectionEnd >= currentLength);
+ if (selectionEnd > currentLength) {
+ setSelectionEnd(currentLength);
+ }
+
+ // Generate new string
+ if (selectionStart > 0) // Create head of test string
+ {
+ endOfHead = selectionStart;
+ if (insertionPoint && backspace) {
+ endOfHead -= 1;
+ }
+ testString += currentText.substring(0, endOfHead);
+ }
+
+ if (!(backspace || delete || paste)) // Add the new character
+ {
+ testString += newChar;
+ }
+
+ if (paste) // Add the string from the clipboard
+ {
+ Transferable data = getToolkit().getSystemClipboard().getContents(this);
+ if (data != null) {
+ try {
+ String clipString = (String) data.getTransferData(DataFlavor.stringFlavor);
+ testString += clipString;
+ } catch (java.io.IOException ioe) {
+ // Do nothing
+ } catch (UnsupportedFlavorException ufe) {
+ // Do nothing
+ }
+ }
+ }
+
+ if (selectionEnd < currentLength) // Add the tail of the string
+ {
+ startOfTail = selectionEnd;
+ if (insertionPoint && delete) {
+ startOfTail += 1;
+ }
+ testString += currentText.substring(startOfTail);
+ }
+
+ }
+
+ if (testString.compareTo("") != 0) // Null string is OK
+ {
+ if (!(isValidString(testString))) {
+ e.consume();
+ }
+ }
+ } else {
+ e.consume();
+ }
+ }
+ super.processKeyEvent(e);
+
+ postProcessing();
+ }
+
+ /*******************************
+ * PROTECTED METHODS
+ *******************************/
+
+ /**
+ * Default constructor for this class. The initial text of the smart text field
+ * can be specified as well as the size (in characters) of the text field.
+ *
+ * @param text The initial string that is displayed in the text field.
+ * @param columns THe width of the text field in characters.
+ */
+ protected SmartTextField(String text, int columns) {
+ super(text, columns);
+ }
+
+ /**
+ * Returns whether a character is valid for this text field. As the user types
+ * from the keyboard, this method is called to determine if the character is a
+ * valid character based in the restrictions of the subclass.
+ *
+ * @param aChar A character to perform the validity test with.
+ * @return True if the character is valid for this subclassed text field. <BR>
+ * False is the character is not valid.
+ */
+ abstract protected boolean isValidCharacter(char aChar);
+
+ /**
+ * Returns whether a string is valid for this text field. As the user types from
+ * the keyboard, this method is called to determine if the new string in the
+ * text field is valid based upon the restriction of the subclass. This is done
+ * after the character has been determined to be valid since there can be
+ * restrictions placed on the text string as a whole, such a maximum length or
+ * date format.
+ *
+ * @param aString The string to perform the validity check with.
+ * @return True if the string is valid for this subclassed text field. <BR>
+ * False if the character is not valud.
+ */
+ abstract protected boolean isValidString(String aString);
+
+ /**
+ * This method is used by the any subclass that need to complete any processing
+ * of the text string in the text field after all the requirement checks have
+ * been performed.
+ */
+ abstract protected void postProcessing();
+
+ /*******************************
+ * PRIVATE METHODS
+ *******************************/
+
+ private boolean isPrintableCharacter(char inputChar) {
+ if ((inputChar >= ' ') && (inputChar <= '~')) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/StatusButtonPanel.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/StatusButtonPanel.java
index 3d9a85b..ba9f361 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/StatusButtonPanel.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/StatusButtonPanel.java
@@ -34,243 +34,228 @@ import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
/**
-* StatusButtonPanel extends ButtonPanel to provide a space
-* to display status messages in a consistent manner.<BR><BR>
-* Messages are erased after a certain predefined interval,
-* defaulting to 10 seconds.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class StatusButtonPanel extends ButtonPanel
-{
-/**
-* This is the action command to all listeners when the status text is changed.
-*/
- public static final String STATUS_CHANGED = "STATUS_CHANGED";
-
- // note: weirdness happens if you initialize
- // this variable. Because it is set by initLayout
- // and initLayout is called by the superclass constructor,
- // this variable would get initialized after initLayout
- // is called...
- protected Component statusComponent; // = null;
-
- protected Timer timer = null;
- protected int interval = 10000; // adjust as needed
-
-/**
-* Constructs a StatusButtonPanel. Three buttons are created
-* so the panel is filled when used in a GUI-builder environment.
-*/
- public StatusButtonPanel()
- {
- super();
- setupTimer();
- }
-
-/**
-* Constructs a StatusButtonPanel using specified buttons.
-* @param buttonList An array containing the strings to be used in labeling the buttons.
-*/
- public StatusButtonPanel( String[] buttonList )
- {
- super( buttonList );
- setupTimer();
- }
-
-/**
-* Initializes the timer instance variable.
-*/
- protected void setupTimer()
- {
- timer = new Timer( interval, this );
- timer.addActionListener( this );
- timer.setRepeats( false );
- timer.start();
- }
-
-/**
-* Returns the number of milliseconds before the status message is cleared.
-* The default is 10000.
-* @return The current delay interval in milliseconds.
-*/
- public int getDelayInterval()
- {
- return interval;
- }
-
-/**
-* Sets the number of milliseconds before the status message is cleared.
-* @param millis The new delay interval in milliseconds.
-*/
- public void setDelayInterval( int millis )
- {
- interval = millis;
- timer.setDelay( interval );
- }
-
-/**
-* Returns the visual component used to display the status.
-* @return A component used for displaying status.
-*/
- public Component getStatusComponent()
- {
- return statusComponent;
-
- }
-/**
-* Receives ActionEvents from the internal timer.
-* @param e The action event in question.
-*/
- public void actionPerformed(ActionEvent e)
- {
- if ( e.getSource() == timer )
- {
- setText( "" );
- return;
- }
-
- // otherwise continue with superclass implementation
- super.actionPerformed( e );
- }
-
-/**
-* This method is responsible for the initial layout of the panel.
-* Subclasses can implement different layouts, but this method
-* is responsible for initializing buttonPanelLayout to a valid
-* layout manager and setting this panel to use it. This method
-* must should initialize statusComponent to a component that ideally
-* has get/setText methods, although this is not required.
-*/
- protected void initLayout()
- {
-
- statusComponent = new JTextField();
- JTextField textField = (JTextField) statusComponent;
- textField.setColumns( 20 );
- textField.setBackground( getBackground() );
- textField.setEditable( false );
+ * StatusButtonPanel extends ButtonPanel to provide a space to display status
+ * messages in a consistent manner.<BR>
+ * <BR>
+ * Messages are erased after a certain predefined interval, defaulting to 10
+ * seconds.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class StatusButtonPanel extends ButtonPanel {
+ /**
+ * This is the action command to all listeners when the status text is changed.
+ */
+ public static final String STATUS_CHANGED = "STATUS_CHANGED";
+
+ // note: weirdness happens if you initialize
+ // this variable. Because it is set by initLayout
+ // and initLayout is called by the superclass constructor,
+ // this variable would get initialized after initLayout
+ // is called...
+ protected Component statusComponent; // = null;
+
+ protected Timer timer = null;
+ protected int interval = 10000; // adjust as needed
+
+ /**
+ * Constructs a StatusButtonPanel. Three buttons are created so the panel is
+ * filled when used in a GUI-builder environment.
+ */
+ public StatusButtonPanel() {
+ super();
+ setupTimer();
+ }
+
+ /**
+ * Constructs a StatusButtonPanel using specified buttons.
+ *
+ * @param buttonList An array containing the strings to be used in labeling the
+ * buttons.
+ */
+ public StatusButtonPanel(String[] buttonList) {
+ super(buttonList);
+ setupTimer();
+ }
+
+ /**
+ * Initializes the timer instance variable.
+ */
+ protected void setupTimer() {
+ timer = new Timer(interval, this);
+ timer.addActionListener(this);
+ timer.setRepeats(false);
+ timer.start();
+ }
+
+ /**
+ * Returns the number of milliseconds before the status message is cleared. The
+ * default is 10000.
+ *
+ * @return The current delay interval in milliseconds.
+ */
+ public int getDelayInterval() {
+ return interval;
+ }
+
+ /**
+ * Sets the number of milliseconds before the status message is cleared.
+ *
+ * @param millis The new delay interval in milliseconds.
+ */
+ public void setDelayInterval(int millis) {
+ interval = millis;
+ timer.setDelay(interval);
+ }
+
+ /**
+ * Returns the visual component used to display the status.
+ *
+ * @return A component used for displaying status.
+ */
+ public Component getStatusComponent() {
+ return statusComponent;
+
+ }
+
+ /**
+ * Receives ActionEvents from the internal timer.
+ *
+ * @param e The action event in question.
+ */
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == timer) {
+ setText("");
+ return;
+ }
+
+ // otherwise continue with superclass implementation
+ super.actionPerformed(e);
+ }
+
+ /**
+ * This method is responsible for the initial layout of the panel. Subclasses
+ * can implement different layouts, but this method is responsible for
+ * initializing buttonPanelLayout to a valid layout manager and setting this
+ * panel to use it. This method must should initialize statusComponent to a
+ * component that ideally has get/setText methods, although this is not
+ * required.
+ */
+ protected void initLayout() {
+
+ statusComponent = new JTextField();
+ JTextField textField = (JTextField) statusComponent;
+ textField.setColumns(20);
+ textField.setBackground(getBackground());
+ textField.setEditable(false);
// statusComponent = new PickListPanel(); // for testing
- this.setLayout( new GridBagLayout() );
-
- GridBagConstraints gbc =
- new GridBagConstraints();
- gbc.gridx = GridBagConstraints.RELATIVE;
- gbc.gridy = GridBagConstraints.RELATIVE;
- gbc.gridwidth = 1;
- gbc.gridheight = 1;
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
- gbc.anchor = GridBagConstraints.CENTER;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.insets = new Insets(0, 5, 0, 10);
- gbc.ipadx = 0;
- gbc.ipady = 0;
+ this.setLayout(new GridBagLayout());
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = GridBagConstraints.RELATIVE;
+ gbc.gridy = GridBagConstraints.RELATIVE;
+ gbc.gridwidth = 1;
+ gbc.gridheight = 1;
+ gbc.weightx = 1.0;
+ gbc.weighty = 0.0;
+ gbc.anchor = GridBagConstraints.CENTER;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.insets = new Insets(0, 5, 0, 10);
+ gbc.ipadx = 0;
+ gbc.ipady = 0;
//1.2 new GridBagConstraints(GridBagConstraints.RELATIVE, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0,
//1.2 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 10), 0, 0 );
- this.add( statusComponent, gbc );
-
- buttonContainer = new JPanel();
- buttonPanelLayout = new BetterFlowLayout();
- buttonContainer.setLayout(buttonPanelLayout);
- buttonPanelLayout.setAlignment( BetterFlowLayout.RIGHT );
- ((BetterFlowLayout)buttonPanelLayout).setWidthUniform( true );
- gbc.weightx = 0.0;
- gbc.insets = new Insets( 0, 0, 0, 0 );
- this.add( buttonContainer, gbc );
- }
-
-/**
-* Sets the text to appear in the status area.
-* @param newText A string to appear in the status area. Nulls are allowed.
-*/
- public void setText(String newText)
- {
- // TODO: should use property introspection instead
-
- // use reflection to call the "setText" method, if any.
- try
- {
- Class c = statusComponent.getClass();
- Method m = c.getMethod( "setText", new Class[] { new String().getClass() } );
- m.invoke( statusComponent, new Object[] { newText } );
- broadcastEvent( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, STATUS_CHANGED ) );
- statusComponent.paint( statusComponent.getGraphics() );
- }
- catch ( Exception exc )
- {
- // "setText" method does not exist; do nothing.
- }
-
- // if non-empty string, start the timer
- if ( ! "".equals( newText ) )
- {
- timer.restart();
- }
- }
-
-/**
-* Gets the text in the status area.
-* @return The string being displayed in the status area.
-*/
- public String getText()
- {
- // TODO: should use property introspection instead
-
- String value = "";
- // use reflection to call the "setText" method, if any.
- try
- {
- Class c = statusComponent.getClass();
- Method m = c.getMethod( "getText", (Class[])null );
- value = (String) m.invoke( statusComponent, (Object[])null );
- }
- catch ( Exception exc )
- {
- // "getText" method does not exist; do nothing.
- }
- return value;
- }
-
- // for testing
-
- public static void main( String[] argv )
- {
- try
- {
- UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
- }
- catch (Exception exc)
- {
-
- }
-
- JFrame dialog = new JFrame();
- BorderLayout bl = new BorderLayout( 20, 20 );
+ this.add(statusComponent, gbc);
+
+ buttonContainer = new JPanel();
+ buttonPanelLayout = new BetterFlowLayout();
+ buttonContainer.setLayout(buttonPanelLayout);
+ buttonPanelLayout.setAlignment(BetterFlowLayout.RIGHT);
+ ((BetterFlowLayout) buttonPanelLayout).setWidthUniform(true);
+ gbc.weightx = 0.0;
+ gbc.insets = new Insets(0, 0, 0, 0);
+ this.add(buttonContainer, gbc);
+ }
+
+ /**
+ * Sets the text to appear in the status area.
+ *
+ * @param newText A string to appear in the status area. Nulls are allowed.
+ */
+ public void setText(String newText) {
+ // TODO: should use property introspection instead
+
+ // use reflection to call the "setText" method, if any.
+ try {
+ Class c = statusComponent.getClass();
+ Method m = c.getMethod("setText", new Class[] { new String().getClass() });
+ m.invoke(statusComponent, new Object[] { newText });
+ broadcastEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, STATUS_CHANGED));
+ statusComponent.paint(statusComponent.getGraphics());
+ } catch (Exception exc) {
+ // "setText" method does not exist; do nothing.
+ }
+
+ // if non-empty string, start the timer
+ if (!"".equals(newText)) {
+ timer.restart();
+ }
+ }
+
+ /**
+ * Gets the text in the status area.
+ *
+ * @return The string being displayed in the status area.
+ */
+ public String getText() {
+ // TODO: should use property introspection instead
+
+ String value = "";
+ // use reflection to call the "setText" method, if any.
+ try {
+ Class c = statusComponent.getClass();
+ Method m = c.getMethod("getText", (Class[]) null);
+ value = (String) m.invoke(statusComponent, (Object[]) null);
+ } catch (Exception exc) {
+ // "getText" method does not exist; do nothing.
+ }
+ return value;
+ }
+
+ // for testing
+
+ public static void main(String[] argv) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception exc) {
+
+ }
+
+ JFrame dialog = new JFrame();
+ BorderLayout bl = new BorderLayout(20, 20);
// StatusButtonPanel panel = new StatusButtonPanel();
// System.out.println( panel.statusComponent );
- StatusButtonPanel panel = new StatusButtonPanel( new String[] { "Okay", "Cancel" } );
+ StatusButtonPanel panel = new StatusButtonPanel(new String[] { "Okay", "Cancel" });
- dialog.getContentPane().setLayout( bl );
- dialog.getContentPane().add( panel, BorderLayout.SOUTH );
- dialog.setLocation( 50, 50 );
- // dialog.setSize( 450, 150 );
- dialog.pack();
- dialog.setVisible( true );
+ dialog.getContentPane().setLayout(bl);
+ dialog.getContentPane().add(panel, BorderLayout.SOUTH);
+ dialog.setLocation(50, 50);
+ // dialog.setSize( 450, 150 );
+ dialog.pack();
+ dialog.setVisible(true);
- panel.setBorder( new EmptyBorder( 5, 5, 5, 5 ) );
- panel.setAlignment( BetterFlowLayout.RIGHT );
+ panel.setBorder(new EmptyBorder(5, 5, 5, 5));
+ panel.setAlignment(BetterFlowLayout.RIGHT);
// panel.getButton( "One" ).setEnabled( false );
- panel.setText( "File saved." );
- System.out.println( panel.getText() );
- }
+ panel.setText("File saved.");
+ System.out.println(panel.getText());
+ }
}
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TintedImageFilter.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TintedImageFilter.java
index a51ed16..b15a660 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TintedImageFilter.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TintedImageFilter.java
@@ -22,79 +22,75 @@ import java.awt.Color;
import java.awt.image.RGBImageFilter;
/**
- * TintedImageFilter tints all gray pixels half-way towards
- * the value passed into the constructor. This "tints" a
- * mostly grayscale image. This has proven useful for tinting
- * user interface decorative images towards one of the SystemColor
- * constants to better mesh with a platform look and feel.
+ * TintedImageFilter tints all gray pixels half-way towards the value passed
+ * into the constructor. This "tints" a mostly grayscale image. This has proven
+ * useful for tinting user interface decorative images towards one of the
+ * SystemColor constants to better mesh with a platform look and feel.
*
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 893 $
*/
- public class TintedImageFilter extends RGBImageFilter
- {
- double redOffset, greenOffset, blueOffset;
-
- public TintedImageFilter( Color aColor )
- {
- canFilterIndexColorModel = true;
- redOffset = getOffset( aColor.getRed() );
- greenOffset = getOffset( aColor.getGreen() );
- blueOffset = getOffset( aColor.getBlue() );
- }
-
- /**
- * Calculates the offset used to modify color
- * values. This method returns half the difference
- * between the specified color level and 192.
- */
- protected double getOffset( int colorValue )
- {
- return ( colorValue - 192 ) / 2;
- }
+public class TintedImageFilter extends RGBImageFilter {
+ double redOffset, greenOffset, blueOffset;
- public int filterRGB(int x, int y, int rgb)
- {
+ public TintedImageFilter(Color aColor) {
+ canFilterIndexColorModel = true;
+ redOffset = getOffset(aColor.getRed());
+ greenOffset = getOffset(aColor.getGreen());
+ blueOffset = getOffset(aColor.getBlue());
+ }
+
+ /**
+ * Calculates the offset used to modify color values. This method returns half
+ * the difference between the specified color level and 192.
+ */
+ protected double getOffset(int colorValue) {
+ return (colorValue - 192) / 2;
+ }
+
+ public int filterRGB(int x, int y, int rgb) {
+
+ int red = (rgb & 0xff0000) >> 16;
+ int green = (rgb & 0x00ff00) >> 8;
+ int blue = (rgb & 0x0000ff);
+
+ // if roughly black
+ if (red + green + blue < 30)
+ return rgb;
+
+ // if roughly gray
+ if ((Math.abs(red - green) < 10) && (Math.abs(red - blue) < 10)) {
+ red += redOffset;
+ if (red < 0)
+ red = 0;
+ if (red > 255)
+ red = 255;
+ green += greenOffset;
+ if (green < 0)
+ green = 0;
+ if (green > 255)
+ green = 255;
+ blue += blueOffset;
+ if (blue < 0)
+ blue = 0;
+ if (blue > 255)
+ blue = 255;
+
+ return new Color(red, green, blue).getRGB();
+ }
+
+ return rgb;
+ }
+}
- int red = ( rgb & 0xff0000 ) >> 16;
- int green = ( rgb & 0x00ff00 ) >> 8;
- int blue = ( rgb & 0x0000ff );
-
- // if roughly black
- if ( red + green + blue < 30 ) return rgb;
-
- // if roughly gray
- if ( ( Math.abs( red - green ) < 10 )
- && ( Math.abs( red - blue ) < 10 ) )
- {
- red += redOffset;
- if ( red < 0 ) red = 0;
- if ( red > 255 ) red = 255;
- green += greenOffset;
- if ( green < 0 ) green = 0;
- if ( green > 255 ) green = 255;
- blue += blueOffset;
- if ( blue < 0 ) blue = 0;
- if ( blue > 255 ) blue = 255;
-
- return new Color( red, green, blue ).getRGB();
- }
-
- return rgb;
- }
- }
-
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/01/18 21:27:04 mpowers
- * Made the tinting a little darker.
+ * Revision 1.2 2001/01/18 21:27:04 mpowers Made the tinting a little darker.
*
- * Revision 1.1 2001/01/12 17:36:27 mpowers
- * Contributing TintedImageFilter.
+ * Revision 1.1 2001/01/12 17:36:27 mpowers Contributing TintedImageFilter.
*
*
*/
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeChooser.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeChooser.java
index f0bb6c2..f5ab50c 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeChooser.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeChooser.java
@@ -66,662 +66,538 @@ import javax.swing.tree.TreeSelectionModel;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* TreeChooser is a FileChooser-like panel that
-* uses a TreeModel as a data source. It basically
-* provides an alternative to JTree for rendering
-* and manipulating tree-like data.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TreeChooser extends JPanel
- implements ActionListener, ListSelectionListener,
- TreeSelectionListener, TreeModelListener, ListCellRenderer
-{
- /**
- * The TreeChooser responds to this action command
- * by calling displayPrevious().
- */
+ * TreeChooser is a FileChooser-like panel that uses a TreeModel as a data
+ * source. It basically provides an alternative to JTree for rendering and
+ * manipulating tree-like data.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TreeChooser extends JPanel
+ implements ActionListener, ListSelectionListener, TreeSelectionListener, TreeModelListener, ListCellRenderer {
+ /**
+ * The TreeChooser responds to this action command by calling displayPrevious().
+ */
public static final String BACK = "Back";
- /**
- * The TreeChooser responds to this action command
- * by calling displayHome().
- */
+ /**
+ * The TreeChooser responds to this action command by calling displayHome().
+ */
public static final String HOME = "Home";
- /**
- * The TreeChooser responds to this action command
- * by calling displayParent().
- */
+ /**
+ * The TreeChooser responds to this action command by calling displayParent().
+ */
public static final String UP = "Up";
- /**
- * The TreeChooser responds to this action command
- * by attempting to navigate to the first node in
- * the current selection and display that node's children.
- */
+ /**
+ * The TreeChooser responds to this action command by attempting to navigate to
+ * the first node in the current selection and display that node's children.
+ */
public static final String SELECT = "Select";
protected JList contents;
- protected JComboBox pathCombo;
+ protected JComboBox pathCombo;
protected JToolBar toolBar;
-
+
protected TreeModel model;
protected TreeSelectionModel selectionModel;
- protected TreeCellRenderer renderer;
- protected TreePath displayPath;
- protected Stack pathStack;
- protected int pathIndent;
-
- private ChooserComboBoxModel comboBoxModel;
- private JTree bogusJTree; // needed for tree cell renderer
- private Dimension preferredSize;
-
- public TreeChooser()
- {
- preferredSize = new Dimension( 300, 200 );
- model = new DefaultTreeModel( new DefaultMutableTreeNode( "Root" ) );
- displayPath = new TreePath( model.getRoot() );
- selectionModel = new DefaultTreeSelectionModel();
- renderer = new DefaultTreeCellRenderer();
- pathStack = new Stack();
- pathIndent = 0; // 16;
- comboBoxModel = new ChooserComboBoxModel( this );
-
- bogusJTree = new JTree();
- bogusJTree.setModel( model );
+ protected TreeCellRenderer renderer;
+ protected TreePath displayPath;
+ protected Stack pathStack;
+ protected int pathIndent;
+
+ private ChooserComboBoxModel comboBoxModel;
+ private JTree bogusJTree; // needed for tree cell renderer
+ private Dimension preferredSize;
+
+ public TreeChooser() {
+ preferredSize = new Dimension(300, 200);
+ model = new DefaultTreeModel(new DefaultMutableTreeNode("Root"));
+ displayPath = new TreePath(model.getRoot());
+ selectionModel = new DefaultTreeSelectionModel();
+ renderer = new DefaultTreeCellRenderer();
+ pathStack = new Stack();
+ pathIndent = 0; // 16;
+ comboBoxModel = new ChooserComboBoxModel(this);
+
+ bogusJTree = new JTree();
+ bogusJTree.setModel(model);
init();
- displayHome();
-
- stopListening(); // clear existing listeners
- startListening();
- }
-
- public Dimension getPreferredSize()
- {
- return preferredSize;
- }
-
- protected void init()
- {
- this.setLayout( new BorderLayout( 10, 10 ) );
-
+ displayHome();
+
+ stopListening(); // clear existing listeners
+ startListening();
+ }
+
+ public Dimension getPreferredSize() {
+ return preferredSize;
+ }
+
+ protected void init() {
+ this.setLayout(new BorderLayout(10, 10));
+
contents = initList();
- contents.getSelectionModel().setSelectionMode(
- ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
- // synchs with DefaultTreeSelectionModel
-
- JScrollPane scrollPane = new JScrollPane( contents );
- scrollPane.setPreferredSize( new Dimension( 200, 150 ) );
- this.add( scrollPane, BorderLayout.CENTER );
-
- Component previewPane = initPreviewPane();
- if ( previewPane != null )
- {
- this.add( previewPane, BorderLayout.EAST );
- }
-
+ contents.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ // synchs with DefaultTreeSelectionModel
+
+ JScrollPane scrollPane = new JScrollPane(contents);
+ scrollPane.setPreferredSize(new Dimension(200, 150));
+ this.add(scrollPane, BorderLayout.CENTER);
+
+ Component previewPane = initPreviewPane();
+ if (previewPane != null) {
+ this.add(previewPane, BorderLayout.EAST);
+ }
+
JPanel navigationPanel = new JPanel();
- navigationPanel.setLayout( new BorderLayout( 10, 10 ) );
- this.add( navigationPanel, BorderLayout.NORTH );
-
+ navigationPanel.setLayout(new BorderLayout(10, 10));
+ this.add(navigationPanel, BorderLayout.NORTH);
+
pathCombo = initComboBox();
- if ( pathCombo != null )
- {
- pathCombo.setModel( comboBoxModel );
+ if (pathCombo != null) {
+ pathCombo.setModel(comboBoxModel);
// put combo in a grid bag to handle varying
- // heights of JToolBars across platforms
+ // heights of JToolBars across platforms
JPanel panel = new JPanel();
- panel.setLayout( new GridBagLayout() );
+ panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
- panel.add( pathCombo, gbc );
- navigationPanel.add( panel, BorderLayout.CENTER );
- }
-
+ panel.add(pathCombo, gbc);
+ navigationPanel.add(panel, BorderLayout.CENTER);
+ }
+
Component toolBar = initToolBar();
- if ( toolBar != null )
- {
- navigationPanel.add( toolBar, BorderLayout.EAST );
- }
-
- }
-
- /**
- * Creates tool bar or return null if no tool bar is desired.
- * This implementation returns a JToolBar containing buttons
- * for BACK, UP, and HOME.
- */
- protected Component initToolBar()
- {
+ if (toolBar != null) {
+ navigationPanel.add(toolBar, BorderLayout.EAST);
+ }
+
+ }
+
+ /**
+ * Creates tool bar or return null if no tool bar is desired. This
+ * implementation returns a JToolBar containing buttons for BACK, UP, and HOME.
+ */
+ protected Component initToolBar() {
JToolBar toolBar = new JToolBar();
- toolBar.setFloatable( false );
- JButton button;
- button = new JButton( UIManager.getIcon("FileChooser.upFolderIcon") );
- button.setActionCommand( UP );
- button.addActionListener( this );
- toolBar.add( button );
- button = new JButton( UIManager.getIcon("FileChooser.homeFolderIcon") );
- button.setActionCommand( HOME );
- button.addActionListener( this );
- toolBar.add( button );
-/*
- button = new JButton( UIManager.getIcon("FileChooser.newFolderIcon") );
- button.setActionCommand( BACK );
- button.addActionListener( this );
- toolBar.add( button );
-*/
- return toolBar;
- }
-
- /**
- * Creates the component that is used to display a preview of the
- * selected item(s) in the content area. This component would listen
- * to the selection model to update itself when the selected items change.
- * Return null to omit this component.
- * This implementation returns null.
- */
- protected Component initPreviewPane()
- {
- return null;
- }
-
- /**
- * Creates the JComboBox that is used to render the path leading to
- * the displayed contents. Return null to omit this combo box.
- * This implementation returns a stock JComboBox that uses this
- * class as its cell renderer.
- */
- protected JComboBox initComboBox()
- {
- JComboBox comboBox = new JComboBox();
- comboBox.setRenderer( this );
- return comboBox;
- }
-
- /**
- * Creates the JList that is used to render the path leading to
- * the displayed contents. This method may not return null.
- * This implementation returns a stock JList that uses this
- * class as its cell renderer and fires a SELECT action event
- * on double click.
- */
- protected JList initList()
- {
- JList list = new JList();
- list.setCellRenderer( this );
- list.addMouseListener( new MouseAdapter()
- {
- public void mouseClicked( MouseEvent evt )
- {
- if ( evt.getClickCount() > 1 )
- {
- actionPerformed( new ActionEvent( this, 0, SELECT ) );
- }
- }
- });
- return list;
- }
-
- /**
- * Begins listening to the specified tree model
- * and tree selection model.
- */
- protected void startListening()
- {
- model.addTreeModelListener( this );
- selectionModel.addTreeSelectionListener( this );
- contents.addListSelectionListener( this );
- }
-
- /**
- * Stops listening to the specified tree model
- * and tree selection model.
- */
- protected void stopListening()
- {
- model.removeTreeModelListener( this );
- selectionModel.removeTreeSelectionListener( this );
- contents.removeListSelectionListener( this );
- }
-
- /**
- * Returns the TreeModel used by the TreeChooser.
- */
- public TreeModel getModel()
- {
- return model;
- }
-
- /**
- * Sets the TreeModel used by the TreeChooser.
- */
- public void setModel( TreeModel aTreeModel )
- {
- stopListening();
- model = aTreeModel;
- bogusJTree.setModel( aTreeModel );
- pathStack.removeAllElements();
- startListening();
- displayHome();
- }
-
- /**
- * Returns the TreeSelectionModel used by the TreeChooser.
- */
- public TreeSelectionModel getSelectionModel()
- {
- return selectionModel;
- }
-
- /**
- * Sets the TreeSelectionModel used by the TreeChooser.
- */
- public void setSelectionModel( TreeSelectionModel aSelectionModel )
- {
- selectionModel = aSelectionModel;
- if ( aSelectionModel.getSelectionMode() ==
- TreeSelectionModel.SINGLE_TREE_SELECTION )
- {
- contents.getSelectionModel().setSelectionMode(
- ListSelectionModel.SINGLE_SELECTION );
- }
- else
- {
- contents.getSelectionModel().setSelectionMode(
- ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
- }
- updateSelection();
- }
-
- /**
- * Returns the TreeCellRenderer used by the TreeChooser.
- */
- public TreeCellRenderer getRenderer()
- {
- return renderer;
- }
-
- /**
- * Sets the TreeCellRenderer used by the TreeChooser.
- */
- public void setRenderer( TreeCellRenderer aRenderer )
- {
- renderer = aRenderer;
- updateContents();
- }
-
- /**
- * Displays the "home" directory.
- * This implementation displays the root node's children.
- */
- public void displayHome()
- {
- setDisplayPath( null );
- }
-
- /**
- * Displays the parent path of the currently displayed path.
- */
- public void displayParent()
- {
- setDisplayPath( displayPath.getParentPath() );
- }
-
- /**
- * Displays the last displayed path before the current one,
- * emulating the behavior of a "back" button.
- */
- public void displayPrevious()
- {
- if ( pathStack.empty() )
- {
- displayHome();
- }
- else
- {
- setDisplayPathDirect( (TreePath) pathStack.pop() );
- updateContents();
- }
- }
-
- /**
- * Pushes the previous item onto the stack, sets
- * the display path, and then updates the contents.
- * If aPath is null, the root node's children are displayed.
- */
- public void setDisplayPath( TreePath aPath )
- {
- if ( aPath == null )
- {
- aPath = new TreePath( getModel().getRoot() );
- }
- if ( ! displayPath.equals ( aPath ) )
- {
- pathStack.push( displayPath );
- setDisplayPathDirect( aPath );
- }
- updateContents();
- }
-
- /**
- * Sets the displayPath field and does not
- * update the stack nor update the contents.
- */
- protected void setDisplayPathDirect( TreePath aPath )
- {
- displayPath = aPath;
- }
-
- /**
- * Gets the currently displayed path.
- */
- public TreePath getDisplayPath()
- {
- return displayPath;
- }
-
- /**
- * Called when selected path changes or when model indicates
- * that the displayed path has changed.
- */
- protected void updateContents()
- {
- stopListening();
-
- // update combo box
- comboBoxModel.fireContentsChanged();
-
- // update list contents
- Object displayedObject = displayPath.getLastPathComponent();
-/*
-//FIXME: this display group doesn't seem to be getting the sort orderings from parent
-if ( displayedObject instanceof net.wotonomy.ui.EODisplayGroup )
-System.out.println( ((net.wotonomy.ui.EODisplayGroup)displayedObject).displayedObjects() );
-*/
- int count = model.getChildCount( displayedObject );
- Object[] children = new Object[ count ];
- for ( int i = 0; i < count; i++ )
- {
- children[i] = model.getChild( displayedObject, i );
- }
- contents.setListData( children );
-
- startListening();
-
- // synchronize the selection
- updateSelection();
- }
-
- /**
- * Updates the selection in the list to reflect the
- * selection in the tree selection model.
- */
- public void updateSelection()
- {
- int index;
- Object last = displayPath.getLastPathComponent();
- TreePath[] selectionPaths = selectionModel.getSelectionPaths();
- if ( selectionPaths != null )
- {
- List selectedIndices = new LinkedList();
- for ( int i = 0; i < selectionPaths.length; i++ )
- {
- if ( displayPath.equals( selectionPaths[i].getParentPath() ) )
- {
- index = getModel().getIndexOfChild(
- last, selectionPaths[i].getLastPathComponent() );
- if ( index != -1 )
- {
- selectedIndices.add( new Integer( index ) );
- }
- else // should never happen
- {
- throw new WotonomyException(
- "Could not find child of displayed node." );
- }
- }
- }
- int[] selected = new int[ selectedIndices.size() ];
- for ( int i = 0; i < selected.length; i++ )
- {
- selected[i] = ((Integer)selectedIndices.get(i)).intValue();
- }
- stopListening();
- contents.setSelectedIndices( selected );
- startListening();
- }
- }
-
- // interface TreeModelListener
-
- public void treeNodesChanged( TreeModelEvent evt )
- {
-/*
- if ( displayPath.getLastPathComponent().toString().equals(
- evt.getTreePath().getLastPathComponent().toString() ) )
- {
-System.out.println( "TreeChooser.treeNodesChanged: " + count++ );
-*/
- updateContents();
-/*
- }
- else
- {
- System.out.println( evt.getTreePath() + " != " + displayPath );
- }
-*/
- }
-
- public void treeNodesInserted( TreeModelEvent evt )
- {
+ toolBar.setFloatable(false);
+ JButton button;
+ button = new JButton(UIManager.getIcon("FileChooser.upFolderIcon"));
+ button.setActionCommand(UP);
+ button.addActionListener(this);
+ toolBar.add(button);
+ button = new JButton(UIManager.getIcon("FileChooser.homeFolderIcon"));
+ button.setActionCommand(HOME);
+ button.addActionListener(this);
+ toolBar.add(button);
+ /*
+ * button = new JButton( UIManager.getIcon("FileChooser.newFolderIcon") );
+ * button.setActionCommand( BACK ); button.addActionListener( this );
+ * toolBar.add( button );
+ */
+ return toolBar;
+ }
+
+ /**
+ * Creates the component that is used to display a preview of the selected
+ * item(s) in the content area. This component would listen to the selection
+ * model to update itself when the selected items change. Return null to omit
+ * this component. This implementation returns null.
+ */
+ protected Component initPreviewPane() {
+ return null;
+ }
+
+ /**
+ * Creates the JComboBox that is used to render the path leading to the
+ * displayed contents. Return null to omit this combo box. This implementation
+ * returns a stock JComboBox that uses this class as its cell renderer.
+ */
+ protected JComboBox initComboBox() {
+ JComboBox comboBox = new JComboBox();
+ comboBox.setRenderer(this);
+ return comboBox;
+ }
+
+ /**
+ * Creates the JList that is used to render the path leading to the displayed
+ * contents. This method may not return null. This implementation returns a
+ * stock JList that uses this class as its cell renderer and fires a SELECT
+ * action event on double click.
+ */
+ protected JList initList() {
+ JList list = new JList();
+ list.setCellRenderer(this);
+ list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent evt) {
+ if (evt.getClickCount() > 1) {
+ actionPerformed(new ActionEvent(this, 0, SELECT));
+ }
+ }
+ });
+ return list;
+ }
+
+ /**
+ * Begins listening to the specified tree model and tree selection model.
+ */
+ protected void startListening() {
+ model.addTreeModelListener(this);
+ selectionModel.addTreeSelectionListener(this);
+ contents.addListSelectionListener(this);
+ }
+
+ /**
+ * Stops listening to the specified tree model and tree selection model.
+ */
+ protected void stopListening() {
+ model.removeTreeModelListener(this);
+ selectionModel.removeTreeSelectionListener(this);
+ contents.removeListSelectionListener(this);
+ }
+
+ /**
+ * Returns the TreeModel used by the TreeChooser.
+ */
+ public TreeModel getModel() {
+ return model;
+ }
+
+ /**
+ * Sets the TreeModel used by the TreeChooser.
+ */
+ public void setModel(TreeModel aTreeModel) {
+ stopListening();
+ model = aTreeModel;
+ bogusJTree.setModel(aTreeModel);
+ pathStack.removeAllElements();
+ startListening();
+ displayHome();
+ }
+
+ /**
+ * Returns the TreeSelectionModel used by the TreeChooser.
+ */
+ public TreeSelectionModel getSelectionModel() {
+ return selectionModel;
+ }
+
+ /**
+ * Sets the TreeSelectionModel used by the TreeChooser.
+ */
+ public void setSelectionModel(TreeSelectionModel aSelectionModel) {
+ selectionModel = aSelectionModel;
+ if (aSelectionModel.getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION) {
+ contents.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ } else {
+ contents.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ }
+ updateSelection();
+ }
+
+ /**
+ * Returns the TreeCellRenderer used by the TreeChooser.
+ */
+ public TreeCellRenderer getRenderer() {
+ return renderer;
+ }
+
+ /**
+ * Sets the TreeCellRenderer used by the TreeChooser.
+ */
+ public void setRenderer(TreeCellRenderer aRenderer) {
+ renderer = aRenderer;
+ updateContents();
+ }
+
+ /**
+ * Displays the "home" directory. This implementation displays the root node's
+ * children.
+ */
+ public void displayHome() {
+ setDisplayPath(null);
+ }
+
+ /**
+ * Displays the parent path of the currently displayed path.
+ */
+ public void displayParent() {
+ setDisplayPath(displayPath.getParentPath());
+ }
+
+ /**
+ * Displays the last displayed path before the current one, emulating the
+ * behavior of a "back" button.
+ */
+ public void displayPrevious() {
+ if (pathStack.empty()) {
+ displayHome();
+ } else {
+ setDisplayPathDirect((TreePath) pathStack.pop());
+ updateContents();
+ }
+ }
+
+ /**
+ * Pushes the previous item onto the stack, sets the display path, and then
+ * updates the contents. If aPath is null, the root node's children are
+ * displayed.
+ */
+ public void setDisplayPath(TreePath aPath) {
+ if (aPath == null) {
+ aPath = new TreePath(getModel().getRoot());
+ }
+ if (!displayPath.equals(aPath)) {
+ pathStack.push(displayPath);
+ setDisplayPathDirect(aPath);
+ }
+ updateContents();
+ }
+
+ /**
+ * Sets the displayPath field and does not update the stack nor update the
+ * contents.
+ */
+ protected void setDisplayPathDirect(TreePath aPath) {
+ displayPath = aPath;
+ }
+
+ /**
+ * Gets the currently displayed path.
+ */
+ public TreePath getDisplayPath() {
+ return displayPath;
+ }
+
+ /**
+ * Called when selected path changes or when model indicates that the displayed
+ * path has changed.
+ */
+ protected void updateContents() {
+ stopListening();
+
+ // update combo box
+ comboBoxModel.fireContentsChanged();
+
+ // update list contents
+ Object displayedObject = displayPath.getLastPathComponent();
+ /*
+ * //FIXME: this display group doesn't seem to be getting the sort orderings
+ * from parent if ( displayedObject instanceof net.wotonomy.ui.EODisplayGroup )
+ * System.out.println(
+ * ((net.wotonomy.ui.EODisplayGroup)displayedObject).displayedObjects() );
+ */
+ int count = model.getChildCount(displayedObject);
+ Object[] children = new Object[count];
+ for (int i = 0; i < count; i++) {
+ children[i] = model.getChild(displayedObject, i);
+ }
+ contents.setListData(children);
+
+ startListening();
+
+ // synchronize the selection
+ updateSelection();
+ }
+
+ /**
+ * Updates the selection in the list to reflect the selection in the tree
+ * selection model.
+ */
+ public void updateSelection() {
+ int index;
+ Object last = displayPath.getLastPathComponent();
+ TreePath[] selectionPaths = selectionModel.getSelectionPaths();
+ if (selectionPaths != null) {
+ List selectedIndices = new LinkedList();
+ for (int i = 0; i < selectionPaths.length; i++) {
+ if (displayPath.equals(selectionPaths[i].getParentPath())) {
+ index = getModel().getIndexOfChild(last, selectionPaths[i].getLastPathComponent());
+ if (index != -1) {
+ selectedIndices.add(new Integer(index));
+ } else // should never happen
+ {
+ throw new WotonomyException("Could not find child of displayed node.");
+ }
+ }
+ }
+ int[] selected = new int[selectedIndices.size()];
+ for (int i = 0; i < selected.length; i++) {
+ selected[i] = ((Integer) selectedIndices.get(i)).intValue();
+ }
+ stopListening();
+ contents.setSelectedIndices(selected);
+ startListening();
+ }
+ }
+
+ // interface TreeModelListener
+
+ public void treeNodesChanged(TreeModelEvent evt) {
+ /*
+ * if ( displayPath.getLastPathComponent().toString().equals(
+ * evt.getTreePath().getLastPathComponent().toString() ) ) { System.out.println(
+ * "TreeChooser.treeNodesChanged: " + count++ );
+ */
+ updateContents();
+ /*
+ * } else { System.out.println( evt.getTreePath() + " != " + displayPath ); }
+ */
+ }
+
+ public void treeNodesInserted(TreeModelEvent evt) {
// updateContents();
- }
-
- public void treeNodesRemoved( TreeModelEvent evt )
- {
+ }
+
+ public void treeNodesRemoved(TreeModelEvent evt) {
// updateContents();
- }
-
- public void treeStructureChanged( TreeModelEvent evt )
- {
- if ( ( evt.getTreePath().equals( displayPath ) )
- || ( evt.getTreePath().isDescendant( displayPath ) ) )
- {
+ }
+
+ public void treeStructureChanged(TreeModelEvent evt) {
+ if ((evt.getTreePath().equals(displayPath)) || (evt.getTreePath().isDescendant(displayPath))) {
// setDisplayPath( evt.getTreePath() );
- }
-
- displayHome();
- }
-
- // interface TreeSelectionListener
-
- /**
- * Called when the tree selection model's value changes.
- * This is presumably an external change, so this calls
- * updateSelection.
- */
- public void valueChanged( TreeSelectionEvent evt )
- {
- updateSelection();
- }
-
- // interface ListSelectionListener
-
- /**
- * Called when user changes the selection in the list.
- * This implementation updates the tree selection model
- * with the corresponding selection.
- */
- public void valueChanged( ListSelectionEvent evt )
- {
- if ( ! evt.getValueIsAdjusting() )
- {
- Object last = displayPath.getLastPathComponent();
- int[] selection = contents.getSelectedIndices();
- TreePath[] selectionPaths = new TreePath[ selection.length ];
- for ( int i = 0; i < selection.length; i++ )
- {
- selectionPaths[i] = displayPath.pathByAddingChild(
- getModel().getChild( last, selection[i] ) );
- }
- selectionModel.setSelectionPaths( selectionPaths );
- }
-
- }
-
- // interface ListCellRenderer
-
- /**
- * This method returns the component returned by the tree cell renderer.
- */
- public Component getListCellRendererComponent(
- JList list,
- Object value,
- int index,
- boolean isSelected,
- boolean cellHasFocus )
- {
- boolean isLeaf = ( model.isLeaf( value ) );
-
- bogusJTree.setForeground( list.getForeground() );
- bogusJTree.setBackground( list.getBackground() );
-
- JComponent result = (JComponent) renderer.getTreeCellRendererComponent(
- bogusJTree, value, isSelected, (list != contents),
- isLeaf, index, cellHasFocus );
-/*
- if ( ( list != contents ) && ( index > -1 ) )
- {
- result.setBorder(
- BorderFactory.createEmptyBorder( 0, index*pathIndent, 0, 0 ) );
- }
- else
- {
- result.setBorder(
- BorderFactory.createEmptyBorder() );
- }
-*/
- return result;
- }
-
- // interface ActionListener
-
- public void actionPerformed( ActionEvent evt )
- {
- String command = evt.getActionCommand();
-
- if ( HOME.equals( command ) )
- {
- displayHome();
- }
- else
- if ( UP.equals( command ) )
- {
- displayParent();
- }
- else
- if ( BACK.equals( command ) )
- {
- displayPrevious();
- }
- else
- if ( SELECT.equals( command ) )
- {
- Cursor oldCursor = getCursor();
- setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
-
- int index = contents.getSelectedIndex();
- // if selection
- if ( index != -1 )
- {
- Object parent = displayPath.getLastPathComponent();
- Object child = getModel().getChild( parent, index );
- // if selected item is not a leaf
- if ( getModel().getChildCount( child ) > 0 )
- {
- // navigate to selected item
- setDisplayPath( displayPath.pathByAddingChild( child ) );
- }
- }
-
- setCursor( oldCursor );
- }
-
- }
-
- private class ChooserComboBoxModel implements ComboBoxModel
- {
- TreeChooser treeChooser;
- Vector listeners;
-
- ChooserComboBoxModel( TreeChooser aTreeChooser )
- {
- treeChooser = aTreeChooser;
- listeners = new Vector();
- }
-
- public int getSize()
- {
- return treeChooser.displayPath.getPathCount();
- }
-
- public Object getElementAt(int index)
- {
- return treeChooser.displayPath.getPathComponent( index );
- }
-
- public Object getSelectedItem()
- {
- return treeChooser.displayPath.getLastPathComponent();
- }
-
- public void setSelectedItem(Object anItem)
- {
- if ( ! (
- treeChooser.displayPath.getLastPathComponent().equals( anItem ) ) )
- {
- Object[] items = treeChooser.displayPath.getPath();
- TreePath path = new TreePath( getModel().getRoot() );
- for ( int i = 1; i < items.length; i++ )
- {
- if ( path.getLastPathComponent() == anItem )
- {
- treeChooser.setDisplayPath( path );
- return;
- }
- path = path.pathByAddingChild( items[i] );
- }
- }
- }
-
- public void addListDataListener(ListDataListener l)
- {
- listeners.add( l );
- }
-
- public void removeListDataListener(ListDataListener l)
- {
- listeners.remove( l );
- }
-
- public void fireContentsChanged()
- {
- Enumeration e = listeners.elements();
- while ( e.hasMoreElements() )
- {
- ((ListDataListener)e.nextElement()).contentsChanged(
- new ListDataEvent(
- this, ListDataEvent.CONTENTS_CHANGED, 0, getSize() ) );
- }
- }
- }
-
-}
+ }
+
+ displayHome();
+ }
+
+ // interface TreeSelectionListener
+
+ /**
+ * Called when the tree selection model's value changes. This is presumably an
+ * external change, so this calls updateSelection.
+ */
+ public void valueChanged(TreeSelectionEvent evt) {
+ updateSelection();
+ }
+ // interface ListSelectionListener
+ /**
+ * Called when user changes the selection in the list. This implementation
+ * updates the tree selection model with the corresponding selection.
+ */
+ public void valueChanged(ListSelectionEvent evt) {
+ if (!evt.getValueIsAdjusting()) {
+ Object last = displayPath.getLastPathComponent();
+ int[] selection = contents.getSelectedIndices();
+ TreePath[] selectionPaths = new TreePath[selection.length];
+ for (int i = 0; i < selection.length; i++) {
+ selectionPaths[i] = displayPath.pathByAddingChild(getModel().getChild(last, selection[i]));
+ }
+ selectionModel.setSelectionPaths(selectionPaths);
+ }
+
+ }
+
+ // interface ListCellRenderer
+
+ /**
+ * This method returns the component returned by the tree cell renderer.
+ */
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ boolean isLeaf = (model.isLeaf(value));
+
+ bogusJTree.setForeground(list.getForeground());
+ bogusJTree.setBackground(list.getBackground());
+
+ JComponent result = (JComponent) renderer.getTreeCellRendererComponent(bogusJTree, value, isSelected,
+ (list != contents), isLeaf, index, cellHasFocus);
+ /*
+ * if ( ( list != contents ) && ( index > -1 ) ) { result.setBorder(
+ * BorderFactory.createEmptyBorder( 0, index*pathIndent, 0, 0 ) ); } else {
+ * result.setBorder( BorderFactory.createEmptyBorder() ); }
+ */
+ return result;
+ }
+
+ // interface ActionListener
+
+ public void actionPerformed(ActionEvent evt) {
+ String command = evt.getActionCommand();
+
+ if (HOME.equals(command)) {
+ displayHome();
+ } else if (UP.equals(command)) {
+ displayParent();
+ } else if (BACK.equals(command)) {
+ displayPrevious();
+ } else if (SELECT.equals(command)) {
+ Cursor oldCursor = getCursor();
+ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+ int index = contents.getSelectedIndex();
+ // if selection
+ if (index != -1) {
+ Object parent = displayPath.getLastPathComponent();
+ Object child = getModel().getChild(parent, index);
+ // if selected item is not a leaf
+ if (getModel().getChildCount(child) > 0) {
+ // navigate to selected item
+ setDisplayPath(displayPath.pathByAddingChild(child));
+ }
+ }
+
+ setCursor(oldCursor);
+ }
+
+ }
+
+ private class ChooserComboBoxModel implements ComboBoxModel {
+ TreeChooser treeChooser;
+ Vector listeners;
+
+ ChooserComboBoxModel(TreeChooser aTreeChooser) {
+ treeChooser = aTreeChooser;
+ listeners = new Vector();
+ }
+
+ public int getSize() {
+ return treeChooser.displayPath.getPathCount();
+ }
+
+ public Object getElementAt(int index) {
+ return treeChooser.displayPath.getPathComponent(index);
+ }
+
+ public Object getSelectedItem() {
+ return treeChooser.displayPath.getLastPathComponent();
+ }
+
+ public void setSelectedItem(Object anItem) {
+ if (!(treeChooser.displayPath.getLastPathComponent().equals(anItem))) {
+ Object[] items = treeChooser.displayPath.getPath();
+ TreePath path = new TreePath(getModel().getRoot());
+ for (int i = 1; i < items.length; i++) {
+ if (path.getLastPathComponent() == anItem) {
+ treeChooser.setDisplayPath(path);
+ return;
+ }
+ path = path.pathByAddingChild(items[i]);
+ }
+ }
+ }
+
+ public void addListDataListener(ListDataListener l) {
+ listeners.add(l);
+ }
+
+ public void removeListDataListener(ListDataListener l) {
+ listeners.remove(l);
+ }
+
+ public void fireContentsChanged() {
+ Enumeration e = listeners.elements();
+ while (e.hasMoreElements()) {
+ ((ListDataListener) e.nextElement())
+ .contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize()));
+ }
+ }
+ }
+
+}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeTableCellRenderer.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeTableCellRenderer.java
index fbf3791..c6e1a99 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeTableCellRenderer.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/components/TreeTableCellRenderer.java
@@ -32,193 +32,158 @@ import javax.swing.JViewport;
import javax.swing.table.TableCellRenderer;
/**
-* A TableCellRenderer that paints a portion of a JTree.
-* Extends JViewport to take advantage of buffering and
-* fast blitting (avoids repeated clipping and repainting).
-* Defaults opaque to false: to see selection background
-* painted, call setOpaque( true ).
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * A TableCellRenderer that paints a portion of a JTree. Extends JViewport to
+ * take advantage of buffering and fast blitting (avoids repeated clipping and
+ * repainting). Defaults opaque to false: to see selection background painted,
+ * call setOpaque( true ).
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
public class TreeTableCellRenderer extends JViewport implements TableCellRenderer, MouseListener {
- JTree tree;
- Component emptyComponent;
- JTable delegateTable;
- int lastKnownColumn;
-
- /**
- * Constructor takes a JTree and modifies it by setting
- * rootVisible to false, showsRootHandles to true,
- * opaque to false, and border to null.
- */
- public TreeTableCellRenderer( JTree aTree )
- {
- setView( aTree );
- setBorder( null );
- tree = aTree;
- tree.setRootVisible( false );
- tree.setShowsRootHandles( true );
- tree.setBorder( null );
- tree.setOpaque( false );
-
- Object renderer = tree.getCellRenderer();
- if ( renderer instanceof JComponent )
- {
- ((JComponent)renderer).setOpaque( false );
- }
- Object editor = tree.getCellEditor();
- if ( editor instanceof JComponent )
- {
- ((JComponent)editor).setOpaque( false );
- }
-
- this.setOpaque( false );
- emptyComponent = new JLabel();
- }
-
- public Component getTableCellRendererComponent(
- JTable table, Object value,
- boolean isSelected, boolean hasFocus,
- int row, int column)
- {
- if ( isSelected )
- {
- setForeground( table.getSelectionForeground() );
- setBackground( table.getSelectionBackground() );
- }
- else
- {
- setForeground( table.getForeground() );
- setBackground( table.getBackground() );
- }
-
- lastKnownColumn = column;
- if ( delegateTable != table )
- {
- if ( delegateTable != null )
- {
- delegateTable.removeMouseListener( this );
- }
- table.addMouseListener( this );
- delegateTable = table;
- }
-
- Rectangle rect = tree.getRowBounds( row );
- if ( rect != null )
- {
- setViewPosition( new Point( 0 /*rect.x*/, rect.y ) );
-
- //FIXME: this causes problems for some LAFs (like Metal):
- // in particular, the table height seems to get stuck.
- //if ( table.getRowHeight( row ) != rect.height )
- //{
- // table.setRowHeight( row, rect.height );
- //}
- return this;
- }
- else
- {
- return emptyComponent;
- }
- }
-
- public void mouseClicked(MouseEvent e)
- {
- delegateToTree( e );
- }
-
- public void mousePressed(MouseEvent e)
- {
- delegateToTree( e );
- }
-
- public void mouseReleased(MouseEvent e)
- {
- delegateToTree( e );
- }
-
- public void mouseEntered(MouseEvent e)
- {
- delegateToTree( e );
- }
-
- public void mouseExited(MouseEvent e)
- {
- delegateToTree( e );
- }
-
- protected void delegateToTree(MouseEvent e)
- {
- int col = delegateTable.getColumnModel().getColumnIndexAtX( e.getX() );
- if ( col == lastKnownColumn )
- {
- Rectangle nodeRect = tree.getRowBounds( 0 );
- Rectangle cellRect = delegateTable.getCellRect( -1, col, false );
- if ( nodeRect != null )
- {
- e.translatePoint( -cellRect.x, nodeRect.y );
- tree.dispatchEvent( // e );
- new MouseEvent( tree, e.getID(), e.getWhen(), e.getModifiers(),
- e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger() ) );
- }
- }
- }
-
- public void repaint()
- {
- //if ( delegateTable != null ) delegateTable.repaint();
-
- // not calling super.repaint() does not seem to cause
- // any problems so we're not doing it.
- }
+ JTree tree;
+ Component emptyComponent;
+ JTable delegateTable;
+ int lastKnownColumn;
+
+ /**
+ * Constructor takes a JTree and modifies it by setting rootVisible to false,
+ * showsRootHandles to true, opaque to false, and border to null.
+ */
+ public TreeTableCellRenderer(JTree aTree) {
+ setView(aTree);
+ setBorder(null);
+ tree = aTree;
+ tree.setRootVisible(false);
+ tree.setShowsRootHandles(true);
+ tree.setBorder(null);
+ tree.setOpaque(false);
+
+ Object renderer = tree.getCellRenderer();
+ if (renderer instanceof JComponent) {
+ ((JComponent) renderer).setOpaque(false);
+ }
+ Object editor = tree.getCellEditor();
+ if (editor instanceof JComponent) {
+ ((JComponent) editor).setOpaque(false);
+ }
+
+ this.setOpaque(false);
+ emptyComponent = new JLabel();
+ }
+
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ if (isSelected) {
+ setForeground(table.getSelectionForeground());
+ setBackground(table.getSelectionBackground());
+ } else {
+ setForeground(table.getForeground());
+ setBackground(table.getBackground());
+ }
+
+ lastKnownColumn = column;
+ if (delegateTable != table) {
+ if (delegateTable != null) {
+ delegateTable.removeMouseListener(this);
+ }
+ table.addMouseListener(this);
+ delegateTable = table;
+ }
+
+ Rectangle rect = tree.getRowBounds(row);
+ if (rect != null) {
+ setViewPosition(new Point(0 /* rect.x */, rect.y));
+
+ // FIXME: this causes problems for some LAFs (like Metal):
+ // in particular, the table height seems to get stuck.
+ // if ( table.getRowHeight( row ) != rect.height )
+ // {
+ // table.setRowHeight( row, rect.height );
+ // }
+ return this;
+ } else {
+ return emptyComponent;
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ delegateToTree(e);
+ }
+
+ public void mousePressed(MouseEvent e) {
+ delegateToTree(e);
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ delegateToTree(e);
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ delegateToTree(e);
+ }
+
+ public void mouseExited(MouseEvent e) {
+ delegateToTree(e);
+ }
+
+ protected void delegateToTree(MouseEvent e) {
+ int col = delegateTable.getColumnModel().getColumnIndexAtX(e.getX());
+ if (col == lastKnownColumn) {
+ Rectangle nodeRect = tree.getRowBounds(0);
+ Rectangle cellRect = delegateTable.getCellRect(-1, col, false);
+ if (nodeRect != null) {
+ e.translatePoint(-cellRect.x, nodeRect.y);
+ tree.dispatchEvent( // e );
+ new MouseEvent(tree, e.getID(), e.getWhen(), e.getModifiers(), e.getX(), e.getY(),
+ e.getClickCount(), e.isPopupTrigger()));
+ }
+ }
+ }
+
+ public void repaint() {
+ // if ( delegateTable != null ) delegateTable.repaint();
+
+ // not calling super.repaint() does not seem to cause
+ // any problems so we're not doing it.
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.11 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.11 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.10 2002/04/12 20:07:35 mpowers
- * Fixed cool/annoying view position.
+ * Revision 1.10 2002/04/12 20:07:35 mpowers Fixed cool/annoying view position.
*
- * Revision 1.9 2002/04/09 18:12:21 mpowers
- * Fixes for 1.4.
+ * Revision 1.9 2002/04/09 18:12:21 mpowers Fixes for 1.4.
*
- * Revision 1.8 2002/03/22 22:39:24 mpowers
- * Can now move column to any position in the table.
+ * Revision 1.8 2002/03/22 22:39:24 mpowers Can now move column to any position
+ * in the table.
*
- * Revision 1.7 2002/03/11 03:13:22 mpowers
- * Adjusting for viewport position; no longer responding to repaint().
+ * Revision 1.7 2002/03/11 03:13:22 mpowers Adjusting for viewport position; no
+ * longer responding to repaint().
*
- * Revision 1.6 2002/03/07 23:04:36 mpowers
- * Refining TreeColumnAssociation.
+ * Revision 1.6 2002/03/07 23:04:36 mpowers Refining TreeColumnAssociation.
*
- * Revision 1.5 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.5 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.3 2002/02/27 23:19:17 mpowers
- * Refactoring of TreeAssociation to create TreeModelAssociation parent.
+ * Revision 1.3 2002/02/27 23:19:17 mpowers Refactoring of TreeAssociation to
+ * create TreeModelAssociation parent.
*
- * Revision 1.2 2002/02/18 23:13:55 mpowers
- * Only setting row height when needed.
+ * Revision 1.2 2002/02/18 23:13:55 mpowers Only setting row height when needed.
*
- * Revision 1.1 2002/02/18 03:46:08 mpowers
- * Implemented TreeTableCellRenderer.
+ * Revision 1.1 2002/02/18 03:46:08 mpowers Implemented TreeTableCellRenderer.
*
*
*/
-
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ClassGrabber.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ClassGrabber.java
index 4412dbc..0e95d2d 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ClassGrabber.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ClassGrabber.java
@@ -25,79 +25,67 @@ import java.io.InputStream;
import java.util.Hashtable;
/**
- * ClassGrabber is a class loader used by WindowGrabber.
- * It simply loads classes by filename and nothing more.
- * It exists mainly because the java 1.1 class loading
- * framework doesn't easily allow the creation of class
- * loaders nor the loading of arbitrary classes.
+ * ClassGrabber is a class loader used by WindowGrabber. It simply loads classes
+ * by filename and nothing more. It exists mainly because the java 1.1 class
+ * loading framework doesn't easily allow the creation of class loaders nor the
+ * loading of arbitrary classes.
*
* @author michael@mpowers.net
- * @version $Revision: 904 $
- * $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
*/
-public class ClassGrabber extends ClassLoader
-{
+public class ClassGrabber extends ClassLoader {
Hashtable classMap = new Hashtable();
- public ClassGrabber()
- {
+ public ClassGrabber() {
super();
}
- protected Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- Class c = (Class) classMap.get( name );
+ protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ Class c = (Class) classMap.get(name);
- if ( c != null ) return c;
+ if (c != null)
+ return c;
- try
- {
- c = findSystemClass( name );
- }
- catch ( Exception exc1 )
- {
+ try {
+ c = findSystemClass(name);
+ } catch (Exception exc1) {
// System.err.print( "findSystemClass: " + name + ": " );
// System.err.println( exc1 );
}
- if ( c != null ) return c;
+ if (c != null)
+ return c;
- try
- {
- c = findLoadedClass( name );
- }
- catch ( Exception exc1 )
- {
+ try {
+ c = findLoadedClass(name);
+ } catch (Exception exc1) {
// System.err.print( "findLoadedClass: " + name + ": " );
// System.err.println( exc1 );
}
-
- if ( c != null ) return c;
-
- try
- {
- InputStream input = new BufferedInputStream( new FileInputStream( name ) );
- ByteArrayOutputStream output = new ByteArrayOutputStream( 200 );
+
+ if (c != null)
+ return c;
+
+ try {
+ InputStream input = new BufferedInputStream(new FileInputStream(name));
+ ByteArrayOutputStream output = new ByteArrayOutputStream(200);
int ch;
- while ( ( ch = input.read() ) != -1 )
- {
- output.write( ch );
+ while ((ch = input.read()) != -1) {
+ output.write(ch);
}
byte[] data = output.toByteArray();
- c = defineClass( null, data, 0, data.length );
- }
- catch ( Exception exc )
- {
- System.err.print( "getResource: " + name + ": " );
- System.err.println( exc );
- c = null;
+ c = defineClass(null, data, 0, data.length);
+ } catch (Exception exc) {
+ System.err.print("getResource: " + name + ": ");
+ System.err.println(exc);
+ c = null;
}
- if ( c != null )
- {
- classMap.put( name, c );
- if ( resolve ) resolveClass( c );
+ if (c != null) {
+ classMap.put(name, c);
+ if (resolve)
+ resolveClass(c);
}
return c;
@@ -105,22 +93,18 @@ public class ClassGrabber extends ClassLoader
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1.1.1 2000/12/21 15:51:18 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:18 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:45 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:45 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ComponentHighlighter.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ComponentHighlighter.java
index c63157d..08e6216 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ComponentHighlighter.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ComponentHighlighter.java
@@ -36,125 +36,115 @@ import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
-* Visually highlights a component with the specified image for a brief period.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*/
-public class ComponentHighlighter implements ActionListener
-{
- // lots of state to track
- JRootPane rootPane;
- JComponent component;
- Component oldGlassPane;
- JLabel imageLabel;
- Timer timer;
- JPanel glassPane;
-
-/**
-* Alternate "Fire-and-forget" constructor loads an image from a URL.
-* @param aComponent A Component that will be highlighted.
-* @param aURL A URL pointing to an image.
-*/
- public ComponentHighlighter( JComponent aComponent, URL aURL )
- {
- if ( aURL == null ) return;
- init( aComponent, Toolkit.getDefaultToolkit().getImage( aURL ) );
- }
-
-/**
-* "Fire-and-forget" constructor.
-* @param aComponent A Component that will be highlighted.
-* @param anImage An image, preferably an animated GIF with transparency,
-* that will slide along the length of the component.
-*/
- public ComponentHighlighter( JComponent aComponent, Image anImage )
- {
- init( aComponent, anImage );
- }
-
- protected void init( JComponent aComponent, Image anImage )
- {
- if ( ( aComponent == null ) || ( anImage == null ) ) return;
-
- component = aComponent;
- rootPane = SwingUtilities.getRootPane( component );
- oldGlassPane = rootPane.getGlassPane();
+ * Visually highlights a component with the specified image for a brief period.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ */
+public class ComponentHighlighter implements ActionListener {
+ // lots of state to track
+ JRootPane rootPane;
+ JComponent component;
+ Component oldGlassPane;
+ JLabel imageLabel;
+ Timer timer;
+ JPanel glassPane;
+
+ /**
+ * Alternate "Fire-and-forget" constructor loads an image from a URL.
+ *
+ * @param aComponent A Component that will be highlighted.
+ * @param aURL A URL pointing to an image.
+ */
+ public ComponentHighlighter(JComponent aComponent, URL aURL) {
+ if (aURL == null)
+ return;
+ init(aComponent, Toolkit.getDefaultToolkit().getImage(aURL));
+ }
+
+ /**
+ * "Fire-and-forget" constructor.
+ *
+ * @param aComponent A Component that will be highlighted.
+ * @param anImage An image, preferably an animated GIF with transparency,
+ * that will slide along the length of the component.
+ */
+ public ComponentHighlighter(JComponent aComponent, Image anImage) {
+ init(aComponent, anImage);
+ }
+
+ protected void init(JComponent aComponent, Image anImage) {
+ if ((aComponent == null) || (anImage == null))
+ return;
+
+ component = aComponent;
+ rootPane = SwingUtilities.getRootPane(component);
+ oldGlassPane = rootPane.getGlassPane();
glassPane = new JPanel();
- rootPane.setGlassPane( glassPane );
- glassPane.setVisible( true );
- glassPane.setOpaque( false );
- glassPane.setLayout( null );
-
- ImageIcon icon = new ImageIcon( anImage );
-
- imageLabel = new JLabel();
- imageLabel.setIconTextGap( 0 );
- imageLabel.setIcon( icon );
- imageLabel.setSize( icon.getIconWidth(), icon.getIconHeight() );
- glassPane.add( imageLabel );
-
- Rectangle bounds = component.getBounds();
- if ( component.getParent() instanceof Component )
- {
- bounds = SwingUtilities.convertRectangle( (Container) component.getParent(),
- bounds, rootPane.getContentPane() );
- }
- imageLabel.setLocation(
- bounds.x, bounds.y + bounds.height - imageLabel.getBounds().height );
-
- glassPane.revalidate();
- glassPane.repaint();
-
- component.transferFocus(); // halts a caret, if necessary
-
- timer = new Timer( 80, this );
- timer.setRepeats( true );
- timer.start();
- }
-
- public void actionPerformed( ActionEvent evt )
- {
- Rectangle bounds = imageLabel.getBounds();
- Rectangle target = component.getBounds();
- if ( component.getParent() instanceof Component )
- {
- target = SwingUtilities.convertRectangle( (Container) component.getParent(),
- target, rootPane.getContentPane() );
- }
-
- if ( bounds.x + bounds.width > target.x + target.width )
- { // clean up and end
- timer.stop();
- rootPane.setGlassPane( oldGlassPane );
- component.requestFocus();
- return;
- }
-
- // else, slide to the right and continue
- imageLabel.setLocation(
- bounds.x + Math.max( bounds.width / 12, 1 ), bounds.y );
- imageLabel.repaint();
- }
+ rootPane.setGlassPane(glassPane);
+ glassPane.setVisible(true);
+ glassPane.setOpaque(false);
+ glassPane.setLayout(null);
+
+ ImageIcon icon = new ImageIcon(anImage);
+
+ imageLabel = new JLabel();
+ imageLabel.setIconTextGap(0);
+ imageLabel.setIcon(icon);
+ imageLabel.setSize(icon.getIconWidth(), icon.getIconHeight());
+ glassPane.add(imageLabel);
+
+ Rectangle bounds = component.getBounds();
+ if (component.getParent() instanceof Component) {
+ bounds = SwingUtilities.convertRectangle((Container) component.getParent(), bounds,
+ rootPane.getContentPane());
+ }
+ imageLabel.setLocation(bounds.x, bounds.y + bounds.height - imageLabel.getBounds().height);
+
+ glassPane.revalidate();
+ glassPane.repaint();
+
+ component.transferFocus(); // halts a caret, if necessary
+
+ timer = new Timer(80, this);
+ timer.setRepeats(true);
+ timer.start();
+ }
+
+ public void actionPerformed(ActionEvent evt) {
+ Rectangle bounds = imageLabel.getBounds();
+ Rectangle target = component.getBounds();
+ if (component.getParent() instanceof Component) {
+ target = SwingUtilities.convertRectangle((Container) component.getParent(), target,
+ rootPane.getContentPane());
+ }
+
+ if (bounds.x + bounds.width > target.x + target.width) { // clean up and end
+ timer.stop();
+ rootPane.setGlassPane(oldGlassPane);
+ component.requestFocus();
+ return;
+ }
+
+ // else, slide to the right and continue
+ imageLabel.setLocation(bounds.x + Math.max(bounds.width / 12, 1), bounds.y);
+ imageLabel.repaint();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:51:18 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:18 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:45 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:45 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/GIFEncoder.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/GIFEncoder.java
index 82fd897..9ff7496 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/GIFEncoder.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/GIFEncoder.java
@@ -12,509 +12,445 @@ import java.io.IOException;
import java.io.OutputStream;
/**
- * GIFEncoder is a class which takes an image and saves it to a stream
- * using the GIF file format. A GIFEncoder is constructed with either
- * an AWT Image (which must be fully loaded) or a set of RGB arrays.
- * The image can be written out with a call to <CODE>write</CODE>.<br><br>
+ * GIFEncoder is a class which takes an image and saves it to a stream using the
+ * GIF file format. A GIFEncoder is constructed with either an AWT Image (which
+ * must be fully loaded) or a set of RGB arrays. The image can be written out
+ * with a call to <CODE>write</CODE>.<br>
+ * <br>
*
* Three caveats:
* <UL>
- * <LI>GIFEncoder will convert the image to indexed color upon
- * construction, and this is not fast.
+ * <LI>GIFEncoder will convert the image to indexed color upon construction, and
+ * this is not fast.
*
- * <LI>The image cannot have more than 256 colors, since GIF is an 8
- * bit format.
+ * <LI>The image cannot have more than 256 colors, since GIF is an 8 bit format.
*
- * <LI>Since the image must be completely loaded into memory,
- * there may be problems with large images.
+ * <LI>Since the image must be completely loaded into memory, there may be
+ * problems with large images.
* </UL>
*
- * This implementation is heavily based on code made available by
- * Adam Doppelt, which was based upon gifsave.c, which was written
- * and released by Sverre H. Huseby.
+ * This implementation is heavily based on code made available by Adam Doppelt,
+ * which was based upon gifsave.c, which was written and released by Sverre H.
+ * Huseby.
*
* @author amd@brown.edu
* @author sverrehu@ifi.uio.no
* @author michael@mpowers.net
*/
-public class GIFEncoder
-{
- short width_, height_;
- int numColors_;
- byte pixels_[], colors_[];
-
- ScreenDescriptor sd_;
- ImageDescriptor id_;
-
-/**
- * Construct a GIFEncoder. The constructor will convert the image to
- * an indexed color array. This may take some time. If more than 256
- * colors are encountered, all subsequent colors are mapped to the first
- * color encountered.
- * @param image The image to encode. The image must be completely loaded.
- * @exception AWTException Will be thrown if the pixel grab fails. This
- * can happen if Java runs out of memory.
- * */
- public GIFEncoder(Image image) throws AWTException
- {
- width_ = (short)image.getWidth(null);
- height_ = (short)image.getHeight(null);
-
- int values[] = new int[width_ * height_];
- PixelGrabber grabber = new PixelGrabber(
- image, 0, 0, width_, height_, values, 0, width_);
-
- try
- {
- if(grabber.grabPixels() != true)
- throw new AWTException("Grabber returned false: " +
- grabber.status());
- }
- catch (InterruptedException e)
- {
- }
-
- byte r[][] = new byte[width_][height_];
- byte g[][] = new byte[width_][height_];
- byte b[][] = new byte[width_][height_];
- int index = 0;
- for (int y = 0; y < height_; ++y)
- {
- for (int x = 0; x < width_; ++x)
- {
- r[x][y] = (byte)((values[index] >> 16) & 0xFF);
- g[x][y] = (byte)((values[index] >> 8) & 0xFF);
- b[x][y] = (byte)((values[index]) & 0xFF);
- ++index;
- }
- }
- toIndexedColor(r, g, b);
- }
-
-/**
- * Construct a GIFEncoder. The constructor will convert the image to
- * an indexed color array. This may take some time. <br><br>
- * Each array stores intensity values for the image. In other words,
- * r[x][y] refers to the red intensity of the pixel at column x, row y.
- * @param r An array containing the red intensity values.
- * @param g An array containing the green intensity values.
- * @param b An array containing the blue intensity values.
- *
- * @exception AWTException Will be thrown if the image contains more than
- * 256 colors.
- * */
- public GIFEncoder(byte r[][], byte g[][], byte b[][]) throws AWTException
- {
- width_ = (short)(r.length);
- height_ = (short)(r[0].length);
-
- toIndexedColor(r, g, b);
- }
-
-/**
- * Writes the image out to a stream in the GIF file format. This will
- * be a single GIF87a image, non-interlaced, with no background color.
- * <B>This may take some time.</B><P>
- *
- * @param output The stream to output to. This should probably be a
- * buffered stream.
- *
- * @exception IOException Will be thrown if a write operation fails.
- * */
- public void write(OutputStream output) throws IOException
- {
- BitUtils.writeString(output, "GIF87a");
- ScreenDescriptor sd = new ScreenDescriptor(width_, height_,
- numColors_);
- sd.write(output);
-
- output.write(colors_, 0, colors_.length);
-
- ImageDescriptor id = new ImageDescriptor(width_, height_, ',');
- id.write(output);
-
- byte codesize = BitUtils.bitsNeeded(numColors_);
- if (codesize == 1)
- ++codesize;
- output.write(codesize);
-
- LZWCompressor.LZWCompress(output, codesize, pixels_);
- output.write(0);
- id = new ImageDescriptor((byte)0, (byte)0, ';');
- id.write(output);
- output.flush();
- }
-
- void toIndexedColor(byte r[][], byte g[][],
- byte b[][]) throws AWTException
- {
- pixels_ = new byte[width_ * height_];
- colors_ = new byte[256 * 3];
- int colornum = 0;
- for (int x = 0; x < width_; ++x)
- {
- for (int y = 0; y < height_; ++y)
- {
- int search;
- for (search = 0; search < colornum; ++search)
- if (colors_[search * 3] == r[x][y] &&
- colors_[search * 3 + 1] == g[x][y] &&
- colors_[search * 3 + 2] == b[x][y])
- break;
-
- if (search > 255)
- search = 0;
- //throw new AWTException("Too many colors.");
-
- pixels_[y * width_ + x] = (byte)search;
-
- if (search == colornum) {
- colors_[search * 3] = r[x][y];
- colors_[search * 3 + 1] = g[x][y];
- colors_[search * 3 + 2] = b[x][y];
- ++colornum;
- }
- }
- }
-
- numColors_ = 1 << BitUtils.bitsNeeded(colornum);
- byte copy[] = new byte[numColors_ * 3];
- System.arraycopy(colors_, 0, copy, 0, numColors_ * 3);
- colors_ = copy;
- }
+public class GIFEncoder {
+ short width_, height_;
+ int numColors_;
+ byte pixels_[], colors_[];
+
+ ScreenDescriptor sd_;
+ ImageDescriptor id_;
+
+ /**
+ * Construct a GIFEncoder. The constructor will convert the image to an indexed
+ * color array. This may take some time. If more than 256 colors are
+ * encountered, all subsequent colors are mapped to the first color encountered.
+ *
+ * @param image The image to encode. The image must be completely loaded.
+ * @exception AWTException Will be thrown if the pixel grab fails. This can
+ * happen if Java runs out of memory.
+ */
+ public GIFEncoder(Image image) throws AWTException {
+ width_ = (short) image.getWidth(null);
+ height_ = (short) image.getHeight(null);
+
+ int values[] = new int[width_ * height_];
+ PixelGrabber grabber = new PixelGrabber(image, 0, 0, width_, height_, values, 0, width_);
+
+ try {
+ if (grabber.grabPixels() != true)
+ throw new AWTException("Grabber returned false: " + grabber.status());
+ } catch (InterruptedException e) {
+ }
+
+ byte r[][] = new byte[width_][height_];
+ byte g[][] = new byte[width_][height_];
+ byte b[][] = new byte[width_][height_];
+ int index = 0;
+ for (int y = 0; y < height_; ++y) {
+ for (int x = 0; x < width_; ++x) {
+ r[x][y] = (byte) ((values[index] >> 16) & 0xFF);
+ g[x][y] = (byte) ((values[index] >> 8) & 0xFF);
+ b[x][y] = (byte) ((values[index]) & 0xFF);
+ ++index;
+ }
+ }
+ toIndexedColor(r, g, b);
+ }
+
+ /**
+ * Construct a GIFEncoder. The constructor will convert the image to an indexed
+ * color array. This may take some time. <br>
+ * <br>
+ * Each array stores intensity values for the image. In other words, r[x][y]
+ * refers to the red intensity of the pixel at column x, row y.
+ *
+ * @param r An array containing the red intensity values.
+ * @param g An array containing the green intensity values.
+ * @param b An array containing the blue intensity values.
+ *
+ * @exception AWTException Will be thrown if the image contains more than 256
+ * colors.
+ */
+ public GIFEncoder(byte r[][], byte g[][], byte b[][]) throws AWTException {
+ width_ = (short) (r.length);
+ height_ = (short) (r[0].length);
+
+ toIndexedColor(r, g, b);
+ }
+
+ /**
+ * Writes the image out to a stream in the GIF file format. This will be a
+ * single GIF87a image, non-interlaced, with no background color. <B>This may
+ * take some time.</B>
+ * <P>
+ *
+ * @param output The stream to output to. This should probably be a buffered
+ * stream.
+ *
+ * @exception IOException Will be thrown if a write operation fails.
+ */
+ public void write(OutputStream output) throws IOException {
+ BitUtils.writeString(output, "GIF87a");
+ ScreenDescriptor sd = new ScreenDescriptor(width_, height_, numColors_);
+ sd.write(output);
+
+ output.write(colors_, 0, colors_.length);
+
+ ImageDescriptor id = new ImageDescriptor(width_, height_, ',');
+ id.write(output);
+
+ byte codesize = BitUtils.bitsNeeded(numColors_);
+ if (codesize == 1)
+ ++codesize;
+ output.write(codesize);
+
+ LZWCompressor.LZWCompress(output, codesize, pixels_);
+ output.write(0);
+ id = new ImageDescriptor((byte) 0, (byte) 0, ';');
+ id.write(output);
+ output.flush();
+ }
+
+ void toIndexedColor(byte r[][], byte g[][], byte b[][]) throws AWTException {
+ pixels_ = new byte[width_ * height_];
+ colors_ = new byte[256 * 3];
+ int colornum = 0;
+ for (int x = 0; x < width_; ++x) {
+ for (int y = 0; y < height_; ++y) {
+ int search;
+ for (search = 0; search < colornum; ++search)
+ if (colors_[search * 3] == r[x][y] && colors_[search * 3 + 1] == g[x][y]
+ && colors_[search * 3 + 2] == b[x][y])
+ break;
+
+ if (search > 255)
+ search = 0;
+ // throw new AWTException("Too many colors.");
+
+ pixels_[y * width_ + x] = (byte) search;
+
+ if (search == colornum) {
+ colors_[search * 3] = r[x][y];
+ colors_[search * 3 + 1] = g[x][y];
+ colors_[search * 3 + 2] = b[x][y];
+ ++colornum;
+ }
+ }
+ }
+
+ numColors_ = 1 << BitUtils.bitsNeeded(colornum);
+ byte copy[] = new byte[numColors_ * 3];
+ System.arraycopy(colors_, 0, copy, 0, numColors_ * 3);
+ colors_ = copy;
+ }
}
-class BitFile
-{
- OutputStream output_;
- byte buffer_[];
- int index_, bitsLeft_;
-
- public BitFile(OutputStream output)
- {
- output_ = output;
- buffer_ = new byte[256];
- index_ = 0;
- bitsLeft_ = 8;
- }
-
- public void flush() throws IOException
- {
- int numBytes = index_ + (bitsLeft_ == 8 ? 0 : 1);
- if (numBytes > 0)
- {
- output_.write(numBytes);
- output_.write(buffer_, 0, numBytes);
- buffer_[0] = 0;
- index_ = 0;
- bitsLeft_ = 8;
- }
- }
-
- public void writeBits(int bits, int numbits) throws IOException {
- int bitsWritten = 0;
- int numBytes = 255;
- do
- {
- if ((index_ == 254 && bitsLeft_ == 0) || index_ > 254)
- {
- output_.write(numBytes);
- output_.write(buffer_, 0, numBytes);
-
- buffer_[0] = 0;
- index_ = 0;
- bitsLeft_ = 8;
- }
-
- if (numbits <= bitsLeft_)
- {
- buffer_[index_] |= (bits & ((1 << numbits) - 1)) <<
- (8 - bitsLeft_);
- bitsWritten += numbits;
- bitsLeft_ -= numbits;
- numbits = 0;
- }
- else
- {
- buffer_[index_] |= (bits & ((1 << bitsLeft_) - 1)) <<
- (8 - bitsLeft_);
- bitsWritten += bitsLeft_;
- bits >>= bitsLeft_;
- numbits -= bitsLeft_;
- buffer_[++index_] = 0;
- bitsLeft_ = 8;
- }
-
- }
- while (numbits != 0);
- }
+class BitFile {
+ OutputStream output_;
+ byte buffer_[];
+ int index_, bitsLeft_;
+
+ public BitFile(OutputStream output) {
+ output_ = output;
+ buffer_ = new byte[256];
+ index_ = 0;
+ bitsLeft_ = 8;
+ }
+
+ public void flush() throws IOException {
+ int numBytes = index_ + (bitsLeft_ == 8 ? 0 : 1);
+ if (numBytes > 0) {
+ output_.write(numBytes);
+ output_.write(buffer_, 0, numBytes);
+ buffer_[0] = 0;
+ index_ = 0;
+ bitsLeft_ = 8;
+ }
+ }
+
+ public void writeBits(int bits, int numbits) throws IOException {
+ int bitsWritten = 0;
+ int numBytes = 255;
+ do {
+ if ((index_ == 254 && bitsLeft_ == 0) || index_ > 254) {
+ output_.write(numBytes);
+ output_.write(buffer_, 0, numBytes);
+
+ buffer_[0] = 0;
+ index_ = 0;
+ bitsLeft_ = 8;
+ }
+
+ if (numbits <= bitsLeft_) {
+ buffer_[index_] |= (bits & ((1 << numbits) - 1)) << (8 - bitsLeft_);
+ bitsWritten += numbits;
+ bitsLeft_ -= numbits;
+ numbits = 0;
+ } else {
+ buffer_[index_] |= (bits & ((1 << bitsLeft_) - 1)) << (8 - bitsLeft_);
+ bitsWritten += bitsLeft_;
+ bits >>= bitsLeft_;
+ numbits -= bitsLeft_;
+ buffer_[++index_] = 0;
+ bitsLeft_ = 8;
+ }
+
+ } while (numbits != 0);
+ }
}
-class LZWStringTable
-{
- private final static int RES_CODES = 2;
- private final static short HASH_FREE = (short)0xFFFF;
- private final static short NEXT_FIRST = (short)0xFFFF;
- private final static int MAXBITS = 12;
- private final static int MAXSTR = (1 << MAXBITS);
- private final static short HASHSIZE = 9973;
- private final static short HASHSTEP = 2039;
-
- byte strChr_[];
- short strNxt_[];
- short strHsh_[];
- short numStrings_;
-
- public LZWStringTable()
- {
- strChr_ = new byte[MAXSTR];
- strNxt_ = new short[MAXSTR];
- strHsh_ = new short[HASHSIZE];
- }
-
- public int addCharString(short index, byte b)
- {
- int hshidx;
-
- if (numStrings_ >= MAXSTR)
- return 0xFFFF;
-
- hshidx = Hash(index, b);
- while (strHsh_[hshidx] != HASH_FREE)
- hshidx = (hshidx + HASHSTEP) % HASHSIZE;
-
- strHsh_[hshidx] = numStrings_;
- strChr_[numStrings_] = b;
- strNxt_[numStrings_] = (index != HASH_FREE) ? index : NEXT_FIRST;
-
- return numStrings_++;
- }
-
- public short findCharString(short index, byte b)
- {
- int hshidx, nxtidx;
-
- if (index == HASH_FREE)
- return b;
-
- hshidx = Hash(index, b);
- while ((nxtidx = strHsh_[hshidx]) != HASH_FREE)
- {
- if (strNxt_[nxtidx] == index && strChr_[nxtidx] == b)
- return (short)nxtidx;
- hshidx = (hshidx + HASHSTEP) % HASHSIZE;
- }
-
- return (short)0xFFFF;
- }
-
- public void clearTable(int codesize)
- {
- numStrings_ = 0;
-
- for (int q = 0; q < HASHSIZE; q++)
- {
- strHsh_[q] = HASH_FREE;
- }
-
- int w = (1 << codesize) + RES_CODES;
- for (int q = 0; q < w; q++)
- {
- addCharString((short)0xFFFF, (byte)q);
- }
- }
-
- static public int Hash(short index, byte lastbyte)
- {
- return ((int)((short)(lastbyte << 8) ^ index) & 0xFFFF) % HASHSIZE;
- }
+class LZWStringTable {
+ private final static int RES_CODES = 2;
+ private final static short HASH_FREE = (short) 0xFFFF;
+ private final static short NEXT_FIRST = (short) 0xFFFF;
+ private final static int MAXBITS = 12;
+ private final static int MAXSTR = (1 << MAXBITS);
+ private final static short HASHSIZE = 9973;
+ private final static short HASHSTEP = 2039;
+
+ byte strChr_[];
+ short strNxt_[];
+ short strHsh_[];
+ short numStrings_;
+
+ public LZWStringTable() {
+ strChr_ = new byte[MAXSTR];
+ strNxt_ = new short[MAXSTR];
+ strHsh_ = new short[HASHSIZE];
+ }
+
+ public int addCharString(short index, byte b) {
+ int hshidx;
+
+ if (numStrings_ >= MAXSTR)
+ return 0xFFFF;
+
+ hshidx = Hash(index, b);
+ while (strHsh_[hshidx] != HASH_FREE)
+ hshidx = (hshidx + HASHSTEP) % HASHSIZE;
+
+ strHsh_[hshidx] = numStrings_;
+ strChr_[numStrings_] = b;
+ strNxt_[numStrings_] = (index != HASH_FREE) ? index : NEXT_FIRST;
+
+ return numStrings_++;
+ }
+
+ public short findCharString(short index, byte b) {
+ int hshidx, nxtidx;
+
+ if (index == HASH_FREE)
+ return b;
+
+ hshidx = Hash(index, b);
+ while ((nxtidx = strHsh_[hshidx]) != HASH_FREE) {
+ if (strNxt_[nxtidx] == index && strChr_[nxtidx] == b)
+ return (short) nxtidx;
+ hshidx = (hshidx + HASHSTEP) % HASHSIZE;
+ }
+
+ return (short) 0xFFFF;
+ }
+
+ public void clearTable(int codesize) {
+ numStrings_ = 0;
+
+ for (int q = 0; q < HASHSIZE; q++) {
+ strHsh_[q] = HASH_FREE;
+ }
+
+ int w = (1 << codesize) + RES_CODES;
+ for (int q = 0; q < w; q++) {
+ addCharString((short) 0xFFFF, (byte) q);
+ }
+ }
+
+ static public int Hash(short index, byte lastbyte) {
+ return ((int) ((short) (lastbyte << 8) ^ index) & 0xFFFF) % HASHSIZE;
+ }
}
class LZWCompressor {
- public static void LZWCompress(OutputStream output, int codesize,
- byte toCompress[]) throws IOException
- {
- byte c;
- short index;
- int clearcode, endofinfo, numbits, limit, errcode;
- short prefix = (short)0xFFFF;
-
- BitFile bitFile = new BitFile(output);
- LZWStringTable strings = new LZWStringTable();
-
- clearcode = 1 << codesize;
- endofinfo = clearcode + 1;
-
- numbits = codesize + 1;
- limit = (1 << numbits) - 1;
- strings.clearTable(codesize);
- bitFile.writeBits(clearcode, numbits);
-
- for (int loop = 0; loop < toCompress.length; ++loop)
- {
- c = toCompress[loop];
- if ((index = strings.findCharString(prefix, c)) != -1)
- {
- prefix = index;
- }
- else
- {
- bitFile.writeBits(prefix, numbits);
- if (strings.addCharString(prefix, c) > limit) {
- if (++numbits > 12) {
- bitFile.writeBits(clearcode, numbits - 1);
- strings.clearTable(codesize);
- numbits = codesize + 1;
- }
- limit = (1 << numbits) - 1;
- }
-
- prefix = (short)((short)c & 0xFF);
- }
- }
-
- if (prefix != -1)
- bitFile.writeBits(prefix, numbits);
-
- bitFile.writeBits(endofinfo, numbits);
- bitFile.flush();
- }
+ public static void LZWCompress(OutputStream output, int codesize, byte toCompress[]) throws IOException {
+ byte c;
+ short index;
+ int clearcode, endofinfo, numbits, limit, errcode;
+ short prefix = (short) 0xFFFF;
+
+ BitFile bitFile = new BitFile(output);
+ LZWStringTable strings = new LZWStringTable();
+
+ clearcode = 1 << codesize;
+ endofinfo = clearcode + 1;
+
+ numbits = codesize + 1;
+ limit = (1 << numbits) - 1;
+ strings.clearTable(codesize);
+ bitFile.writeBits(clearcode, numbits);
+
+ for (int loop = 0; loop < toCompress.length; ++loop) {
+ c = toCompress[loop];
+ if ((index = strings.findCharString(prefix, c)) != -1) {
+ prefix = index;
+ } else {
+ bitFile.writeBits(prefix, numbits);
+ if (strings.addCharString(prefix, c) > limit) {
+ if (++numbits > 12) {
+ bitFile.writeBits(clearcode, numbits - 1);
+ strings.clearTable(codesize);
+ numbits = codesize + 1;
+ }
+ limit = (1 << numbits) - 1;
+ }
+
+ prefix = (short) ((short) c & 0xFF);
+ }
+ }
+
+ if (prefix != -1)
+ bitFile.writeBits(prefix, numbits);
+
+ bitFile.writeBits(endofinfo, numbits);
+ bitFile.flush();
+ }
}
-class ScreenDescriptor
-{
- public short localScreenWidth_, localScreenHeight_;
- private byte byte_;
- public byte backgroundColorIndex_, pixelAspectRatio_;
-
- public ScreenDescriptor(short width, short height, int numColors)
- {
- localScreenWidth_ = width;
- localScreenHeight_ = height;
- setGlobalColorTableSize((byte)(BitUtils.bitsNeeded(numColors) - 1));
- setGlobalColorTableFlag((byte)1);
- setSortFlag((byte)0);
- setColorResolution((byte)7);
- backgroundColorIndex_ = 0;
- pixelAspectRatio_ = 0;
- }
-
- public void write(OutputStream output) throws IOException
- {
- BitUtils.writeWord(output, localScreenWidth_);
- BitUtils.writeWord(output, localScreenHeight_);
- output.write(byte_);
- output.write(backgroundColorIndex_);
- output.write(pixelAspectRatio_);
- }
-
- public void setGlobalColorTableSize(byte num)
- {
- byte_ |= (num & 7);
- }
-
- public void setSortFlag(byte num)
- {
- byte_ |= (num & 1) << 3;
- }
-
- public void setColorResolution(byte num)
- {
- byte_ |= (num & 7) << 4;
- }
-
- public void setGlobalColorTableFlag(byte num)
- {
- byte_ |= (num & 1) << 7;
- }
+class ScreenDescriptor {
+ public short localScreenWidth_, localScreenHeight_;
+ private byte byte_;
+ public byte backgroundColorIndex_, pixelAspectRatio_;
+
+ public ScreenDescriptor(short width, short height, int numColors) {
+ localScreenWidth_ = width;
+ localScreenHeight_ = height;
+ setGlobalColorTableSize((byte) (BitUtils.bitsNeeded(numColors) - 1));
+ setGlobalColorTableFlag((byte) 1);
+ setSortFlag((byte) 0);
+ setColorResolution((byte) 7);
+ backgroundColorIndex_ = 0;
+ pixelAspectRatio_ = 0;
+ }
+
+ public void write(OutputStream output) throws IOException {
+ BitUtils.writeWord(output, localScreenWidth_);
+ BitUtils.writeWord(output, localScreenHeight_);
+ output.write(byte_);
+ output.write(backgroundColorIndex_);
+ output.write(pixelAspectRatio_);
+ }
+
+ public void setGlobalColorTableSize(byte num) {
+ byte_ |= (num & 7);
+ }
+
+ public void setSortFlag(byte num) {
+ byte_ |= (num & 1) << 3;
+ }
+
+ public void setColorResolution(byte num) {
+ byte_ |= (num & 7) << 4;
+ }
+
+ public void setGlobalColorTableFlag(byte num) {
+ byte_ |= (num & 1) << 7;
+ }
}
-class ImageDescriptor
-{
- public byte separator_;
- public short leftPosition_, topPosition_, width_, height_;
- private byte byte_;
-
- public ImageDescriptor(short width, short height, char separator)
- {
- separator_ = (byte)separator;
- leftPosition_ = 0;
- topPosition_ = 0;
- width_ = width;
- height_ = height;
- setLocalColorTableSize((byte)0);
- setReserved((byte)0);
- setSortFlag((byte)0);
- setInterlaceFlag((byte)0);
- setLocalColorTableFlag((byte)0);
- }
-
- public void write(OutputStream output) throws IOException
- {
- output.write(separator_);
- BitUtils.writeWord(output, leftPosition_);
- BitUtils.writeWord(output, topPosition_);
- BitUtils.writeWord(output, width_);
- BitUtils.writeWord(output, height_);
- output.write(byte_);
- }
-
- public void setLocalColorTableSize(byte num)
- {
- byte_ |= (num & 7);
- }
-
- public void setReserved(byte num)
- {
- byte_ |= (num & 3) << 3;
- }
-
- public void setSortFlag(byte num)
- {
- byte_ |= (num & 1) << 5;
- }
-
- public void setInterlaceFlag(byte num)
- {
- byte_ |= (num & 1) << 6;
- }
-
- public void setLocalColorTableFlag(byte num)
- {
- byte_ |= (num & 1) << 7;
- }
+class ImageDescriptor {
+ public byte separator_;
+ public short leftPosition_, topPosition_, width_, height_;
+ private byte byte_;
+
+ public ImageDescriptor(short width, short height, char separator) {
+ separator_ = (byte) separator;
+ leftPosition_ = 0;
+ topPosition_ = 0;
+ width_ = width;
+ height_ = height;
+ setLocalColorTableSize((byte) 0);
+ setReserved((byte) 0);
+ setSortFlag((byte) 0);
+ setInterlaceFlag((byte) 0);
+ setLocalColorTableFlag((byte) 0);
+ }
+
+ public void write(OutputStream output) throws IOException {
+ output.write(separator_);
+ BitUtils.writeWord(output, leftPosition_);
+ BitUtils.writeWord(output, topPosition_);
+ BitUtils.writeWord(output, width_);
+ BitUtils.writeWord(output, height_);
+ output.write(byte_);
+ }
+
+ public void setLocalColorTableSize(byte num) {
+ byte_ |= (num & 7);
+ }
+
+ public void setReserved(byte num) {
+ byte_ |= (num & 3) << 3;
+ }
+
+ public void setSortFlag(byte num) {
+ byte_ |= (num & 1) << 5;
+ }
+
+ public void setInterlaceFlag(byte num) {
+ byte_ |= (num & 1) << 6;
+ }
+
+ public void setLocalColorTableFlag(byte num) {
+ byte_ |= (num & 1) << 7;
+ }
}
-class BitUtils
-{
- public static byte bitsNeeded(int n)
- {
- byte ret = 1;
-
- if (n-- == 0)
- return 0;
-
- while ((n >>= 1) != 0)
- ++ret;
-
- return ret;
- }
-
- public static void writeWord(OutputStream output,
- short w) throws IOException
- {
- output.write(w & 0xFF);
- output.write((w >> 8) & 0xFF);
- }
-
- static void writeString(OutputStream output,
- String string) throws IOException
- {
- for (int loop = 0; loop < string.length(); ++loop)
- output.write((byte)(string.charAt(loop)));
- }
-}
+class BitUtils {
+ public static byte bitsNeeded(int n) {
+ byte ret = 1;
+ if (n-- == 0)
+ return 0;
+ while ((n >>= 1) != 0)
+ ++ret;
+
+ return ret;
+ }
+
+ public static void writeWord(OutputStream output, short w) throws IOException {
+ output.write(w & 0xFF);
+ output.write((w >> 8) & 0xFF);
+ }
+
+ static void writeString(OutputStream output, String string) throws IOException {
+ for (int loop = 0; loop < string.length(); ++loop)
+ output.write((byte) (string.charAt(loop)));
+ }
+}
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ObjectInspector.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ObjectInspector.java
index 6c8d7ee..ad94ddd 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ObjectInspector.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/ObjectInspector.java
@@ -44,183 +44,165 @@ import net.wotonomy.ui.swing.components.PropertyEditorTable;
import net.wotonomy.ui.swing.components.PropertyEditorTableModel;
/**
-* The ObjectInspector displays a JFrame containing
-* a PropertyEditorTable that displays an object. <br><br>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
+ * The ObjectInspector displays a JFrame containing a PropertyEditorTable that
+ * displays an object. <br>
+ * <br>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
-public class ObjectInspector implements ActionListener, MouseListener
-{
- protected JTable table = null;
+public class ObjectInspector implements ActionListener, MouseListener {
+ protected JTable table = null;
- // key command to copy contents to clipboard
- static public final String COPY = "COPY";
+ // key command to copy contents to clipboard
+ static public final String COPY = "COPY";
/**
- * Displays the specified object in a frame.
- */
- public ObjectInspector( Object anObject )
- {
- initLayout( anObject );
- }
-
- protected void initLayout( Object aTargetObject )
- {
- PropertyEditorTableModel model =
- new PropertyEditorTableModel();
- model.setObject( aTargetObject );
- table = new PropertyEditorTable()
- {
- public void methodInvoked( Object anObject, Method aMethod, Object aResult )
- {
- if
- ( ( aResult == null )
- || ( aResult instanceof Number )
- || ( aResult instanceof Boolean )
- || ( aResult instanceof String ) )
- {
- System.out.println( aMethod.getName() + ": " + aResult );
- }
- else
- {
- new ObjectInspector( aResult );
+ * Displays the specified object in a frame.
+ */
+ public ObjectInspector(Object anObject) {
+ initLayout(anObject);
+ }
+
+ protected void initLayout(Object aTargetObject) {
+ PropertyEditorTableModel model = new PropertyEditorTableModel();
+ model.setObject(aTargetObject);
+ table = new PropertyEditorTable() {
+ public void methodInvoked(Object anObject, Method aMethod, Object aResult) {
+ if ((aResult == null) || (aResult instanceof Number) || (aResult instanceof Boolean)
+ || (aResult instanceof String)) {
+ System.out.println(aMethod.getName() + ": " + aResult);
+ } else {
+ new ObjectInspector(aResult);
}
}
};
- table.setModel( model );
- table.addMouseListener( this ); // listen for double-clicks
-
- // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
- table.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
- table.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_X,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
-
- JPanel panel = new JPanel();
- panel.setBorder( new EmptyBorder( new Insets( 10, 10, 10, 10 ) ) );
- panel.setLayout( new BorderLayout( 10, 10 ) );
-
- JScrollPane scrollPane = new JScrollPane( table );
- scrollPane.setPreferredSize( new Dimension( 325, 350 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
-
- JFrame window = new JFrame();
- window.setTitle( aTargetObject.getClass().getName() );
- window.getContentPane().add( panel );
-
- window.pack();
- WindowUtilities.cascade( window );
- window.show();
- }
-
- // interface MouseListener
-
- /**
- * Double click to call invokeFileFromString.
- */
-
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.getClickCount() > 1 )
- {
- int row = table.rowAtPoint( e.getPoint() );
- int col = table.columnAtPoint( e.getPoint() );
-
- if ( ( row == -1 ) || ( col != 0 ) ) return;
-
- /* do something here */
- }
- }
- }
-
- public void mouseReleased(MouseEvent e) {}
- public void mousePressed(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {}
-
-
- // interface ActionEventListener - for listening to key commands
-
- public void actionPerformed(ActionEvent evt)
- {
- if ( COPY.equals( evt.getActionCommand() ) )
- {
- copyToClipboard();
- return;
- }
- }
+ table.setModel(model);
+ table.addMouseListener(this); // listen for double-clicks
+
+ // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
+ table.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ table.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+
+ JPanel panel = new JPanel();
+ panel.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
+ panel.setLayout(new BorderLayout(10, 10));
+
+ JScrollPane scrollPane = new JScrollPane(table);
+ scrollPane.setPreferredSize(new Dimension(325, 350));
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+ JFrame window = new JFrame();
+ window.setTitle(aTargetObject.getClass().getName());
+ window.getContentPane().add(panel);
+
+ window.pack();
+ WindowUtilities.cascade(window);
+ window.show();
+ }
+
+ // interface MouseListener
-/**
-* Copies the contents of the table to the clipboard as a tab-delimited string.
-*/
- public void copyToClipboard()
- {
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Clipboard clipboard = toolkit.getSystemClipboard();
- StringSelection selection =
- new StringSelection( getTabDelimitedString() );
- clipboard.setContents( selection, selection );
- }
-
/**
- * Converts the contents of the table to a tab-delimited string.
- * @return A String containing the text contents of the table.
- */
- public String getTabDelimitedString()
- {
- StringBuffer result = new StringBuffer(64);
-
- TableModel model = table.getModel();
- int cols = model.getColumnCount();
- int rows = model.getRowCount();
-
- Object o = null;
- for ( int y = 0; y < rows; y++ )
- {
- for ( int x = 0; x < cols; x++ )
- {
- o = model.getValueAt( y, x );
- if ( o == null ) o = "";
- result.append( o );
- result.append( '\t' );
- }
- result.append( '\n' );
- }
-
- return result.toString();
- }
+ * Double click to call invokeFileFromString.
+ */
+
+ public void mouseClicked(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.getClickCount() > 1) {
+ int row = table.rowAtPoint(e.getPoint());
+ int col = table.columnAtPoint(e.getPoint());
+
+ if ((row == -1) || (col != 0))
+ return;
+
+ /* do something here */
+ }
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ }
+
+ public void mousePressed(MouseEvent e) {
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ public void mouseExited(MouseEvent e) {
+ }
+
+ // interface ActionEventListener - for listening to key commands
+
+ public void actionPerformed(ActionEvent evt) {
+ if (COPY.equals(evt.getActionCommand())) {
+ copyToClipboard();
+ return;
+ }
+ }
+
+ /**
+ * Copies the contents of the table to the clipboard as a tab-delimited string.
+ */
+ public void copyToClipboard() {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Clipboard clipboard = toolkit.getSystemClipboard();
+ StringSelection selection = new StringSelection(getTabDelimitedString());
+ clipboard.setContents(selection, selection);
+ }
+
+ /**
+ * Converts the contents of the table to a tab-delimited string.
+ *
+ * @return A String containing the text contents of the table.
+ */
+ public String getTabDelimitedString() {
+ StringBuffer result = new StringBuffer(64);
+
+ TableModel model = table.getModel();
+ int cols = model.getColumnCount();
+ int rows = model.getRowCount();
+
+ Object o = null;
+ for (int y = 0; y < rows; y++) {
+ for (int x = 0; x < cols; x++) {
+ o = model.getValueAt(y, x);
+ if (o == null)
+ o = "";
+ result.append(o);
+ result.append('\t');
+ }
+ result.append('\n');
+ }
+
+ return result.toString();
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2002/11/16 16:33:31 mpowers
- * Now using platform-specific accelerator key for shortcuts.
+ * Revision 1.2 2002/11/16 16:33:31 mpowers Now using platform-specific
+ * accelerator key for shortcuts.
*
- * Revision 1.1.1.1 2000/12/21 15:51:27 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:27 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:45 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:45 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/PositionComparator.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/PositionComparator.java
index f5fe3e4..7f2adb8 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/PositionComparator.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/PositionComparator.java
@@ -27,63 +27,55 @@ import java.util.Comparator;
import javax.swing.SwingUtilities;
/**
-* A Comparator that will sort components in a common container
-* based first on their y-coordinate and then on their x-coordinate,
-* producing a list sorted from top to bottom and left to right.
-* If all components are not in the same container, the resulting
-* sort is undefined.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class PositionComparator implements Comparator, Serializable
-{
- private Container rootContainer;
- private transient Component c1, c2;
- private transient Point p1, p2;
+ * A Comparator that will sort components in a common container based first on
+ * their y-coordinate and then on their x-coordinate, producing a list sorted
+ * from top to bottom and left to right. If all components are not in the same
+ * container, the resulting sort is undefined.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class PositionComparator implements Comparator, Serializable {
+ private Container rootContainer;
+ private transient Component c1, c2;
+ private transient Point p1, p2;
-/**
-* Standard constructor to configure the comparator.
-* @param aContainer The common container for all the objects to be compared.
-*/
- public PositionComparator( Container aContainer )
- {
- rootContainer = aContainer;
- }
+ /**
+ * Standard constructor to configure the comparator.
+ *
+ * @param aContainer The common container for all the objects to be compared.
+ */
+ public PositionComparator(Container aContainer) {
+ rootContainer = aContainer;
+ }
- // interface Comparable
+ // interface Comparable
- public int compare(Object o1, Object o2)
- {
- c1 = (Component) o1;
- c2 = (Component) o2;
+ public int compare(Object o1, Object o2) {
+ c1 = (Component) o1;
+ c2 = (Component) o2;
- p1 = SwingUtilities.convertPoint( c1.getParent(), c1.getLocation(), rootContainer );
- p2 = SwingUtilities.convertPoint( c2.getParent(), c2.getLocation(), rootContainer );
+ p1 = SwingUtilities.convertPoint(c1.getParent(), c1.getLocation(), rootContainer);
+ p2 = SwingUtilities.convertPoint(c2.getParent(), c2.getLocation(), rootContainer);
- if ( p1.y != p2.y )
- {
- return p1.y - p2.y;
- }
- return p1.x - p2.x;
- }
+ if (p1.y != p2.y) {
+ return p1.y - p2.y;
+ }
+ return p1.x - p2.x;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:51:27 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:27 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:45 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:45 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/StackTraceInspector.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/StackTraceInspector.java
index 7e61411..ae4bb2d 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/StackTraceInspector.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/StackTraceInspector.java
@@ -50,408 +50,364 @@ import javax.swing.table.TableModel;
import net.wotonomy.ui.swing.components.MultiLineLabel;
/**
-* The StackTraceInspector displays a JFrame containing
-* stack trace information for a Throwable. <br><br>
-*
-* There are also a few static methods for obtaining
-* information about the current stack, which is useful
-* for determining who's calling you at runtime.
-*
-* @author michael@mpowers.net
-* @version $Revision: 904 $
-*/
+ * The StackTraceInspector displays a JFrame containing stack trace information
+ * for a Throwable. <br>
+ * <br>
+ *
+ * There are also a few static methods for obtaining information about the
+ * current stack, which is useful for determining who's calling you at runtime.
+ *
+ * @author michael@mpowers.net
+ * @version $Revision: 904 $
+ */
-public class StackTraceInspector
- implements TableModel, MouseListener, ActionListener
-{
- protected JTable table = null;
- protected List tableModelListeners = null;
- protected List methodNames = new ArrayList();
+public class StackTraceInspector implements TableModel, MouseListener, ActionListener {
+ protected JTable table = null;
+ protected List tableModelListeners = null;
+ protected List methodNames = new ArrayList();
+
+ // key command to copy contents to clipboard
+ static public final String COPY = "COPY";
+
+ /**
+ * Displays the current stack trace at the time of instantiation in a table on a
+ * frame.
+ */
+ public StackTraceInspector() {
+ initLayout(parseStackTrace(new RuntimeException()), null);
+ }
+
+ /**
+ * Displays the current stack trace at the time of instantiation in a table on a
+ * frame annotated with the specified message.
+ */
+ public StackTraceInspector(String aMessage) {
+ initLayout(parseStackTrace(new RuntimeException()), aMessage);
+ }
+
+ /**
+ * Displays the stack trace for the given throwable in a table on a frame.
+ *
+ * @param aThrowable A Throwable whose stack will be examined.
+ */
+ public StackTraceInspector(Throwable aThrowable) {
+ initLayout(parseStackTrace(aThrowable), aThrowable.getClass() + ": " + aThrowable.getMessage());
+ }
+
+ /**
+ * Simply displays the list items in a dialog. Presumably (but not necessarily)
+ * called from the other constructors. (I guess if you just want a frame with
+ * strings in table, you can call this.)
+ *
+ * @param aStringList A List containing Strings.
+ */
+ public StackTraceInspector(List aStringList) {
+ initLayout(aStringList, null);
+ }
+
+ protected void initLayout(List items, String message) {
+ methodNames = new ArrayList(items);
+ table = new JTable(this); // this class is the table model
+ table.addMouseListener(this); // listen for double-clicks
+
+ // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
+ table.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ table.registerKeyboardAction(this, COPY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+
+ JPanel panel = new JPanel();
+ panel.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
+ panel.setLayout(new BorderLayout(10, 10));
+
+ if (message != null) {
+ panel.add(new MultiLineLabel(message), BorderLayout.NORTH);
+ }
- // key command to copy contents to clipboard
- static public final String COPY = "COPY";
+ JScrollPane scrollPane = new JScrollPane(table);
+ scrollPane.setPreferredSize(new Dimension(325, 350));
+ panel.add(scrollPane, BorderLayout.CENTER);
-/**
-* Displays the current stack trace at the time
-* of instantiation in a table on a frame.
-*/
- public StackTraceInspector()
- {
- initLayout( parseStackTrace( new RuntimeException() ), null );
- }
+ JFrame window = new JFrame();
+ window.setTitle("Stack Trace Inspector");
+ window.getContentPane().add(panel);
-/**
-* Displays the current stack trace at the time
-* of instantiation in a table on a frame
-* annotated with the specified message.
-*/
- public StackTraceInspector( String aMessage )
- {
- initLayout( parseStackTrace( new RuntimeException() ), aMessage );
- }
+ window.pack();
+ WindowUtilities.cascade(window);
+ window.show();
+ }
-/**
-* Displays the stack trace for the given throwable
-* in a table on a frame.
-* @param aThrowable A Throwable whose stack will be examined.
-*/
- public StackTraceInspector( Throwable aThrowable )
- {
- initLayout( parseStackTrace( aThrowable ),
- aThrowable.getClass() + ": " + aThrowable.getMessage() );
- }
+ // interface TableModel
-/**
-* Simply displays the list items in a dialog.
-* Presumably (but not necessarily) called from
-* the other constructors. (I guess if you just
-* want a frame with strings in table, you can
-* call this.)
-* @param aStringList A List containing Strings.
-*/
- public StackTraceInspector( List aStringList )
- {
- initLayout( aStringList, null );
- }
-
- protected void initLayout( List items, String message )
- {
- methodNames = new ArrayList( items );
- table = new JTable( this ); // this class is the table model
- table.addMouseListener( this ); // listen for double-clicks
-
- // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X
- table.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
- table.registerKeyboardAction( this, COPY,
- KeyStroke.getKeyStroke( KeyEvent.VK_X,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ),
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
-
- JPanel panel = new JPanel();
- panel.setBorder( new EmptyBorder( new Insets( 10, 10, 10, 10 ) ) );
- panel.setLayout( new BorderLayout( 10, 10 ) );
-
- if ( message != null )
- {
- panel.add( new MultiLineLabel( message ), BorderLayout.NORTH );
+ public int getRowCount() {
+ return methodNames.size();
+ }
+
+ public int getColumnCount() {
+ return 1;
+ }
+
+ public String getColumnName(int columnIndex) {
+ switch (columnIndex) {
+ case 0:
+ return "Methods";
+ case 1:
+ return "Property";
}
+ System.out.println("StackTraceInspector.getColumnName: unknown column: " + columnIndex);
+ return "";
+ }
+
+ public Class getColumnClass(int columnIndex) {
+ switch (columnIndex) {
+ case 0:
+ return String.class;
+ case 1:
+ return String.class;
+ }
+ System.out.println("StackTraceInspector.getColumnClass: unknown column: " + columnIndex);
+ return Object.class;
+ }
- JScrollPane scrollPane = new JScrollPane( table );
- scrollPane.setPreferredSize( new Dimension( 325, 350 ) );
- panel.add( scrollPane, BorderLayout.CENTER );
-
- JFrame window = new JFrame();
- window.setTitle( "Stack Trace Inspector" );
- window.getContentPane().add( panel );
-
- window.pack();
- WindowUtilities.cascade( window );
- window.show();
- }
-
- // interface TableModel
-
- public int getRowCount()
- {
- return methodNames.size();
- }
-
- public int getColumnCount()
- {
- return 1;
- }
-
- public String getColumnName(int columnIndex)
- {
- switch ( columnIndex )
- {
- case 0:
- return "Methods";
- case 1:
- return "Property";
- }
- System.out.println( "StackTraceInspector.getColumnName: unknown column: " + columnIndex );
- return "";
- }
-
- public Class getColumnClass(int columnIndex)
- {
- switch ( columnIndex )
- {
- case 0:
- return String.class;
- case 1:
- return String.class;
- }
- System.out.println( "StackTraceInspector.getColumnClass: unknown column: " + columnIndex );
- return Object.class;
- }
-
- public boolean isCellEditable(int rowIndex,
- int columnIndex)
- {
- return false;
- }
-
- public Object getValueAt(int rowIndex,
- int columnIndex)
- {
- return methodNames.get( rowIndex );
- }
-
- public void setValueAt(Object aValue,
- int rowIndex,
- int columnIndex)
- {
- }
-
- public void addTableModelListener(TableModelListener l)
- {
- if ( tableModelListeners == null )
- {
- tableModelListeners = new ArrayList();
- }
- tableModelListeners.add( l );
- }
-
- public void removeTableModelListener(TableModelListener l)
- {
- if ( tableModelListeners != null )
- {
- tableModelListeners.remove( l );
- }
- }
-
- // interface MouseListener
-
- /**
- * Double click to call invokeFileFromString.
- */
-
- public void mouseClicked(MouseEvent e)
- {
- if ( e.getSource() == table )
- {
- if ( e.getClickCount() > 1 )
- {
- int row = table.rowAtPoint( e.getPoint() );
- int col = table.columnAtPoint( e.getPoint() );
-
- if ( ( row == -1 ) || ( col != 0 ) ) return;
-
- invokeFileFromString( methodNames.get( row ).toString() );
- }
- }
- }
-
- public void mouseReleased(MouseEvent e) {}
- public void mousePressed(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {}
-
-
- // interface ActionEventListener - for listening to key commands
-
- public void actionPerformed(ActionEvent evt)
- {
- if ( COPY.equals( evt.getActionCommand() ) )
- {
- copyToClipboard();
- return;
- }
- }
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return false;
+ }
-/**
-* Copies the contents of the table to the clipboard as a tab-delimited string.
-*/
- public void copyToClipboard()
- {
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Clipboard clipboard = toolkit.getSystemClipboard();
- StringSelection selection =
- new StringSelection( getSelectedStackString() );
- clipboard.setContents( selection, selection );
- }
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ return methodNames.get(rowIndex);
+ }
-/**
-* Converts the selected contents of the table to a string.
-* @return A String containing the text contents of the table.
-*/
- public String getSelectedStackString()
- {
- StringBuffer result = new StringBuffer(64);
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ }
- TableModel model = table.getModel();
+ public void addTableModelListener(TableModelListener l) {
+ if (tableModelListeners == null) {
+ tableModelListeners = new ArrayList();
+ }
+ tableModelListeners.add(l);
+ }
- Object o;
- int[] selectedRows = table.getSelectedRows();
- for ( int i = 0; i < selectedRows.length; i++ )
- {
- o = model.getValueAt( selectedRows[i], 0 );
- if ( o == null ) o = "";
- result.append( o );
- result.append( '\n' );
- }
+ public void removeTableModelListener(TableModelListener l) {
+ if (tableModelListeners != null) {
+ tableModelListeners.remove(l);
+ }
+ }
- return result.toString();
- }
+ // interface MouseListener
+ /**
+ * Double click to call invokeFileFromString.
+ */
- // static methods
+ public void mouseClicked(MouseEvent e) {
+ if (e.getSource() == table) {
+ if (e.getClickCount() > 1) {
+ int row = table.rowAtPoint(e.getPoint());
+ int col = table.columnAtPoint(e.getPoint());
-/**
-* Obtains a list of strings representing the stack trace
-* associated with this throwable starting with the most recent call.
-* @param aThrowable A Throwable whose stack trace is parsed.
-* @return a List containing the method names as Strings.
-*/
- static public List parseStackTrace( Throwable aThrowable )
- {
- String trace = null;
+ if ((row == -1) || (col != 0))
+ return;
- // create new stream
- ByteArrayOutputStream os = new ByteArrayOutputStream( 256 );
- PrintStream newErr = new PrintStream( os );
- aThrowable.printStackTrace( newErr ); // prints to System.err
+ invokeFileFromString(methodNames.get(row).toString());
+ }
+ }
+ }
- // convert to string
- trace = os.toString();
+ public void mouseReleased(MouseEvent e) {
+ }
- List result = new ArrayList();
+ public void mousePressed(MouseEvent e) {
+ }
- // populate list with parsed trace, starting from top
- String token;
- StringTokenizer tokens = new StringTokenizer( trace, "\n" );
- tokens.nextToken(); // strip off description of throwable
- while ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
- if ( token.indexOf( StackTraceInspector.class.getName() ) == -1 )
- { // add only those methods not from this class
+ public void mouseEntered(MouseEvent e) {
+ }
- // strip whitespace, "at " from front, and \r from end
- token.trim();
- token = token.substring( 4, token.length() - 1 );
+ public void mouseExited(MouseEvent e) {
+ }
- result.add( token );
- }
- }
+ // interface ActionEventListener - for listening to key commands
- return result;
- }
+ public void actionPerformed(ActionEvent evt) {
+ if (COPY.equals(evt.getActionCommand())) {
+ copyToClipboard();
+ return;
+ }
+ }
+
+ /**
+ * Copies the contents of the table to the clipboard as a tab-delimited string.
+ */
+ public void copyToClipboard() {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Clipboard clipboard = toolkit.getSystemClipboard();
+ StringSelection selection = new StringSelection(getSelectedStackString());
+ clipboard.setContents(selection, selection);
+ }
+
+ /**
+ * Converts the selected contents of the table to a string.
+ *
+ * @return A String containing the text contents of the table.
+ */
+ public String getSelectedStackString() {
+ StringBuffer result = new StringBuffer(64);
+
+ TableModel model = table.getModel();
+
+ Object o;
+ int[] selectedRows = table.getSelectedRows();
+ for (int i = 0; i < selectedRows.length; i++) {
+ o = model.getValueAt(selectedRows[i], 0);
+ if (o == null)
+ o = "";
+ result.append(o);
+ result.append('\n');
+ }
-/**
-* Convenience method that obtains a String representing
-* the caller's caller.
-* @return a String representing a method in stack trace format.
-*/
- static public String getMyCaller()
- {
- List trace = parseStackTrace( new RuntimeException() );
- if ( trace.size() > 1 )
- {
- return trace.get( 1 ).toString();
- }
+ return result.toString();
+ }
+
+ // static methods
+
+ /**
+ * Obtains a list of strings representing the stack trace associated with this
+ * throwable starting with the most recent call.
+ *
+ * @param aThrowable A Throwable whose stack trace is parsed.
+ * @return a List containing the method names as Strings.
+ */
+ static public List parseStackTrace(Throwable aThrowable) {
+ String trace = null;
+
+ // create new stream
+ ByteArrayOutputStream os = new ByteArrayOutputStream(256);
+ PrintStream newErr = new PrintStream(os);
+ aThrowable.printStackTrace(newErr); // prints to System.err
+
+ // convert to string
+ trace = os.toString();
+
+ List result = new ArrayList();
+
+ // populate list with parsed trace, starting from top
+ String token;
+ StringTokenizer tokens = new StringTokenizer(trace, "\n");
+ tokens.nextToken(); // strip off description of throwable
+ while (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+ if (token.indexOf(StackTraceInspector.class.getName()) == -1) { // add only those methods not from this
+ // class
+
+ // strip whitespace, "at " from front, and \r from end
+ token.trim();
+ token = token.substring(4, token.length() - 1);
+
+ result.add(token);
+ }
+ }
- return null;
- }
+ return result;
+ }
+
+ /**
+ * Convenience method that obtains a String representing the caller's caller.
+ *
+ * @return a String representing a method in stack trace format.
+ */
+ static public String getMyCaller() {
+ List trace = parseStackTrace(new RuntimeException());
+ if (trace.size() > 1) {
+ return trace.get(1).toString();
+ }
-/**
-* Prints a stack trace up to the first method whose fully
-* qualified class name begins with "java" to System.out.
-*/
- static public void printShortStackTrace()
- {
- String s;
- Iterator i = parseStackTrace( new RuntimeException() ).iterator();
- while ( i.hasNext() )
- {
- System.out.println( " " + ( s = i.next().toString() ) );
- if ( s.startsWith( "java" ) ) break;
- }
- }
-
- protected void invokeFileFromString( String aString )
- {
- // strip off parentheses, if any
- int openParam = aString.indexOf( "(" );
- if ( openParam != -1 )
- {
- aString = aString.substring( 0, openParam );
- }
-
- // separate class name from method name
- int lastDot = aString.lastIndexOf( "." );
- if ( lastDot == -1 ) return;
- String className = aString.substring( 0, lastDot );
- String methodName = aString.substring( lastDot + 1 );
-
- // convert "."s to file separator characters
- StringBuffer buf = new StringBuffer();
- StringTokenizer tokens = new StringTokenizer( className, "." );
- while ( true )
- {
- buf.append( tokens.nextToken() );
- if ( ! tokens.hasMoreTokens() ) break;
- buf.append( File.separator );
- }
- String path = buf.toString();
- java.net.URL url = ClassLoader.getSystemResource( path + ".java" );
- if ( url == null ) return; // do nothing
-
- String name = url.getFile();
-
- // try to launch the document
- try
- {
- // NOTE: This is Windows-dependent!
- String args[] = new String[] {
- "cmd", "/c", "\"start \"\" \"" + name.substring(1) + "\"\"" };
- // this translates to: cmd /c "start "" "path""
- // apparently an array is more reliable for calling exec().
- // all the extra quotes are to handle paths with spaces.
- // trims off the first "/" before the drive letter.
- // needed a dummy title for the console or it wouldn't work.
- Runtime.getRuntime().exec( args );
- }
- catch ( Exception exc )
- {
- System.out.println( "DocumentLinkPanel.invokeDocument: " + exc );
- }
- return;
- }
+ return null;
+ }
+
+ /**
+ * Prints a stack trace up to the first method whose fully qualified class name
+ * begins with "java" to System.out.
+ */
+ static public void printShortStackTrace() {
+ String s;
+ Iterator i = parseStackTrace(new RuntimeException()).iterator();
+ while (i.hasNext()) {
+ System.out.println(" " + (s = i.next().toString()));
+ if (s.startsWith("java"))
+ break;
+ }
+ }
+
+ protected void invokeFileFromString(String aString) {
+ // strip off parentheses, if any
+ int openParam = aString.indexOf("(");
+ if (openParam != -1) {
+ aString = aString.substring(0, openParam);
+ }
+
+ // separate class name from method name
+ int lastDot = aString.lastIndexOf(".");
+ if (lastDot == -1)
+ return;
+ String className = aString.substring(0, lastDot);
+ String methodName = aString.substring(lastDot + 1);
+
+ // convert "."s to file separator characters
+ StringBuffer buf = new StringBuffer();
+ StringTokenizer tokens = new StringTokenizer(className, ".");
+ while (true) {
+ buf.append(tokens.nextToken());
+ if (!tokens.hasMoreTokens())
+ break;
+ buf.append(File.separator);
+ }
+ String path = buf.toString();
+ java.net.URL url = ClassLoader.getSystemResource(path + ".java");
+ if (url == null)
+ return; // do nothing
+
+ String name = url.getFile();
+
+ // try to launch the document
+ try {
+ // NOTE: This is Windows-dependent!
+ String args[] = new String[] { "cmd", "/c", "\"start \"\" \"" + name.substring(1) + "\"\"" };
+ // this translates to: cmd /c "start "" "path""
+ // apparently an array is more reliable for calling exec().
+ // all the extra quotes are to handle paths with spaces.
+ // trims off the first "/" before the drive letter.
+ // needed a dummy title for the console or it wouldn't work.
+ Runtime.getRuntime().exec(args);
+ } catch (Exception exc) {
+ System.out.println("DocumentLinkPanel.invokeDocument: " + exc);
+ }
+ return;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.5 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.4 2002/11/16 16:33:31 mpowers
- * Now using platform-specific accelerator key for shortcuts.
+ * Revision 1.4 2002/11/16 16:33:31 mpowers Now using platform-specific
+ * accelerator key for shortcuts.
*
- * Revision 1.3 2001/07/18 21:53:33 mpowers
- * Added a string argument for display as a message.
+ * Revision 1.3 2001/07/18 21:53:33 mpowers Added a string argument for display
+ * as a message.
*
- * Revision 1.2 2001/07/17 14:01:43 mpowers
- * Added short stack trace method.
+ * Revision 1.2 2001/07/17 14:01:43 mpowers Added short stack trace method.
*
- * Revision 1.1.1.1 2000/12/21 15:51:34 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:34 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:45 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:45 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/TextInputRangeChecker.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/TextInputRangeChecker.java
index 36dbacf..20f37c1 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/TextInputRangeChecker.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/TextInputRangeChecker.java
@@ -30,339 +30,298 @@ import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
/**
-* This class will actively check the inputs of 2 numbers in seperate text
-* components. The number in the text components represent an upper and lower
-* bound to some range. This class checks to make sure the user inputs values
-* in the lower bound text field that are less than the value of the upper
-* bound and vice versa for the upper bound text field. This class will also
-* check to make sure the bounds fall within a given range if specified.
-*
-* The checks are automatically performed when the focus is lost on either
-* component. If the inputs are correct then no event occurs. If the inputs
-* are not correct, then a dialog message is displayed stating the reason why
-* the bounds are invalid, and the original correct value is restored into the
-* text components.
-*
-* @author rglista
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class TextInputRangeChecker implements FocusListener
-{
- protected static final int NONE = 0;
- protected static final int LOWER = 1;
- protected static final int UPPER = 2;
-
- private JTextComponent lowerComponent;
- private JTextComponent upperComponent;
- private double maxRange;
- private double lowerNumber;
- private double upperNumber;
- private Collection focusListeners;
-
- private String invalidLowerMessage;
- private String invalidUpperMessage;
- private String invalidEitherMessage;
- private String invalidRangeMessage;
-
-
-/**
-* Constructor with some of the settable parameters. No range checking is used.
-* @param aLowerTextComponent A text component for the lower bound.
-* @param anUpperTextComponent A text component for the upper bound.
-*/
- public TextInputRangeChecker( JTextComponent aLowerTextComponent,
- JTextComponent anUpperTextComponent )
- {
- this( aLowerTextComponent, anUpperTextComponent, null, null, 0.0 );
- }
-
-/**
-* Constructor with some of the settable parameters. No range checking is
-* used.
-* @param aLowerTextComponent A text component for the lower bound.
-* @param anUpperTextComponent A text component for the upper bound.
-* @param lowerTextName The name of the lower bound, eg - start year.
-* @param upperTextName The name of the upper bound, eg - end year.
-* is used.
-*/
- public TextInputRangeChecker( JTextComponent aLowerTextComponent,
- JTextComponent anUpperTextComponent,
- String lowerTextName, String upperTextName )
- {
- this( aLowerTextComponent, anUpperTextComponent, lowerTextName, upperTextName, 0.0 );
- }
-
-/**
-* Constructor with some of the settable parameters.
-* @param aLowerTextComponent A text component for the lower bound.
-* @param anUpperTextComponent A text component for the upper bound.
-* @param aMaxRange The range the bounds muist fall between, if 0 then no range
-* is used.
-*/
- public TextInputRangeChecker( JTextComponent aLowerTextComponent,
- JTextComponent anUpperTextComponent,
- double aMaxRange )
- {
- this( aLowerTextComponent, anUpperTextComponent, null, null, aMaxRange );
- }
-
-/**
-* Constructor with all the settable parameters.
-* @param aLowerTextComponent A text component for the lower bound.
-* @param anUpperTextComponent A text component for the upper bound.
-* @param lowerTextName The name of the lower bound, eg - start year.
-* @param upperTextName The name of the upper bound, eg - end year.
-* @param aMaxRange The range the bounds muist fall between, if 0 then no range
-* is used.
-*/
- public TextInputRangeChecker( JTextComponent aLowerTextComponent,
- JTextComponent anUpperTextComponent,
- String lowerTextName, String upperTextName,
- double aMaxRange )
- {
- lowerComponent = aLowerTextComponent;
- upperComponent = anUpperTextComponent;
- maxRange = aMaxRange;
-
- focusListeners = new ArrayList( 1 ); // For most cases, there will be only 1 listener.
-
- lowerComponent.addFocusListener( this );
- upperComponent.addFocusListener( this );
-
- lowerNumber = getNumber( lowerComponent );
- upperNumber = getNumber( upperComponent );
-
- if ( ( lowerTextName != null ) && ( upperTextName != null ) )
- {
- invalidLowerMessage = "The " + lowerTextName + " must be less than or equal to the " + upperTextName + ".";
- invalidUpperMessage = "The " + upperTextName + " must be greater than or equal to the " + lowerTextName + ".";
- invalidEitherMessage = "The " + lowerTextName + " and/or the " + upperTextName + " are not correct.";
- invalidRangeMessage = "The maximum range for the " + lowerTextName + " and " + upperTextName + " is " + maxRange + ".";
- }
- else
- {
- invalidLowerMessage = "The lower bound must be less than or equal to the upper bound.";
- invalidUpperMessage = "The upper bound must be greater than or equal to the lower bound.";
- invalidEitherMessage = "The upper and/or lower bounds are not correct.";
- invalidRangeMessage = "The maximum range is " + maxRange + ".";
- }
- }
-
-/**
-* Allows the caller to perform the validation of the bounds programatically.
-* The lower bound is compared to the upper bound and range checking is performed.
-* If the lower bound is greater than the upper bound, or the range between the
-* bounds is greater than the max range, then validation fails.
-* @return TRUE is validation is successfull, FALSE if it fails.
-*/
- public boolean performCheck()
- {
- return validate( null );
- }
-
-/**
-* Adds the listener to the lists of focus listener maintened by this object.
-* When one of the 2 text components receives a focus event, this object will
-* fire that focus event to any of its listeners. This is useful when the
-* calling object wants to be notified of the components focus events, but wants
-* to ensure that the validation has occured first.
-* <br><br>
-* NOTE: The focus is only fired if the validation was successful. This might
-* have to be changed.
-* @param aListener A Focus Listener to receive Focus Events.
-*/
- public void addFocusListener( FocusListener aListener )
- {
- focusListeners.add( aListener );
- }
-
-/**
-* Returns the last valid value of the lower bound. If this is called while
-* the user is updating the text component but before the focus is lost, the
-* value returned will be the original value before the user started updating
-* the bound.
-* @return The last valid value of the lower bound.
-*/
- public double getLastValidatedLowerNumber()
- {
- return lowerNumber;
- }
-
-/**
-* Returns the last valid value of the upper bound. If this is called while
-* the user is updating the text component but before the focus is lost, the
-* value returned will be the original value before the user started updating
-* the bound.
-* @return The last valid value of the upper bound.
-*/
- public double getLastValidatedUpperNumber()
- {
- return upperNumber;
- }
-
-/**
-* Method used to be notified when one of the text components has gained its
-* focus.
-*/
- public void focusGained( FocusEvent e )
- {
- lowerNumber = getNumber( lowerComponent );
- upperNumber = getNumber( upperComponent );
- }
-
-/**
-* Method used to be notified when one of the text components has lost its
-* focus. Automatic validation occurs here.
-*/
- public void focusLost( FocusEvent e )
- {
- if ( e.isTemporary() )
- {
- return;
- }
-
- if ( validate( e.getSource() ) )
- {
- fireFocusEvent( e );
- }
- }
-
-/**
-* Fires a focus lost event if the validation was successfull.
-*/
- protected void fireFocusEvent( FocusEvent e )
- {
- for ( Iterator it = focusListeners.iterator(); it.hasNext(); )
- {
- ( ( FocusListener )it.next() ).focusLost( e );
- }
- }
-
-/**
-* Validates the bounds inputed by the user.
-* @param aComponent The component to use to display a dialog window, if neccessray.
-* If null, then the parent window of the text componets will be used.
-* @return TRUE if validation was successful, FALSE otherwise.
-*/
- protected boolean validate( Object aComponent )
- {
- int componentUsed = NONE;
- if ( aComponent == lowerComponent )
- {
- componentUsed = LOWER;
- }
- else if ( aComponent == upperComponent )
- {
- componentUsed = UPPER;
- }
-
- double lower = getNumber( lowerComponent );
- double upper = getNumber( upperComponent );
-
- if ( lower > upper )
- {
- if ( componentUsed == LOWER )
- {
- lowerComponent.setText( Double.toString( lowerNumber ) );
- displayMessage( invalidLowerMessage, lowerComponent );
- }
- else if ( componentUsed == UPPER )
- {
- upperComponent.setText( Double.toString( upperNumber ) );
- displayMessage( invalidUpperMessage, upperComponent );
- }
- else
- {
- upperComponent.setText( Double.toString( upperNumber ) );
- lowerComponent.setText( Double.toString( lowerNumber ) );
- displayMessage( invalidEitherMessage, lowerComponent.getTopLevelAncestor() );
- }
-
- return false;
- }
-
- if ( maxRange != 0.0 )
- {
- if ( ( upper - lower ) > maxRange )
- {
- if ( componentUsed == LOWER )
- {
- lowerComponent.setText( Double.toString( lowerNumber ) );
- displayMessage( invalidRangeMessage, lowerComponent );
- }
- else if ( componentUsed == UPPER )
- {
- upperComponent.setText( Double.toString( upperNumber ) );
- displayMessage( invalidRangeMessage, upperComponent );
- }
- else
- {
- upperComponent.setText( Double.toString( upperNumber ) );
- lowerComponent.setText( Double.toString( lowerNumber ) );
- displayMessage( invalidRangeMessage, lowerComponent.getTopLevelAncestor() );
- }
-
- return false;
- }
- }
-
- lowerNumber = lower;
- upperNumber = upper;
- return true;
- }
-
-/**
-* Creates a JOptionPane to display the reason why the bounds failed validation.
-*/
- protected void displayMessage( final String message, final Component parent )
- {
- SwingUtilities.invokeLater( new Runnable()
- {
- public void run()
- {
- JOptionPane.showMessageDialog( parent, message, "Data Entry Error",
- JOptionPane.ERROR_MESSAGE );
- }
- } );
- }
-
-/**
-* Gets the number represented in the text component. If the text does not
-* represent a number, then zero is returned.
-*/
- protected double getNumber( JTextComponent aComponent )
- {
- try
- {
- return Double.valueOf( aComponent.getText() ).doubleValue();
+ * This class will actively check the inputs of 2 numbers in seperate text
+ * components. The number in the text components represent an upper and lower
+ * bound to some range. This class checks to make sure the user inputs values in
+ * the lower bound text field that are less than the value of the upper bound
+ * and vice versa for the upper bound text field. This class will also check to
+ * make sure the bounds fall within a given range if specified.
+ *
+ * The checks are automatically performed when the focus is lost on either
+ * component. If the inputs are correct then no event occurs. If the inputs are
+ * not correct, then a dialog message is displayed stating the reason why the
+ * bounds are invalid, and the original correct value is restored into the text
+ * components.
+ *
+ * @author rglista
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class TextInputRangeChecker implements FocusListener {
+ protected static final int NONE = 0;
+ protected static final int LOWER = 1;
+ protected static final int UPPER = 2;
+
+ private JTextComponent lowerComponent;
+ private JTextComponent upperComponent;
+ private double maxRange;
+ private double lowerNumber;
+ private double upperNumber;
+ private Collection focusListeners;
+
+ private String invalidLowerMessage;
+ private String invalidUpperMessage;
+ private String invalidEitherMessage;
+ private String invalidRangeMessage;
+
+ /**
+ * Constructor with some of the settable parameters. No range checking is used.
+ *
+ * @param aLowerTextComponent A text component for the lower bound.
+ * @param anUpperTextComponent A text component for the upper bound.
+ */
+ public TextInputRangeChecker(JTextComponent aLowerTextComponent, JTextComponent anUpperTextComponent) {
+ this(aLowerTextComponent, anUpperTextComponent, null, null, 0.0);
+ }
+
+ /**
+ * Constructor with some of the settable parameters. No range checking is used.
+ *
+ * @param aLowerTextComponent A text component for the lower bound.
+ * @param anUpperTextComponent A text component for the upper bound.
+ * @param lowerTextName The name of the lower bound, eg - start year.
+ * @param upperTextName The name of the upper bound, eg - end year. is
+ * used.
+ */
+ public TextInputRangeChecker(JTextComponent aLowerTextComponent, JTextComponent anUpperTextComponent,
+ String lowerTextName, String upperTextName) {
+ this(aLowerTextComponent, anUpperTextComponent, lowerTextName, upperTextName, 0.0);
+ }
+
+ /**
+ * Constructor with some of the settable parameters.
+ *
+ * @param aLowerTextComponent A text component for the lower bound.
+ * @param anUpperTextComponent A text component for the upper bound.
+ * @param aMaxRange The range the bounds muist fall between, if 0
+ * then no range is used.
+ */
+ public TextInputRangeChecker(JTextComponent aLowerTextComponent, JTextComponent anUpperTextComponent,
+ double aMaxRange) {
+ this(aLowerTextComponent, anUpperTextComponent, null, null, aMaxRange);
+ }
+
+ /**
+ * Constructor with all the settable parameters.
+ *
+ * @param aLowerTextComponent A text component for the lower bound.
+ * @param anUpperTextComponent A text component for the upper bound.
+ * @param lowerTextName The name of the lower bound, eg - start year.
+ * @param upperTextName The name of the upper bound, eg - end year.
+ * @param aMaxRange The range the bounds muist fall between, if 0
+ * then no range is used.
+ */
+ public TextInputRangeChecker(JTextComponent aLowerTextComponent, JTextComponent anUpperTextComponent,
+ String lowerTextName, String upperTextName, double aMaxRange) {
+ lowerComponent = aLowerTextComponent;
+ upperComponent = anUpperTextComponent;
+ maxRange = aMaxRange;
+
+ focusListeners = new ArrayList(1); // For most cases, there will be only 1 listener.
+
+ lowerComponent.addFocusListener(this);
+ upperComponent.addFocusListener(this);
+
+ lowerNumber = getNumber(lowerComponent);
+ upperNumber = getNumber(upperComponent);
+
+ if ((lowerTextName != null) && (upperTextName != null)) {
+ invalidLowerMessage = "The " + lowerTextName + " must be less than or equal to the " + upperTextName + ".";
+ invalidUpperMessage = "The " + upperTextName + " must be greater than or equal to the " + lowerTextName
+ + ".";
+ invalidEitherMessage = "The " + lowerTextName + " and/or the " + upperTextName + " are not correct.";
+ invalidRangeMessage = "The maximum range for the " + lowerTextName + " and " + upperTextName + " is "
+ + maxRange + ".";
+ } else {
+ invalidLowerMessage = "The lower bound must be less than or equal to the upper bound.";
+ invalidUpperMessage = "The upper bound must be greater than or equal to the lower bound.";
+ invalidEitherMessage = "The upper and/or lower bounds are not correct.";
+ invalidRangeMessage = "The maximum range is " + maxRange + ".";
+ }
+ }
+
+ /**
+ * Allows the caller to perform the validation of the bounds programatically.
+ * The lower bound is compared to the upper bound and range checking is
+ * performed. If the lower bound is greater than the upper bound, or the range
+ * between the bounds is greater than the max range, then validation fails.
+ *
+ * @return TRUE is validation is successfull, FALSE if it fails.
+ */
+ public boolean performCheck() {
+ return validate(null);
+ }
+
+ /**
+ * Adds the listener to the lists of focus listener maintened by this object.
+ * When one of the 2 text components receives a focus event, this object will
+ * fire that focus event to any of its listeners. This is useful when the
+ * calling object wants to be notified of the components focus events, but wants
+ * to ensure that the validation has occured first. <br>
+ * <br>
+ * NOTE: The focus is only fired if the validation was successful. This might
+ * have to be changed.
+ *
+ * @param aListener A Focus Listener to receive Focus Events.
+ */
+ public void addFocusListener(FocusListener aListener) {
+ focusListeners.add(aListener);
+ }
+
+ /**
+ * Returns the last valid value of the lower bound. If this is called while the
+ * user is updating the text component but before the focus is lost, the value
+ * returned will be the original value before the user started updating the
+ * bound.
+ *
+ * @return The last valid value of the lower bound.
+ */
+ public double getLastValidatedLowerNumber() {
+ return lowerNumber;
+ }
+
+ /**
+ * Returns the last valid value of the upper bound. If this is called while the
+ * user is updating the text component but before the focus is lost, the value
+ * returned will be the original value before the user started updating the
+ * bound.
+ *
+ * @return The last valid value of the upper bound.
+ */
+ public double getLastValidatedUpperNumber() {
+ return upperNumber;
+ }
+
+ /**
+ * Method used to be notified when one of the text components has gained its
+ * focus.
+ */
+ public void focusGained(FocusEvent e) {
+ lowerNumber = getNumber(lowerComponent);
+ upperNumber = getNumber(upperComponent);
+ }
+
+ /**
+ * Method used to be notified when one of the text components has lost its
+ * focus. Automatic validation occurs here.
+ */
+ public void focusLost(FocusEvent e) {
+ if (e.isTemporary()) {
+ return;
+ }
+
+ if (validate(e.getSource())) {
+ fireFocusEvent(e);
+ }
+ }
+
+ /**
+ * Fires a focus lost event if the validation was successfull.
+ */
+ protected void fireFocusEvent(FocusEvent e) {
+ for (Iterator it = focusListeners.iterator(); it.hasNext();) {
+ ((FocusListener) it.next()).focusLost(e);
+ }
+ }
+
+ /**
+ * Validates the bounds inputed by the user.
+ *
+ * @param aComponent The component to use to display a dialog window, if
+ * neccessray. If null, then the parent window of the text
+ * componets will be used.
+ * @return TRUE if validation was successful, FALSE otherwise.
+ */
+ protected boolean validate(Object aComponent) {
+ int componentUsed = NONE;
+ if (aComponent == lowerComponent) {
+ componentUsed = LOWER;
+ } else if (aComponent == upperComponent) {
+ componentUsed = UPPER;
+ }
+
+ double lower = getNumber(lowerComponent);
+ double upper = getNumber(upperComponent);
+
+ if (lower > upper) {
+ if (componentUsed == LOWER) {
+ lowerComponent.setText(Double.toString(lowerNumber));
+ displayMessage(invalidLowerMessage, lowerComponent);
+ } else if (componentUsed == UPPER) {
+ upperComponent.setText(Double.toString(upperNumber));
+ displayMessage(invalidUpperMessage, upperComponent);
+ } else {
+ upperComponent.setText(Double.toString(upperNumber));
+ lowerComponent.setText(Double.toString(lowerNumber));
+ displayMessage(invalidEitherMessage, lowerComponent.getTopLevelAncestor());
+ }
+
+ return false;
+ }
+
+ if (maxRange != 0.0) {
+ if ((upper - lower) > maxRange) {
+ if (componentUsed == LOWER) {
+ lowerComponent.setText(Double.toString(lowerNumber));
+ displayMessage(invalidRangeMessage, lowerComponent);
+ } else if (componentUsed == UPPER) {
+ upperComponent.setText(Double.toString(upperNumber));
+ displayMessage(invalidRangeMessage, upperComponent);
+ } else {
+ upperComponent.setText(Double.toString(upperNumber));
+ lowerComponent.setText(Double.toString(lowerNumber));
+ displayMessage(invalidRangeMessage, lowerComponent.getTopLevelAncestor());
+ }
+
+ return false;
+ }
+ }
+
+ lowerNumber = lower;
+ upperNumber = upper;
+ return true;
+ }
+
+ /**
+ * Creates a JOptionPane to display the reason why the bounds failed validation.
+ */
+ protected void displayMessage(final String message, final Component parent) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ JOptionPane.showMessageDialog(parent, message, "Data Entry Error", JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ }
+
+ /**
+ * Gets the number represented in the text component. If the text does not
+ * represent a number, then zero is returned.
+ */
+ protected double getNumber(JTextComponent aComponent) {
+ try {
+ return Double.valueOf(aComponent.getText()).doubleValue();
//1.2 return Double.parseDouble( aComponent.getText() );
- }
- catch ( NumberFormatException e )
- {
- System.out.println("[GUI] TextInputRangeChecker.getNumber(): The text is NOT a number: " + aComponent.getText() );
- return 0.0;
- }
- }
+ } catch (NumberFormatException e) {
+ System.out.println(
+ "[GUI] TextInputRangeChecker.getNumber(): The text is NOT a number: " + aComponent.getText());
+ return 0.0;
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1.1.1 2000/12/21 15:51:49 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:49 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:46 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:46 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowGrabber.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowGrabber.java
index c360105..4ac8374 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowGrabber.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowGrabber.java
@@ -31,173 +31,140 @@ import javax.swing.JFrame;
import javax.swing.JWindow;
/**
- * WindowGrabber is a collection of static utility methods
- * for taking screen shots of lightweight containers. All
- * components that are not native peers will be drawn to a
- * bitmap that will be run-length compressed (LZW encoding, GIF format)
- * and written to the specified file or output stream. <br><br>
+ * WindowGrabber is a collection of static utility methods for taking screen
+ * shots of lightweight containers. All components that are not native peers
+ * will be drawn to a bitmap that will be run-length compressed (LZW encoding,
+ * GIF format) and written to the specified file or output stream. <br>
+ * <br>
*
- * Any Swing/JFC or IFC window is a good candidate for use with these
- * methods. The component is not expected to contain more than 256 colors
- * (the maximum that GIF allows). While there is a color depth limitation,
- * the compression is lossless, with no blurs or bleeding color.
+ * Any Swing/JFC or IFC window is a good candidate for use with these methods.
+ * The component is not expected to contain more than 256 colors (the maximum
+ * that GIF allows). While there is a color depth limitation, the compression is
+ * lossless, with no blurs or bleeding color.
*
* @author michael@mpowers.net
- * @version $Revision: 904 $
- * $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
*/
-public class WindowGrabber
-{
-/**
- * Captures the screen contents of the specified component,
- * and write it to a file with the specified name.
- *
- * @param aComponent a lightweight component or container.
- * @param aFileName the name of the file to write, optionally preceded by path.
- * @return True if the file was successfully written, false if there was an error.
- * Errors are written to the standard error stream.
- */
- static public boolean grab( Component aComponent, String aFileName )
- {
+public class WindowGrabber {
+ /**
+ * Captures the screen contents of the specified component, and write it to a
+ * file with the specified name.
+ *
+ * @param aComponent a lightweight component or container.
+ * @param aFileName the name of the file to write, optionally preceded by path.
+ * @return True if the file was successfully written, false if there was an
+ * error. Errors are written to the standard error stream.
+ */
+ static public boolean grab(Component aComponent, String aFileName) {
OutputStream output = null;
- try
- {
- output = new FileOutputStream( aFileName );
- }
- catch ( Exception exc )
- {
- System.err.println( exc );
+ try {
+ output = new FileOutputStream(aFileName);
+ } catch (Exception exc) {
+ System.err.println(exc);
return false;
}
- return grab( aComponent, output );
+ return grab(aComponent, output);
}
-/**
- * Captures the screen contents of the specified component,
- * and write it to a file with the specified name.
- *
- * @param aComponent a lightweight component or container.
- * @param anOutputStream an output stream to which the image will be written.
- * @return True if the image was successfully written, false if there was an error.
- * Errors are written to the standard error stream.
- */
- static public boolean grab( Component aComponent, OutputStream anOutputStream )
- {
- Image img = aComponent.createImage(
- aComponent.getSize().width, aComponent.getSize().height );
- aComponent.paintAll( img.getGraphics() );
+ /**
+ * Captures the screen contents of the specified component, and write it to a
+ * file with the specified name.
+ *
+ * @param aComponent a lightweight component or container.
+ * @param anOutputStream an output stream to which the image will be written.
+ * @return True if the image was successfully written, false if there was an
+ * error. Errors are written to the standard error stream.
+ */
+ static public boolean grab(Component aComponent, OutputStream anOutputStream) {
+ Image img = aComponent.createImage(aComponent.getSize().width, aComponent.getSize().height);
+ aComponent.paintAll(img.getGraphics());
try {
- GIFEncoder encoder = new GIFEncoder( img );
- encoder.write( anOutputStream );
+ GIFEncoder encoder = new GIFEncoder(img);
+ encoder.write(anOutputStream);
anOutputStream.flush();
- } catch ( Exception exc ) {
- System.err.println( exc );
+ } catch (Exception exc) {
+ System.err.println(exc);
return false;
}
return true;
}
- protected static void processFilenames( String path, String[] filenames )
- {
+ protected static void processFilenames(String path, String[] filenames) {
ClassLoader loader = new ClassGrabber();
File f;
- for ( int i = 0; i < filenames.length; i++ )
- {
- try
- {
- f = new File( path + filenames[i] );
- if ( f.isDirectory() )
- {
- processFilenames (
- path + filenames[i] + "/",
- f.list( new FilenameFilter()
- {
- public boolean accept(File dir, String name)
- {
- return name.endsWith( ".class" );
+ for (int i = 0; i < filenames.length; i++) {
+ try {
+ f = new File(path + filenames[i]);
+ if (f.isDirectory()) {
+ processFilenames(path + filenames[i] + "/", f.list(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".class");
+ }
+ }));
+ } else {
+ System.out.println("Loading " + filenames[i] + ": ");
+ Class c = loader.loadClass(path + filenames[i]);
+
+ System.out.println(c);
+
+ if (JWindow.class.isAssignableFrom(c) || JDialog.class.isAssignableFrom(c)
+ || JFrame.class.isAssignableFrom(c)) {
+ try {
+ Window w = (Window) c.newInstance();
+ if (w.getBounds().width * w.getBounds().height == 0) { // if size not specified or set, pack
+ // it
+ w.pack();
}
- })
- );
- }
- else
- {
- System.out.println( "Loading " + filenames[i] + ": " );
- Class c = loader.loadClass( path + filenames[i] );
-
- System.out.println( c );
-
- if ( JWindow.class.isAssignableFrom( c ) ||
- JDialog.class.isAssignableFrom( c ) ||
- JFrame.class.isAssignableFrom( c ) )
- {
- try
- {
- Window w = (Window) c.newInstance();
- if ( w.getBounds().width * w.getBounds().height == 0 )
- { // if size not specified or set, pack it
- w.pack();
- }
- String gifName = // replace .class with .gif
- filenames[i].substring(
- 0, filenames[i].length() - 5 ) + "gif";
- w.addNotify();
- w.repaint();
- grab( w, gifName );
- System.out.println( "wrote: " + gifName );
- }
- catch ( Exception exc )
- {
- System.err.println( "WindowGrab failed for " + filenames[i] + ": " );
- exc.printStackTrace();
- }
-
- }
- else
- {
- System.out.println( "not a JWindow, JDialog, or JFrame; ignored." );
- }
+ String gifName = // replace .class with .gif
+ filenames[i].substring(0, filenames[i].length() - 5) + "gif";
+ w.addNotify();
+ w.repaint();
+ grab(w, gifName);
+ System.out.println("wrote: " + gifName);
+ } catch (Exception exc) {
+ System.err.println("WindowGrab failed for " + filenames[i] + ": ");
+ exc.printStackTrace();
+ }
+
+ } else {
+ System.out.println("not a JWindow, JDialog, or JFrame; ignored.");
+ }
}
- }
- catch ( Exception exc )
- {
- System.err.println( filenames[i] + ": " + exc );
+ } catch (Exception exc) {
+ System.err.println(filenames[i] + ": " + exc);
}
}
}
-/**
- * Captures images of any Swing window component classes specified
- * as parameters. If created, image file will have the same name
- * as the corresponding class file, but with a ".gif" extension.
- *
- * @param argv a list of filenames or directory names.
- */
- public static void main( String[] argv )
- {
- processFilenames( "", argv );
- System.exit( 0 );
+ /**
+ * Captures images of any Swing window component classes specified as
+ * parameters. If created, image file will have the same name as the
+ * corresponding class file, but with a ".gif" extension.
+ *
+ * @param argv a list of filenames or directory names.
+ */
+ public static void main(String[] argv) {
+ processFilenames("", argv);
+ System.exit(0);
}
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:51:49 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:49 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:46 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:46 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowUtilities.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowUtilities.java
index a36ba12..e9d3329 100644
--- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowUtilities.java
+++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/util/WindowUtilities.java
@@ -34,488 +34,440 @@ import java.util.List;
import java.util.Map;
/**
-* A collection of window-related utilities.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-* $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) $
-*
-*/
-public class WindowUtilities
-{
-
-/**
-* Place frame at center (vertically and horizontally) of screen.
-*/
- public static final int CENTER = 0;
-
-/**
-* Center dialog on frame area of parent, if any.
-*/
- public static final int CENTER_PARENT = 1;
-
-/**
-* Place lower and to the right of the last window
-* placed in this manner. Will wrap to top and left
-* of screen as necessary.
-*/
- public static final int CASCADE = 10;
-
- // cascade state
- private static int lastX = 0;
- private static int lastY = 0;
- private static int incrementX = 20;
- private static int incrementY = 20;
-
-/**
-* Place the window in the center of the screen.
-* Note: don't forget to first set the size of your window.
-* This is a convenience method and simply calls place() with
-* the CENTER parameter.
-* @param aWindow The window to be centered.
-* @see #place
-*/
- public static void center( Window aWindow )
- {
- place( aWindow, CENTER );
- }
-
-/**
-* Place lower and to the right of the last window
-* placed in this manner. Will wrap to top and left
-* of screen as necessary.
-* This is a convenience method and simply calls place() with
-* the CASCADE parameter.
-* @param aWindow The window to be cascaded.
-* @see #place
-*/
- public static void cascade( Window aWindow )
- {
- place( aWindow, CASCADE );
- }
-
-/**
-* Place the window in the specified location.
-* Note: don't forget to first set the size of your window.
-* @param aWindow The window to be placed.
-* @param location Where on screen to place the frame.
-*/
- public static void place( Window aWindow, int location)
- {
- Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
- Dimension mySize = aWindow.getSize();
- int x = (aWindow.getLocation()).x;
- int y = (aWindow.getLocation()).y;
- float aspectRatio = (float)screenSize.height/(float)screenSize.width;
-
- // hack to make windows appear on left monitor if dual monitor
- // if aspect ratio is less than 0.6, assume dual monitor
- if (aspectRatio < 0.6)
- {
- screenSize.width = screenSize.width/2;
- }
-
- switch (location)
- {
- case CENTER_PARENT:
- if ( ( ! ( aWindow instanceof Dialog ) )
- || ( ((Dialog)aWindow).getParent() == null ) )
+ * A collection of window-related utilities.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006)
+ * $
+ *
+ */
+public class WindowUtilities {
+
+ /**
+ * Place frame at center (vertically and horizontally) of screen.
+ */
+ public static final int CENTER = 0;
+
+ /**
+ * Center dialog on frame area of parent, if any.
+ */
+ public static final int CENTER_PARENT = 1;
+
+ /**
+ * Place lower and to the right of the last window placed in this manner. Will
+ * wrap to top and left of screen as necessary.
+ */
+ public static final int CASCADE = 10;
+
+ // cascade state
+ private static int lastX = 0;
+ private static int lastY = 0;
+ private static int incrementX = 20;
+ private static int incrementY = 20;
+
+ /**
+ * Place the window in the center of the screen. Note: don't forget to first set
+ * the size of your window. This is a convenience method and simply calls
+ * place() with the CENTER parameter.
+ *
+ * @param aWindow The window to be centered.
+ * @see #place
+ */
+ public static void center(Window aWindow) {
+ place(aWindow, CENTER);
+ }
+
+ /**
+ * Place lower and to the right of the last window placed in this manner. Will
+ * wrap to top and left of screen as necessary. This is a convenience method and
+ * simply calls place() with the CASCADE parameter.
+ *
+ * @param aWindow The window to be cascaded.
+ * @see #place
+ */
+ public static void cascade(Window aWindow) {
+ place(aWindow, CASCADE);
+ }
+
+ /**
+ * Place the window in the specified location. Note: don't forget to first set
+ * the size of your window.
+ *
+ * @param aWindow The window to be placed.
+ * @param location Where on screen to place the frame.
+ */
+ public static void place(Window aWindow, int location) {
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension mySize = aWindow.getSize();
+ int x = (aWindow.getLocation()).x;
+ int y = (aWindow.getLocation()).y;
+ float aspectRatio = (float) screenSize.height / (float) screenSize.width;
+
+ // hack to make windows appear on left monitor if dual monitor
+ // if aspect ratio is less than 0.6, assume dual monitor
+ if (aspectRatio < 0.6) {
+ screenSize.width = screenSize.width / 2;
+ }
+
+ switch (location) {
+ case CENTER_PARENT:
+ if ((!(aWindow instanceof Dialog)) || (((Dialog) aWindow).getParent() == null))
//1.2 || ( ((Dialog)aWindow).getOwner() == null ) )
- {
- place( aWindow, CENTER );
- return;
- }
- Point parentLocation = (((Dialog)aWindow).getParent()).getLocation();
+ {
+ place(aWindow, CENTER);
+ return;
+ }
+ Point parentLocation = (((Dialog) aWindow).getParent()).getLocation();
//1.2 (((Dialog)aWindow).getOwner()).getLocation();
- Dimension parentSize = (((Dialog)aWindow).getParent()).getSize();
+ Dimension parentSize = (((Dialog) aWindow).getParent()).getSize();
//1.2 Dimension parentSize = (((Dialog)aWindow).getOwner()).getSize();
- if (parentSize.width > mySize.width)
- {
- x = ((parentSize.width - mySize.width)/2) + parentLocation.x;
- }
- if (parentSize.height > mySize.height)
- {
- y = ((parentSize.height - mySize.height)/2) + parentLocation.y;
- }
- break;
- case CENTER:
- if (screenSize.width > mySize.width)
- {
- x = (screenSize.width - mySize.width)/2;
- }
- if (screenSize.height > mySize.height)
- {
- y = (screenSize.height - mySize.height)/2;
- }
- break;
- case CASCADE:
- x = lastX + incrementX;
- if ( x + mySize.width > screenSize.width )
- {
- x = incrementX;
- }
- y = lastY + incrementY;
- if ( y + mySize.height > screenSize.height )
- {
- y = incrementY;
- }
- lastX = x;
- lastY = y;
- break;
- default:
- // don't move the frame
- Point p = aWindow.getLocation();
- x = p.x;
- y = p.y;
- break;
- }
- aWindow.setLocation(x,y);
- }
-
-/**
- * Returns the first parent Window of the specified component.
- *
- * @param c the Component whose parent will be found.
- * @return the Window that contains the component,
- * or null if the component does not have a valid Frame parent.
- */
- public static Window getWindowForComponent(Component c)
- {
- for(Component p = c; p != null; p = p.getParent()) {
- if (p instanceof Window) {
- return (Window) p;
- }
- }
- return null;
- }
-
-
-
-/**
-* Prints out a list of all components to System.out.
-* @param aContainer the Container whose components will be listed.
-*/
- public static void dumpComponents( Container aContainer )
- {
- dumpComponents( aContainer, "" );
- }
-
- protected static void dumpComponents( Container aContainer, String padding )
- {
- Component c = null;
- int count = aContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = aContainer.getComponent( i );
- if ( c instanceof javax.swing.JComponent )
- {
- System.out.println( padding + c.getClass() + ": "
- + ((javax.swing.JComponent)c).getAccessibleContext().getAccessibleName() );
- }
- else
- {
- System.out.println( padding + c.getClass() + ": " + c.getName() );
- }
- if ( c instanceof Container )
- {
- dumpComponents( (Container) c, padding + " " );
- }
- }
- }
-
-/**
-* Gets a list of all children of a specified container, sorted by position.
-* Components are sorted from top to bottom and then left to right.
-* @param aContainer The container whose children are to be returned.
-* @result A List containing the sorted components.
-*/
- public static List getSortedChildComponents( Container aContainer )
- {
- List result = new ArrayList( getAllChildComponents( aContainer ) );
- Collections.sort( result, new PositionComparator( aContainer ) );
- return result;
- }
-
- public static void dumpSortedChildComponents( Container aContainer )
- {
- Component c = null;
- Iterator it = getSortedChildComponents( aContainer ).iterator();
- while ( it.hasNext() )
- {
- c = (Component) it.next();
- System.out.println( c.getLocation() + " : " + c.getClass() );
- }
- }
-
- public static void dumpNamedChildComponents( Container aContainer )
- {
- Iterator it = getUniqueNameMap( getSortedChildComponents( aContainer ) ).values().iterator();
- while ( it.hasNext() )
- {
- System.out.println( it.next() );
- }
- }
-
-/**
-* Generates a unique name for each object in a list and returns
-* a map that maps the objects to the names. The name is based
-* on the class of the object in the object list.
-* @param anObjectList A List of objects.
-* @return A Map that maps the objects in the list to the generated names.
-*/
- public static Map getUniqueNameMap( List anObjectList )
- {
- Map namesToObjects = new HashMap(anObjectList.size(), 1F);
- Map objectsToNames = new HashMap(anObjectList.size(), 1F);
-
- Object o = null;
- String name = null;
- int lastIndex = 0;
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- name = o.getClass().getName();
- lastIndex = name.lastIndexOf( "." );
- if ( lastIndex != -1 )
- {
- name = name.substring( lastIndex+1 );
- }
- name = incrementString( name );
- while ( namesToObjects.get( name ) != null )
- {
- name = incrementString( name );
- }
- namesToObjects.put( name, o );
- objectsToNames.put( o, name );
- }
-
- return objectsToNames;
- }
-
-/**
-* Numerically increments a string. For example, "hello" becomes "hello1"
-* and "hello1" becomes "hello2" while "hello999" becomes "hello1000".
-* @param aString a String to be incremented.
-* @return The incremented String.
-*/
- public static String incrementString( String aString )
- {
- int i = aString.length()-1;
- while ( ( i >= 0 ) && ( Character.isDigit( aString.charAt( i ) ) ) )
- {
- i--;
- }
-
- if ( i == aString.length()-1 )
- { // no numerics at end of string, increment manually
- return aString + "1";
- }
-
- String alpha = aString.substring( 0, i+1 );
- String numeric = aString.substring( i+1 );
- numeric = Integer.toString( Integer.parseInt( numeric ) + 1 );
-
- return alpha + numeric;
-
- }
-
-/**
-* Gets all children of the specified container.
-* @param aContainer the Container to be searched.
-* @return A Collection containing all of the child components of the container.
-*/
- public static Collection getAllChildComponents( Container aContainer )
- {
- Collection result = new ArrayList();
- addAllChildComponents( aContainer, result );
- return result;
- }
-
-/**
-* Adds all children of the specified container to the specified collection.
-* @param aContainer the Container to be searched.
-* @param aCollection the Collection to which the child components will be added.
-*/
- protected static void addAllChildComponents( Container aContainer, Collection aCollection )
- {
- Component c = null;
- int count = aContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = aContainer.getComponent( i );
- aCollection.add( c );
- if ( c instanceof Container )
- {
- addAllChildComponents( (Container) c, aCollection );
- }
- }
- }
-
-/**
-* Sets each child component's tooltip to show the name generated from
-* getComponentNameMap().
-* (We're doing this so the tooltip authors can know how to reference
-* the components.)
-* @param aContainer the Container whose components will be labeled.
-*/
- public static void labelComponents( Container aContainer )
- {
- Map nameToComponent = getNameToComponentMap( aContainer );
- Map nameToName = new HashMap(nameToComponent.size(), 1F);
- Iterator it = nameToComponent.keySet().iterator();
- String key;
- while ( it.hasNext() )
- {
- key = it.next().toString();
- nameToName.put( key, key );
- }
- labelComponents( aContainer, nameToName );
- }
-
-/**
-* Sets each child component's tooltip to show a given string retrieved
-* from a map using the component's generated name as a key.
-* @param aContainer the Container whose components will be labeled.
-* @param aNameMap a Map of generated names to string values.
-*/
- public static void labelComponents( Container aContainer, Map aNameMap )
- {
- if ( aNameMap == null ) return;
-
- String key;
- Object o ;
- Iterator it = aNameMap.keySet().iterator();
- Map nameToComponent = getNameToComponentMap( aContainer );
- while ( it.hasNext() )
- {
- key = it.next().toString();
- o = nameToComponent.get( key );
- if ( o instanceof javax.swing.JComponent )
- {
- ((javax.swing.JComponent)o).setToolTipText( aNameMap.get( key ).toString() );
- }
- }
- }
-
-/**
-* Generates a deterministically unique name for each component in a
-* container. The name is based on the name of the class of the component
-* followed by a number. Each class of component is numbered based on it's
-* position in the container, sorted from top to bottom and left to right.
-* @param aContainer the Container whose components will named.
-* @return a Map that maps each component to its name.
-*/
- public static Map getComponentToNameMap( Container aContainer )
- {
- return getUniqueNameMap( getSortedChildComponents( aContainer ) );
- }
-
-/**
-* Maps a deterministically unique name to a component in a
-* container. The name is based on the name of the class of the component
-* followed by a number. Each class of component is numbered based on it's
-* position in the container, sorted from top to bottom and left to right.
-* @param aContainer the Container whose components will named.
-* @return a Map that maps each component to its name.
-*/
- public static Map getNameToComponentMap( Container aContainer )
- {
- Map componentToName = getComponentToNameMap( aContainer );
- Map result = new HashMap(componentToName.size(), 1F);
- Iterator it = componentToName.keySet().iterator();
- Object key;
- while ( it.hasNext() )
- {
- key = it.next();
- result.put( componentToName.get( key ), key );
- }
- return result;
- }
-
-/**
-* Sets the tooltips of all components in a container to the
-* respective names of those components. (We're using this
-* so the tooltip authors can know how to reference the components.)
-* @param aContainer the Container whose components will be labeled.
-*/
- public static void nameComponents( Container aContainer )
- {
- nameComponents( aContainer, "" );
- }
-
- protected static void nameComponents( Container aContainer, String path )
- {
- Component c = null;
- String className = null;
- int index = 0;
- int count = aContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = aContainer.getComponent( i );
- className = c.getClass().getName();
- className = className.substring( className.lastIndexOf( '.' ) + 1 );
- System.out.println( path + className );
- if ( c instanceof javax.swing.JComponent )
- {
- // ((javax.swing.JComponent)c).setToolTipText( path + className + " (" + c.getName() + ")" );
- ((javax.swing.JComponent)c).setToolTipText( c.getName() );
- }
- if ( c instanceof Container )
- {
- nameComponents( (Container) c, path + className + "." );
- }
- }
- }
-
-/**
-* Sets the enabled state of a container and all of its components.
-* @param aContainer the Container whose components will be enabled.
-* @param isEnabled True if enabled, false id disabled.
-*/
- public static void enableComponents( Container aContainer, boolean isEnabled )
- {
- Component c = null;
- String className = null;
- int index = 0;
- int count = aContainer.getComponentCount();
- for ( int i = 0; i < count; i++ )
- {
- c = aContainer.getComponent( i );
- if ( c instanceof Container )
- {
- enableComponents( (Container) c, isEnabled );
- }
- else
- {
- c.setEnabled( isEnabled );
- }
- }
- aContainer.setEnabled( isEnabled );
- }
+ if (parentSize.width > mySize.width) {
+ x = ((parentSize.width - mySize.width) / 2) + parentLocation.x;
+ }
+ if (parentSize.height > mySize.height) {
+ y = ((parentSize.height - mySize.height) / 2) + parentLocation.y;
+ }
+ break;
+ case CENTER:
+ if (screenSize.width > mySize.width) {
+ x = (screenSize.width - mySize.width) / 2;
+ }
+ if (screenSize.height > mySize.height) {
+ y = (screenSize.height - mySize.height) / 2;
+ }
+ break;
+ case CASCADE:
+ x = lastX + incrementX;
+ if (x + mySize.width > screenSize.width) {
+ x = incrementX;
+ }
+ y = lastY + incrementY;
+ if (y + mySize.height > screenSize.height) {
+ y = incrementY;
+ }
+ lastX = x;
+ lastY = y;
+ break;
+ default:
+ // don't move the frame
+ Point p = aWindow.getLocation();
+ x = p.x;
+ y = p.y;
+ break;
+ }
+ aWindow.setLocation(x, y);
+ }
+
+ /**
+ * Returns the first parent Window of the specified component.
+ *
+ * @param c the Component whose parent will be found.
+ * @return the Window that contains the component, or null if the component does
+ * not have a valid Frame parent.
+ */
+ public static Window getWindowForComponent(Component c) {
+ for (Component p = c; p != null; p = p.getParent()) {
+ if (p instanceof Window) {
+ return (Window) p;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Prints out a list of all components to System.out.
+ *
+ * @param aContainer the Container whose components will be listed.
+ */
+ public static void dumpComponents(Container aContainer) {
+ dumpComponents(aContainer, "");
+ }
+
+ protected static void dumpComponents(Container aContainer, String padding) {
+ Component c = null;
+ int count = aContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = aContainer.getComponent(i);
+ if (c instanceof javax.swing.JComponent) {
+ System.out.println(padding + c.getClass() + ": "
+ + ((javax.swing.JComponent) c).getAccessibleContext().getAccessibleName());
+ } else {
+ System.out.println(padding + c.getClass() + ": " + c.getName());
+ }
+ if (c instanceof Container) {
+ dumpComponents((Container) c, padding + " ");
+ }
+ }
+ }
+
+ /**
+ * Gets a list of all children of a specified container, sorted by position.
+ * Components are sorted from top to bottom and then left to right.
+ *
+ * @param aContainer The container whose children are to be returned.
+ * @result A List containing the sorted components.
+ */
+ public static List getSortedChildComponents(Container aContainer) {
+ List result = new ArrayList(getAllChildComponents(aContainer));
+ Collections.sort(result, new PositionComparator(aContainer));
+ return result;
+ }
+
+ public static void dumpSortedChildComponents(Container aContainer) {
+ Component c = null;
+ Iterator it = getSortedChildComponents(aContainer).iterator();
+ while (it.hasNext()) {
+ c = (Component) it.next();
+ System.out.println(c.getLocation() + " : " + c.getClass());
+ }
+ }
+
+ public static void dumpNamedChildComponents(Container aContainer) {
+ Iterator it = getUniqueNameMap(getSortedChildComponents(aContainer)).values().iterator();
+ while (it.hasNext()) {
+ System.out.println(it.next());
+ }
+ }
+
+ /**
+ * Generates a unique name for each object in a list and returns a map that maps
+ * the objects to the names. The name is based on the class of the object in the
+ * object list.
+ *
+ * @param anObjectList A List of objects.
+ * @return A Map that maps the objects in the list to the generated names.
+ */
+ public static Map getUniqueNameMap(List anObjectList) {
+ Map namesToObjects = new HashMap(anObjectList.size(), 1F);
+ Map objectsToNames = new HashMap(anObjectList.size(), 1F);
+
+ Object o = null;
+ String name = null;
+ int lastIndex = 0;
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ name = o.getClass().getName();
+ lastIndex = name.lastIndexOf(".");
+ if (lastIndex != -1) {
+ name = name.substring(lastIndex + 1);
+ }
+ name = incrementString(name);
+ while (namesToObjects.get(name) != null) {
+ name = incrementString(name);
+ }
+ namesToObjects.put(name, o);
+ objectsToNames.put(o, name);
+ }
+
+ return objectsToNames;
+ }
+
+ /**
+ * Numerically increments a string. For example, "hello" becomes "hello1" and
+ * "hello1" becomes "hello2" while "hello999" becomes "hello1000".
+ *
+ * @param aString a String to be incremented.
+ * @return The incremented String.
+ */
+ public static String incrementString(String aString) {
+ int i = aString.length() - 1;
+ while ((i >= 0) && (Character.isDigit(aString.charAt(i)))) {
+ i--;
+ }
+
+ if (i == aString.length() - 1) { // no numerics at end of string, increment manually
+ return aString + "1";
+ }
+
+ String alpha = aString.substring(0, i + 1);
+ String numeric = aString.substring(i + 1);
+ numeric = Integer.toString(Integer.parseInt(numeric) + 1);
+
+ return alpha + numeric;
+
+ }
+
+ /**
+ * Gets all children of the specified container.
+ *
+ * @param aContainer the Container to be searched.
+ * @return A Collection containing all of the child components of the container.
+ */
+ public static Collection getAllChildComponents(Container aContainer) {
+ Collection result = new ArrayList();
+ addAllChildComponents(aContainer, result);
+ return result;
+ }
+
+ /**
+ * Adds all children of the specified container to the specified collection.
+ *
+ * @param aContainer the Container to be searched.
+ * @param aCollection the Collection to which the child components will be
+ * added.
+ */
+ protected static void addAllChildComponents(Container aContainer, Collection aCollection) {
+ Component c = null;
+ int count = aContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = aContainer.getComponent(i);
+ aCollection.add(c);
+ if (c instanceof Container) {
+ addAllChildComponents((Container) c, aCollection);
+ }
+ }
+ }
+
+ /**
+ * Sets each child component's tooltip to show the name generated from
+ * getComponentNameMap(). (We're doing this so the tooltip authors can know how
+ * to reference the components.)
+ *
+ * @param aContainer the Container whose components will be labeled.
+ */
+ public static void labelComponents(Container aContainer) {
+ Map nameToComponent = getNameToComponentMap(aContainer);
+ Map nameToName = new HashMap(nameToComponent.size(), 1F);
+ Iterator it = nameToComponent.keySet().iterator();
+ String key;
+ while (it.hasNext()) {
+ key = it.next().toString();
+ nameToName.put(key, key);
+ }
+ labelComponents(aContainer, nameToName);
+ }
+
+ /**
+ * Sets each child component's tooltip to show a given string retrieved from a
+ * map using the component's generated name as a key.
+ *
+ * @param aContainer the Container whose components will be labeled.
+ * @param aNameMap a Map of generated names to string values.
+ */
+ public static void labelComponents(Container aContainer, Map aNameMap) {
+ if (aNameMap == null)
+ return;
+
+ String key;
+ Object o;
+ Iterator it = aNameMap.keySet().iterator();
+ Map nameToComponent = getNameToComponentMap(aContainer);
+ while (it.hasNext()) {
+ key = it.next().toString();
+ o = nameToComponent.get(key);
+ if (o instanceof javax.swing.JComponent) {
+ ((javax.swing.JComponent) o).setToolTipText(aNameMap.get(key).toString());
+ }
+ }
+ }
+
+ /**
+ * Generates a deterministically unique name for each component in a container.
+ * The name is based on the name of the class of the component followed by a
+ * number. Each class of component is numbered based on it's position in the
+ * container, sorted from top to bottom and left to right.
+ *
+ * @param aContainer the Container whose components will named.
+ * @return a Map that maps each component to its name.
+ */
+ public static Map getComponentToNameMap(Container aContainer) {
+ return getUniqueNameMap(getSortedChildComponents(aContainer));
+ }
+
+ /**
+ * Maps a deterministically unique name to a component in a container. The name
+ * is based on the name of the class of the component followed by a number. Each
+ * class of component is numbered based on it's position in the container,
+ * sorted from top to bottom and left to right.
+ *
+ * @param aContainer the Container whose components will named.
+ * @return a Map that maps each component to its name.
+ */
+ public static Map getNameToComponentMap(Container aContainer) {
+ Map componentToName = getComponentToNameMap(aContainer);
+ Map result = new HashMap(componentToName.size(), 1F);
+ Iterator it = componentToName.keySet().iterator();
+ Object key;
+ while (it.hasNext()) {
+ key = it.next();
+ result.put(componentToName.get(key), key);
+ }
+ return result;
+ }
+
+ /**
+ * Sets the tooltips of all components in a container to the respective names of
+ * those components. (We're using this so the tooltip authors can know how to
+ * reference the components.)
+ *
+ * @param aContainer the Container whose components will be labeled.
+ */
+ public static void nameComponents(Container aContainer) {
+ nameComponents(aContainer, "");
+ }
+
+ protected static void nameComponents(Container aContainer, String path) {
+ Component c = null;
+ String className = null;
+ int index = 0;
+ int count = aContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = aContainer.getComponent(i);
+ className = c.getClass().getName();
+ className = className.substring(className.lastIndexOf('.') + 1);
+ System.out.println(path + className);
+ if (c instanceof javax.swing.JComponent) {
+ // ((javax.swing.JComponent)c).setToolTipText( path + className + " (" +
+ // c.getName() + ")" );
+ ((javax.swing.JComponent) c).setToolTipText(c.getName());
+ }
+ if (c instanceof Container) {
+ nameComponents((Container) c, path + className + ".");
+ }
+ }
+ }
+
+ /**
+ * Sets the enabled state of a container and all of its components.
+ *
+ * @param aContainer the Container whose components will be enabled.
+ * @param isEnabled True if enabled, false id disabled.
+ */
+ public static void enableComponents(Container aContainer, boolean isEnabled) {
+ Component c = null;
+ String className = null;
+ int index = 0;
+ int count = aContainer.getComponentCount();
+ for (int i = 0; i < count; i++) {
+ c = aContainer.getComponent(i);
+ if (c instanceof Container) {
+ enableComponents((Container) c, isEnabled);
+ } else {
+ c.setEnabled(isEnabled);
+ }
+ }
+ aContainer.setEnabled(isEnabled);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:19:05 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.2 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.1.1.1 2000/12/21 15:51:55 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:51:55 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:46 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:46 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
index 8e9fae2..3512c2a 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
@@ -24,310 +24,200 @@ import net.wotonomy.control.EODataSource;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSNotification;
- /**
- * A display group delegate that prints messages for each
- * of the delegate methods.
- *
- * @author michael@mpowers.net
- * @author $Author: cgruber $
- * @version $Revision: 904 $
- */
- public class DebuggingDelegate implements EODisplayGroup.Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- public void displayGroupCreateObjectFailed (
- EODisplayGroup aDisplayGroup,
- EODataSource aDataSource )
- {
- report( "displayGroupCreateObjectFailed",
- aDisplayGroup,
- new Object[] { aDataSource } );
- }
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- public void displayGroupDidChangeDataSource (
- EODisplayGroup aDisplayGroup )
- {
- report( "displayGroupDidChangeDataSource",
- aDisplayGroup,
- new Object[] { } );
- }
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- public void displayGroupDidChangeSelectedObjects (
- EODisplayGroup aDisplayGroup )
- {
- report( "displayGroupDidChangeSelectedObjects",
- aDisplayGroup,
- new Object[] { } );
- }
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- public void displayGroupDidChangeSelection (
- EODisplayGroup aDisplayGroup )
- {
- report( "displayGroupDidChangeSelection",
- aDisplayGroup,
- new Object[] { } );
- }
-
- /**
- * Called after the specified object display group's
- * selection has changed.
- */
- public void displayGroupDidDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
- report( "displayGroupDidDeleteObject",
- aDisplayGroup,
- new Object[] { anObject } );
- }
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- public void displayGroupDidFetchObjects (
- EODisplayGroup aDisplayGroup,
- List anObjectList )
- {
- report( "displayGroupDidFetchObjects",
- aDisplayGroup,
- new Object[] { anObjectList } );
- }
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- public void displayGroupDidInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
- report( "displayGroupDidInsertObject",
- aDisplayGroup,
- new Object[] { anObject } );
- }
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- public void displayGroupDidSetValueForObject (
- EODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey )
- {
- report( "displayGroupDidSetValueForObject",
- aDisplayGroup,
- new Object[] { aValue, anObject, aKey } );
- }
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- public NSArray displayGroupDisplayArrayForObjects (
- EODisplayGroup aDisplayGroup,
- List aList )
- {
- return get( "displayGroupDisplayArrayForObjects",
- aDisplayGroup,
- aList );
- }
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * This implementation returns true.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- public boolean displayGroupShouldChangeSelection (
- EODisplayGroup aDisplayGroup,
- List aSelectionList )
- {
- return ask( "displayGroupShouldChangeSelection",
- aDisplayGroup,
- new Object[] { aSelectionList } );
- }
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * This implementation returns true.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- public boolean displayGroupShouldDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
- return ask( "displayGroupShouldDeleteObject",
- aDisplayGroup,
- new Object[] { anObject } );
- }
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * This implementation returns true.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- public boolean displayGroupShouldDisplayAlert (
- EODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage )
- {
- return ask( "displayGroupShouldDisplayAlert",
- aDisplayGroup,
- new Object[] { aTitle, aMessage } );
- }
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * This implementation returns true.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- public boolean displayGroupShouldFetch (
- EODisplayGroup aDisplayGroup )
- {
- return ask( "displayGroupShouldFetch",
- aDisplayGroup,
- new Object[] { } );
- }
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * This implementation returns true.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- public boolean displayGroupShouldInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex )
- {
- return ask( "displayGroupShouldInsertObject",
- aDisplayGroup,
- new Object[] { anObject, new Integer( anIndex ) } );
- }
-
- /**
- * No idea what this might indicate,
- * nor what the notification indicates.
- * This implementation returns true.
- */
- public boolean displayGroupShouldRedisplay (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification )
- {
- return ask( "displayGroupShouldRedisplay",
- aDisplayGroup,
- new Object[] { aNotification } );
- }
-
- /**
- * No idea what this might indicate,
- * nor what the notification indicates.
- */
- public boolean displayGroupShouldRefetch (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification )
- {
- return ask( "displayGroupShouldRefetch",
- aDisplayGroup,
- new Object[] { aNotification } );
- }
-
- /**
- * This method is called by all delegate methods that
- * return void.
- * This implementation calls System.out.println.
- * Override to customize or replace the output.
- */
- protected void report( String aTitle,
- EODisplayGroup aDisplayGroup,
- Object[] aParameterArray )
- {
- String result = aTitle + " : " + aDisplayGroup;
- for ( int i = 0; i < aParameterArray.length; i++ )
- {
- result += " : " + aParameterArray[i];
- }
- System.out.println( result );
- }
-
- /**
- * This method is called by displayGroupDisplayArrayForObjects.
- * This implementation calls report
- * and returns a copy of the specified list.
- */
- protected NSArray get( String aTitle,
- EODisplayGroup aDisplayGroup,
- List anObjectList )
- {
- report( aTitle, aDisplayGroup, new Object[] { anObjectList } );
- return new NSArray( anObjectList );
- }
-
- /**
- * This method is called by the methods that
- * return a boolean.
- * This implementation calls report and return true.
- */
- protected boolean ask( String aTitle,
- EODisplayGroup aDisplayGroup,
- Object[] aParameterArray )
- {
- report( aTitle, aDisplayGroup, aParameterArray );
- return true;
- }
-
-
- }
+/**
+ * A display group delegate that prints messages for each of the delegate
+ * methods.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class DebuggingDelegate implements EODisplayGroup.Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ public void displayGroupCreateObjectFailed(EODisplayGroup aDisplayGroup, EODataSource aDataSource) {
+ report("displayGroupCreateObjectFailed", aDisplayGroup, new Object[] { aDataSource });
+ }
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ public void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup) {
+ report("displayGroupDidChangeDataSource", aDisplayGroup, new Object[] {});
+ }
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ public void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup) {
+ report("displayGroupDidChangeSelectedObjects", aDisplayGroup, new Object[] {});
+ }
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ public void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup) {
+ report("displayGroupDidChangeSelection", aDisplayGroup, new Object[] {});
+ }
+
+ /**
+ * Called after the specified object display group's selection has changed.
+ */
+ public void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) {
+ report("displayGroupDidDeleteObject", aDisplayGroup, new Object[] { anObject });
+ }
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ public void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList) {
+ report("displayGroupDidFetchObjects", aDisplayGroup, new Object[] { anObjectList });
+ }
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ public void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject) {
+ report("displayGroupDidInsertObject", aDisplayGroup, new Object[] { anObject });
+ }
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ public void displayGroupDidSetValueForObject(EODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey) {
+ report("displayGroupDidSetValueForObject", aDisplayGroup, new Object[] { aValue, anObject, aKey });
+ }
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) {
+ return get("displayGroupDisplayArrayForObjects", aDisplayGroup, aList);
+ }
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection. This implementation returns true.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ public boolean displayGroupShouldChangeSelection(EODisplayGroup aDisplayGroup, List aSelectionList) {
+ return ask("displayGroupShouldChangeSelection", aDisplayGroup, new Object[] { aSelectionList });
+ }
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object. This implementation returns true.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ public boolean displayGroupShouldDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) {
+ return ask("displayGroupShouldDeleteObject", aDisplayGroup, new Object[] { anObject });
+ }
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user. This implementation returns true.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ public boolean displayGroupShouldDisplayAlert(EODisplayGroup aDisplayGroup, String aTitle, String aMessage) {
+ return ask("displayGroupShouldDisplayAlert", aDisplayGroup, new Object[] { aTitle, aMessage });
+ }
+
+ /**
+ * Called by the specified display group before it attempts fetch objects. This
+ * implementation returns true.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ public boolean displayGroupShouldFetch(EODisplayGroup aDisplayGroup) {
+ return ask("displayGroupShouldFetch", aDisplayGroup, new Object[] {});
+ }
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object. This implementation returns true.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ public boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex) {
+ return ask("displayGroupShouldInsertObject", aDisplayGroup, new Object[] { anObject, new Integer(anIndex) });
+ }
+
+ /**
+ * No idea what this might indicate, nor what the notification indicates. This
+ * implementation returns true.
+ */
+ public boolean displayGroupShouldRedisplay(EODisplayGroup aDisplayGroup, NSNotification aNotification) {
+ return ask("displayGroupShouldRedisplay", aDisplayGroup, new Object[] { aNotification });
+ }
+
+ /**
+ * No idea what this might indicate, nor what the notification indicates.
+ */
+ public boolean displayGroupShouldRefetch(EODisplayGroup aDisplayGroup, NSNotification aNotification) {
+ return ask("displayGroupShouldRefetch", aDisplayGroup, new Object[] { aNotification });
+ }
+
+ /**
+ * This method is called by all delegate methods that return void. This
+ * implementation calls System.out.println. Override to customize or replace the
+ * output.
+ */
+ protected void report(String aTitle, EODisplayGroup aDisplayGroup, Object[] aParameterArray) {
+ String result = aTitle + " : " + aDisplayGroup;
+ for (int i = 0; i < aParameterArray.length; i++) {
+ result += " : " + aParameterArray[i];
+ }
+ System.out.println(result);
+ }
+
+ /**
+ * This method is called by displayGroupDisplayArrayForObjects. This
+ * implementation calls report and returns a copy of the specified list.
+ */
+ protected NSArray get(String aTitle, EODisplayGroup aDisplayGroup, List anObjectList) {
+ report(aTitle, aDisplayGroup, new Object[] { anObjectList });
+ return new NSArray(anObjectList);
+ }
+
+ /**
+ * This method is called by the methods that return a boolean. This
+ * implementation calls report and return true.
+ */
+ protected boolean ask(String aTitle, EODisplayGroup aDisplayGroup, Object[] aParameterArray) {
+ report(aTitle, aDisplayGroup, aParameterArray);
+ return true;
+ }
+
+}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2001/01/24 14:37:24 mpowers
- * Contributing a delegate useful for debugging.
+ * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for
+ * debugging.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
index ed572f4..e801406 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
@@ -24,234 +24,168 @@ import net.wotonomy.control.EODataSource;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSNotification;
- /**
- * A convenience class for creating display group delegates.
- * All methods of the delegate interface are implemented
- * to do nothing.
- *
- * @author michael@mpowers.net
- * @author $Author: cgruber $
- * @version $Revision: 904 $
- */
- public class DelegateAdapter implements EODisplayGroup.Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- public void displayGroupCreateObjectFailed (
- EODisplayGroup aDisplayGroup,
- EODataSource aDataSource )
- {
-
- }
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- public void displayGroupDidChangeDataSource (
- EODisplayGroup aDisplayGroup )
- {
-
- }
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- public void displayGroupDidChangeSelectedObjects (
- EODisplayGroup aDisplayGroup )
- {
-
- }
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- public void displayGroupDidChangeSelection (
- EODisplayGroup aDisplayGroup )
- {
-
- }
-
- /**
- * Called after the specified object display group's
- * selection has changed.
- */
- public void displayGroupDidDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
-
- }
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- public void displayGroupDidFetchObjects (
- EODisplayGroup aDisplayGroup,
- List anObjectList )
- {
-
- }
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- public void displayGroupDidInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
-
- }
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- public void displayGroupDidSetValueForObject (
- EODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey )
- {
-
- }
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- public NSArray displayGroupDisplayArrayForObjects (
- EODisplayGroup aDisplayGroup,
- List aList )
- {
- return new NSArray( aList );
- }
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * This implementation returns true.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- public boolean displayGroupShouldChangeSelection (
- EODisplayGroup aDisplayGroup,
- List aSelectionList )
- {
- return true;
- }
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * This implementation returns true.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- public boolean displayGroupShouldDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject )
- {
- return true;
- }
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * This implementation returns true.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- public boolean displayGroupShouldDisplayAlert (
- EODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage )
- {
- return true;
- }
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * This implementation returns true.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- public boolean displayGroupShouldFetch (
- EODisplayGroup aDisplayGroup )
- {
- return true;
- }
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * This implementation returns true.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- public boolean displayGroupShouldInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex )
- {
- return true;
- }
-
- /**
- * No idea what this might indicate,
- * nor what the notification indicates.
- * This implementation returns true.
- */
- public boolean displayGroupShouldRedisplay (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification )
- {
- return true;
- }
-
- /**
- * No idea what this might indicate,
- * nor what the notification indicates.
- */
- public boolean displayGroupShouldRefetch (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification )
- {
- return true;
- }
-
- }
+/**
+ * A convenience class for creating display group delegates. All methods of the
+ * delegate interface are implemented to do nothing.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class DelegateAdapter implements EODisplayGroup.Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ public void displayGroupCreateObjectFailed(EODisplayGroup aDisplayGroup, EODataSource aDataSource) {
+
+ }
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ public void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup) {
+
+ }
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ public void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup) {
+
+ }
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ public void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup) {
+
+ }
+
+ /**
+ * Called after the specified object display group's selection has changed.
+ */
+ public void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) {
+
+ }
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ public void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList) {
+
+ }
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ public void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject) {
+
+ }
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ public void displayGroupDidSetValueForObject(EODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey) {
+
+ }
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) {
+ return new NSArray(aList);
+ }
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection. This implementation returns true.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ public boolean displayGroupShouldChangeSelection(EODisplayGroup aDisplayGroup, List aSelectionList) {
+ return true;
+ }
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object. This implementation returns true.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ public boolean displayGroupShouldDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) {
+ return true;
+ }
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user. This implementation returns true.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ public boolean displayGroupShouldDisplayAlert(EODisplayGroup aDisplayGroup, String aTitle, String aMessage) {
+ return true;
+ }
+
+ /**
+ * Called by the specified display group before it attempts fetch objects. This
+ * implementation returns true.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ public boolean displayGroupShouldFetch(EODisplayGroup aDisplayGroup) {
+ return true;
+ }
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object. This implementation returns true.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ public boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex) {
+ return true;
+ }
+
+ /**
+ * No idea what this might indicate, nor what the notification indicates. This
+ * implementation returns true.
+ */
+ public boolean displayGroupShouldRedisplay(EODisplayGroup aDisplayGroup, NSNotification aNotification) {
+ return true;
+ }
+
+ /**
+ * No idea what this might indicate, nor what the notification indicates.
+ */
+ public boolean displayGroupShouldRefetch(EODisplayGroup aDisplayGroup, NSNotification aNotification) {
+ return true;
+ }
+
+}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.1 2001/01/24 14:23:17 mpowers
- * Contributing DelegateAdapter.
+ * Revision 1.1 2001/01/24 14:23:17 mpowers Contributing DelegateAdapter.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java
index 9fcbe34..d7dd8d8 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java
@@ -25,276 +25,236 @@ import net.wotonomy.control.EODataSource;
import net.wotonomy.control.EOQualifier;
/**
-* DisplayGroup provides an abstraction of a user interface,
-* comprising of an ordered collection of data objects, some
-* of which are displayed, and of those some are selected.
-* This class extends EODisplayGroup to provide java-friendly
-* convenience methods.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class DisplayGroup extends EODisplayGroup
-{
- /**
- * Returns the current data source backing this display group,
- * or null if no dataSource is currently used.
- */
- public EODataSource getDataSource()
- {
- return super.dataSource();
- }
-
- /**
- * Returns the current delegate for this display group,
- * or null if no delegate is currently set.
- */
- public Object getDelegate()
- {
- return delegate();
- }
-
- /**
- * Returns the current string matching format.
- * If not set, defaults to "%@*".
- */
- public String getDefaultStringMatchFormat()
- {
- return defaultStringMatchFormat();
- }
-
- /**
- * Returns the current string matching operator.
- * If not set, defaults to "caseInsensitiveLike".
- */
- public String getdefaultStringMatchOperator()
- {
- return defaultStringMatchOperator();
- }
-
- /**
- * Returns a Map of default values that are applied
- * to new objects that are inserted into the list.
- */
- public Map getInsertedObjectDefaultValues()
- {
- return insertedObjectDefaultValues();
- }
-
- /**
- * Returns the keys that were declared when read from
- * an external resource file.
- */
- public List getLocalKeys()
- {
- return localKeys();
- }
-
- /**
- * Returns the List of sort orderings for this display group.
- */
- public List getSortOrderings ()
- {
- return sortOrderings();
- }
-
- /**
- * Returns a qualifier that will be applied all the objects
- * in this display group to determine which objects will
- * be displayed.
- */
- public EOQualifier getQualifier ()
- {
- return qualifier();
- }
-
- /**
- * Returns a new qualifier built from the three query
- * value maps: greater than, equal to, and less than.
- */
- public EOQualifier getQualifierFromQueryValues ()
- {
- return qualifierFromQueryValues();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public Map getQueryBindingValues()
- {
- return queryBindingValues();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public Map getQueryOperatorValues()
- {
- return queryOperatorValues();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for equality.
- */
- public Map getEqualToQueryValues()
- {
- return equalToQueryValues();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public Map getGreaterThanQueryValues()
- {
- return greaterThanQueryValues();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public Map getLessThanQueryValues()
- {
- return lessThanQueryValues();
- }
-
- /**
- * Returns the association that is currently being edited,
- * or null if no editing is taking place.
- */
- public EOAssociation getEditingAssociation ()
- {
- return editingAssociation();
- }
-
- /**
- * Returns a List of associations that are observing
- * this display group.
- */
- public List getObservingAssociations()
- {
- return observingAssociations();
- }
-
- /**
- * Returns a List containing all objects managed by the display group.
- * This includes those objects not visible due to disqualification.
- */
- public List getAllObjects()
- {
- return allObjects();
- }
-
- /**
- * Returns a List of all objects in the display group
- * that are currently displayed by the associations.
- * The list is a copy of the internal displayed object list.
- */
- public List getDisplayedObjects()
- {
- return displayedObjects();
- }
-
- /**
- * Returns the currently selected object, or null if
- * there is no selection.
- */
- public Object getSelectedObject()
- {
- return selectedObject();
- }
-
- /**
- * Returns a List containing all selected objects, if any.
- * Returns an empty list if no objects are selected.
- */
- public List getSelectedObjects()
- {
- return selectedObjects();
- }
-
- /**
- * Returns a List containing the indexes of all selected
- * objects, if any. The list contains instances of
- * java.lang.Number; call intValue() retrieve the index.
- */
- public List getSelectionIndexes()
- {
- return selectionIndexes();
- }
-
- /**
- * Returns the index of the changed object. If more than
- * one object has changed, -1 is returned.
- */
- public int getUpdatedObjectIndex()
- {
- return updatedObjectIndex();
- }
-
- /**
- * Returns a value on the selected object for the specified key.
- */
- public Object getSelectedObjectValueForKey ( String aKey )
- {
- return selectedObjectValueForKey( aKey );
- }
-
- /**
- * Returns the value for the specified key on the specified object.
- */
- public Object getValueForObject ( Object anObject, String aKey )
- {
- return valueForObject( anObject, aKey );
- }
-
- /**
- * Calls valueForObject() for the object at the specified index.
- */
- public Object getValueForObjectAtIndex ( int anIndex, String aKey )
- {
- return valueForObjectAtIndex( anIndex, aKey );
- }
-
- /**
- * Specifies the default string matching format for all
- * display groups.
- */
- public static String getGlobalDefaultStringMatchFormat ()
- {
- return globalDefaultStringMatchFormat();
- }
-
- /**
- * Specifies the default string matching operator for all
- * display groups.
- */
- public static String getGlobalDefaultStringMatchOperator ()
- {
- return globalDefaultStringMatchOperator();
- }
-}
+ * DisplayGroup provides an abstraction of a user interface, comprising of an
+ * ordered collection of data objects, some of which are displayed, and of those
+ * some are selected. This class extends EODisplayGroup to provide java-friendly
+ * convenience methods.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class DisplayGroup extends EODisplayGroup {
+ /**
+ * Returns the current data source backing this display group, or null if no
+ * dataSource is currently used.
+ */
+ public EODataSource getDataSource() {
+ return super.dataSource();
+ }
+
+ /**
+ * Returns the current delegate for this display group, or null if no delegate
+ * is currently set.
+ */
+ public Object getDelegate() {
+ return delegate();
+ }
+
+ /**
+ * Returns the current string matching format. If not set, defaults to "%@*".
+ */
+ public String getDefaultStringMatchFormat() {
+ return defaultStringMatchFormat();
+ }
+
+ /**
+ * Returns the current string matching operator. If not set, defaults to
+ * "caseInsensitiveLike".
+ */
+ public String getdefaultStringMatchOperator() {
+ return defaultStringMatchOperator();
+ }
+
+ /**
+ * Returns a Map of default values that are applied to new objects that are
+ * inserted into the list.
+ */
+ public Map getInsertedObjectDefaultValues() {
+ return insertedObjectDefaultValues();
+ }
+
+ /**
+ * Returns the keys that were declared when read from an external resource file.
+ */
+ public List getLocalKeys() {
+ return localKeys();
+ }
+
+ /**
+ * Returns the List of sort orderings for this display group.
+ */
+ public List getSortOrderings() {
+ return sortOrderings();
+ }
+
+ /**
+ * Returns a qualifier that will be applied all the objects in this display
+ * group to determine which objects will be displayed.
+ */
+ public EOQualifier getQualifier() {
+ return qualifier();
+ }
+
+ /**
+ * Returns a new qualifier built from the three query value maps: greater than,
+ * equal to, and less than.
+ */
+ public EOQualifier getQualifierFromQueryValues() {
+ return qualifierFromQueryValues();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public Map getQueryBindingValues() {
+ return queryBindingValues();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public Map getQueryOperatorValues() {
+ return queryOperatorValues();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public Map getEqualToQueryValues() {
+ return equalToQueryValues();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for greater value.
+ */
+ public Map getGreaterThanQueryValues() {
+ return greaterThanQueryValues();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for lesser value.
+ */
+ public Map getLessThanQueryValues() {
+ return lessThanQueryValues();
+ }
+
+ /**
+ * Returns the association that is currently being edited, or null if no editing
+ * is taking place.
+ */
+ public EOAssociation getEditingAssociation() {
+ return editingAssociation();
+ }
+
+ /**
+ * Returns a List of associations that are observing this display group.
+ */
+ public List getObservingAssociations() {
+ return observingAssociations();
+ }
+
+ /**
+ * Returns a List containing all objects managed by the display group. This
+ * includes those objects not visible due to disqualification.
+ */
+ public List getAllObjects() {
+ return allObjects();
+ }
+
+ /**
+ * Returns a List of all objects in the display group that are currently
+ * displayed by the associations. The list is a copy of the internal displayed
+ * object list.
+ */
+ public List getDisplayedObjects() {
+ return displayedObjects();
+ }
+
+ /**
+ * Returns the currently selected object, or null if there is no selection.
+ */
+ public Object getSelectedObject() {
+ return selectedObject();
+ }
+
+ /**
+ * Returns a List containing all selected objects, if any. Returns an empty list
+ * if no objects are selected.
+ */
+ public List getSelectedObjects() {
+ return selectedObjects();
+ }
+
+ /**
+ * Returns a List containing the indexes of all selected objects, if any. The
+ * list contains instances of java.lang.Number; call intValue() retrieve the
+ * index.
+ */
+ public List getSelectionIndexes() {
+ return selectionIndexes();
+ }
+
+ /**
+ * Returns the index of the changed object. If more than one object has changed,
+ * -1 is returned.
+ */
+ public int getUpdatedObjectIndex() {
+ return updatedObjectIndex();
+ }
+
+ /**
+ * Returns a value on the selected object for the specified key.
+ */
+ public Object getSelectedObjectValueForKey(String aKey) {
+ return selectedObjectValueForKey(aKey);
+ }
+
+ /**
+ * Returns the value for the specified key on the specified object.
+ */
+ public Object getValueForObject(Object anObject, String aKey) {
+ return valueForObject(anObject, aKey);
+ }
+
+ /**
+ * Calls valueForObject() for the object at the specified index.
+ */
+ public Object getValueForObjectAtIndex(int anIndex, String aKey) {
+ return valueForObjectAtIndex(anIndex, aKey);
+ }
+
+ /**
+ * Specifies the default string matching format for all display groups.
+ */
+ public static String getGlobalDefaultStringMatchFormat() {
+ return globalDefaultStringMatchFormat();
+ }
+
+ /**
+ * Specifies the default string matching operator for all display groups.
+ */
+ public static String getGlobalDefaultStringMatchOperator() {
+ return globalDefaultStringMatchOperator();
+ }
+}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2002/05/17 15:01:49 mpowers
- * Implemented dynamic lookup of delegate methods so delegates no longer
- * need to implement the DisplayGroup.Delegate interface.
+ * Revision 1.2 2002/05/17 15:01:49 mpowers Implemented dynamic lookup of
+ * delegate methods so delegates no longer need to implement the
+ * DisplayGroup.Delegate interface.
*
- * Revision 1.1 2002/03/26 21:24:43 mpowers
- * Contributing DisplayGroup as convenience for people coming from java.
+ * Revision 1.1 2002/03/26 21:24:43 mpowers Contributing DisplayGroup as
+ * convenience for people coming from java.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java
index 635c5b9..8fb0527 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java
@@ -27,36 +27,34 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* Associations observe DisplayGroups and associate
-* a user interface component with one or more keys
-* on the objects in the display group. <br><br>
-*
-* Associations are created with a ui component in
-* the constructor. Then, one or more aspects are
-* bound to display groups and/or property keys with
-* the bindAspect() method. Finally, the association
-* is initialized with the establishConnection()
-* method. <br><br>
-*
-* Per the openstep convention, you do not need to
-* retain a reference to the association after it is
-* created; the association will be garbage-collected
-* when the ui component is garbage-collected. <br><br>
-*
-* (Because java components don't have delegates like
-* openstep components do, java-based associations
-* will likely need to implement some sort of listener
-* and add itself to the component's list of listeners
-* so that the component will have a strong reference
-* (and the only reference) to the association.) <br><br>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class EOAssociation extends EODelayedObserver
-{
- // aspect constants
+ * Associations observe DisplayGroups and associate a user interface component
+ * with one or more keys on the objects in the display group. <br>
+ * <br>
+ *
+ * Associations are created with a ui component in the constructor. Then, one or
+ * more aspects are bound to display groups and/or property keys with the
+ * bindAspect() method. Finally, the association is initialized with the
+ * establishConnection() method. <br>
+ * <br>
+ *
+ * Per the openstep convention, you do not need to retain a reference to the
+ * association after it is created; the association will be garbage-collected
+ * when the ui component is garbage-collected. <br>
+ * <br>
+ *
+ * (Because java components don't have delegates like openstep components do,
+ * java-based associations will likely need to implement some sort of listener
+ * and add itself to the component's list of listeners so that the component
+ * will have a strong reference (and the only reference) to the association.)
+ * <br>
+ * <br>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class EOAssociation extends EODelayedObserver {
+ // aspect constants
public static final String ActionAspect = "action";
public static final String EnabledAspect = "enabled";
public static final String SourceAspect = "source";
@@ -77,489 +75,405 @@ public class EOAssociation extends EODelayedObserver
public static final String ObjectsAspect = "objects"; // not in spec
public static final String LabelAspect = "label"; // not in spec
public static final String IconAspect = "icon"; // not in spec
-
+
public static final String AttributeAspectSignature = "A";
public static final String NullAspectSignature = "";
- public static final String AttributeToOneAspectSignature = "A1";
+ public static final String AttributeToOneAspectSignature = "A1";
public static final String ToOneAspectSignature = "1";
- public static final String AttributeToOneToManyAspectSignature = "A1M";
+ public static final String AttributeToOneToManyAspectSignature = "A1M";
public static final String ToOneToManyAspectSignature = "1M";
public static final String AttributeToManyAspectSignature = "AM";
public static final String ToManyAspectSignature = "M";
-
- protected Object control;
- protected NSMutableDictionary aspectToGroup;
- protected NSMutableDictionary aspectToKey;
-
- /**
- * Default constructor.
- */
- public EOAssociation ()
- {
- aspectToGroup = new NSMutableDictionary();
- aspectToKey = new NSMutableDictionary();
- control = null;
- }
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public EOAssociation ( Object anObject )
- {
- this();
- control = anObject;
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- int size = aspects().count();
- NSMutableArray result = new NSMutableArray();
- for ( int i = 0; i < size; i++ )
- {
- result.addObject( AttributeToOneToManyAspectSignature );
- }
- return result;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- *
- * TODO: Is this static in the WebObjects published API? If not, fix.
- */
- public static NSArray aspects ()
- {
- return new NSArray();
- }
-
- /**
- * Returns all registered subclasses of EOAssociation
- * for which usableWithObject with the specified object
- * returns true. You should only call this method on
- * the EOAssociation class.
- */
- public static NSArray associationClassesForObject (
- Object anObject )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- * This implementation returns an empty list.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
-
- /**
- * Binds the specified aspect of this association to the
- * specified key on the specified display group.
- */
- public void bindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey )
- {
+
+ protected Object control;
+ protected NSMutableDictionary aspectToGroup;
+ protected NSMutableDictionary aspectToKey;
+
+ /**
+ * Default constructor.
+ */
+ public EOAssociation() {
+ aspectToGroup = new NSMutableDictionary();
+ aspectToKey = new NSMutableDictionary();
+ control = null;
+ }
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public EOAssociation(Object anObject) {
+ this();
+ control = anObject;
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ int size = aspects().count();
+ NSMutableArray result = new NSMutableArray();
+ for (int i = 0; i < size; i++) {
+ result.addObject(AttributeToOneToManyAspectSignature);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ *
+ * TODO: Is this static in the WebObjects published API? If not, fix.
+ */
+ public static NSArray aspects() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns all registered subclasses of EOAssociation for which usableWithObject
+ * with the specified object returns true. You should only call this method on
+ * the EOAssociation class.
+ */
+ public static NSArray associationClassesForObject(Object anObject) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association. This
+ * implementation returns an empty list.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Binds the specified aspect of this association to the specified key on the
+ * specified display group.
+ */
+ public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
// unattach old group, if any
- EODisplayGroup oldGroup = displayGroupForAspect( anAspect );
- if ( oldGroup != null )
- {
- EOObserverCenter.removeObserver( this, oldGroup );
+ EODisplayGroup oldGroup = displayGroupForAspect(anAspect);
+ if (oldGroup != null) {
+ EOObserverCenter.removeObserver(this, oldGroup);
}
// attach new group
- if ( aDisplayGroup != null )
- {
- aspectToGroup.setObjectForKey( aDisplayGroup, anAspect );
- }
- else
- {
- aspectToGroup.removeObjectForKey( anAspect );
+ if (aDisplayGroup != null) {
+ aspectToGroup.setObjectForKey(aDisplayGroup, anAspect);
+ } else {
+ aspectToGroup.removeObjectForKey(anAspect);
}
// attach new key
- if ( aKey != null )
- {
- aspectToKey.setObjectForKey( aKey, anAspect );
+ if (aKey != null) {
+ aspectToKey.setObjectForKey(aKey, anAspect);
+ } else {
+ aspectToKey.removeObjectForKey(anAspect);
}
- else
- {
- aspectToKey.removeObjectForKey( anAspect );
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object, but remember to call this method.
+ * This implementation unregisters this association from observing each bound
+ * display group.
+ */
+ public void breakConnection() {
+ discardPendingNotification();
+ Enumeration e = aspectToGroup.objectEnumerator();
+ while (e.hasMoreElements()) {
+ EOObserverCenter.removeObserver(this, e.nextElement());
}
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object, but remember to call this method.
- * This implementation unregisters this association
- * from observing each bound display group.
- */
- public void breakConnection ()
- {
- discardPendingNotification();
- Enumeration e = aspectToGroup.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- EOObserverCenter.removeObserver( this, e.nextElement() );
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect. This implementation returns
+ * false.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return false;
+ }
+
+ /**
+ * Copies the binding for each aspect in this association that has a matching
+ * aspect in the specified association.
+ */
+ public void copyMatchingBindingsFromAssociation(EOAssociation anAssociation) {
+ // FIXME: this is broken: aspects() returns EOAssociation.aspects()
+ // NOTE: This is actually quite crazy - should this even be static? -ceg
+ NSMutableArray ourAspects = new NSMutableArray(this.aspects());
+ NSArray theirAspects = anAssociation.aspects();
+
+ String aspect;
+ Enumeration e = ourAspects.objectEnumerator();
+ while (e.hasMoreElements()) {
+ aspect = e.nextElement().toString();
+ if (theirAspects.containsObject(aspect)) {
+ this.bindAspect(aspect, anAssociation.displayGroupForAspect(aspect),
+ anAssociation.displayGroupKeyForAspect(aspect));
+ }
}
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- * This implementation returns false.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return false;
- }
-
- /**
- * Copies the binding for each aspect in this association
- * that has a matching aspect in the specified association.
- */
- public void copyMatchingBindingsFromAssociation (
- EOAssociation anAssociation )
- {
- //FIXME: this is broken: aspects() returns EOAssociation.aspects()
- //NOTE: This is actually quite crazy - should this even be static? -ceg
- NSMutableArray ourAspects = new NSMutableArray( this.aspects() );
- NSArray theirAspects = anAssociation.aspects();
-
- String aspect;
- Enumeration e = ourAspects.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- aspect = e.nextElement().toString();
- if ( theirAspects.containsObject( aspect ) )
- {
- this.bindAspect(
- aspect,
- anAssociation.displayGroupForAspect( aspect ),
- anAssociation.displayGroupKeyForAspect( aspect ) );
- }
- }
- }
-
- /**
- * Returns the display group that is bound the specified
- * aspect, or null if no display group is currently
- * bound to that aspect.
- */
- public EODisplayGroup displayGroupForAspect ( String anAspect )
- {
- return (EODisplayGroup) aspectToGroup.objectForKey( anAspect );
- }
-
- /**
- * Returns the key for the display group bound to the
- * specified aspect, or null if no display group is currently
- * bound to that aspect.
- */
- public String displayGroupKeyForAspect ( String anAspect )
- {
- return (String) aspectToKey.objectForKey( anAspect );
- }
-
- /**
- * The human-readable descriptive name for this association.
- * This implementation returns the class name.
- */
- public String displayName () // was static - can static method get class name?
- {
- String className = getClass().getName();
- int index = className.lastIndexOf( "." );
- if ( index == -1 ) return className;
- return className.substring( index+1 );
- }
-
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * This implementation returns true.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
- return true;
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should populate
- * their controlled object from the display group and begin
- * listening for events from their controlled object here,
- * but remember to call this method. Any existing value
- * in the controlled object will be overwritten.
- * This implementation registers this assocation to
- * observer changes to each of the bound display groups.
- */
- public void establishConnection ()
- {
- Enumeration e = aspectToGroup.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- EOObserverCenter.addObserver( this, e.nextElement() );
+ }
+
+ /**
+ * Returns the display group that is bound the specified aspect, or null if no
+ * display group is currently bound to that aspect.
+ */
+ public EODisplayGroup displayGroupForAspect(String anAspect) {
+ return (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ }
+
+ /**
+ * Returns the key for the display group bound to the specified aspect, or null
+ * if no display group is currently bound to that aspect.
+ */
+ public String displayGroupKeyForAspect(String anAspect) {
+ return (String) aspectToKey.objectForKey(anAspect);
+ }
+
+ /**
+ * The human-readable descriptive name for this association. This implementation
+ * returns the class name.
+ */
+ public String displayName() // was static - can static method get class name?
+ {
+ String className = getClass().getName();
+ int index = className.lastIndexOf(".");
+ if (index == -1)
+ return className;
+ return className.substring(index + 1);
+ }
+
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input. This implementation returns true.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ return true;
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should populate their controlled object from the display group and
+ * begin listening for events from their controlled object here, but remember to
+ * call this method. Any existing value in the controlled object will be
+ * overwritten. This implementation registers this assocation to observer
+ * changes to each of the bound display groups.
+ */
+ public void establishConnection() {
+ Enumeration e = aspectToGroup.objectEnumerator();
+ while (e.hasMoreElements()) {
+ EOObserverCenter.addObserver(this, e.nextElement());
}
- }
-
- /**
- * Returns whether this class can control the specified
- * object. This implementation returns false.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return false;
- }
-
- /**
- * Returns the object that is currently controlled by this
- * association, or null if no object is currently controlled.
- */
- public Object object ()
- {
- return control;
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- * This implementation returns an empty list.
- */
- public static NSArray objectKeysTaken ()
- {
- return new NSArray();
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- * This implementation returns null.
- */
- public static String primaryAspect ()
- {
- return null;
- }
-
- /**
- * Writes the specified value for the display group
- * and key currently bound to the specified aspect.
- * This implementation calls
- * EODisplayGroup.setSelectedObjectValue().
- * @return True if the value was successfully set,
- * otherwise false.
- */
- public boolean setValueForAspect (
- Object aValue,
- String anAspect )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return false;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return false;
-
- //FIXME: is this the right method to call
- return group.setSelectedObjectValue( aValue, key );
- }
-
-
- /**
- * Writes the specified value for the display group
- * and key currently bound to the specified aspect,
- * at the specified index (assuming it's an indexed
- * property).
- * This implementation calls
- * EODisplayGroup.setValueForObjectAtIndex().
- * @return True if the value was successfully set,
- * otherwise false.
- */
- public boolean setValueForAspectAtIndex (
- Object aValue,
- String anAspect,
- int anIndex )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return false;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return false;
-
- //FIXME: is this the right method to call?
- return group.setValueForObjectAtIndex( aValue, anIndex, key );
- }
-
- /**
- * Called by subclasses to notify that the user's input
- * failed validation. Notifies the display group for
- * the aspect, returning the result.
- * This implementation calls
- * EODisplayGroup.associationFailedToValidateValue()
- * with the display group's selected object.
- * @return True if the user should be allowed to continue,
- * meaning that the display group with handle user notification,
- * otherwise false meaning the caller should notify the user.
- */
- public boolean shouldEndEditing (
- String anAspect,
- String anInvalidInput,
- String anErrorDescription )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return false;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return false;
- return group.associationFailedToValidateValue(
- this, anInvalidInput, key,
- group.selectedObject(), //FIXME: is this correct?
- anErrorDescription );
- }
-
- /**
- * Called by subclasses to notify that the user's input
- * failed validation. Notifies the display group for
- * the aspect, returning the result.
- * This implementation calls
- * EODisplayGroup.associationFailedToValidateValue()
- * with the object in the display group's displayed
- * objects array at the specified index.
- * @return True if the user should be allowed to continue,
- * meaning that the display group with handle user notification,
- * otherwise false meaning the caller should notify the user.
- */
- public boolean shouldEndEditingAtIndex (
- String anAspect,
- String anInvalidInput,
- String anErrorDescription,
- int anIndex )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return false;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return false;
- return group.associationFailedToValidateValue(
- this, anInvalidInput, key,
- group.displayedObjects().objectAtIndex( anIndex ),
- //FIXME: is this correct?
- anErrorDescription );
- }
-
- /**
- * Called when either the selection or the contents of
- * an associated display group have changed.
- * This implementation does nothing.
- */
- public void subjectChanged ()
- {
- // does nothing
- }
-
- /**
- * Returns the current value for the display group
- * and key associated with the specified aspect.
- */
- public Object valueForAspect ( String anAspect )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return null;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return null;
-
- //FIXME: is this correct? use selected object?
- return group.valueForObject( group.selectedObject(), key );
- }
-
- /**
- * Returns the current value for the display group
- * and key associated with the specified aspect,
- * and the specified index (assuming multiple values).
- */
- public Object valueForAspectAtIndex (
- String anAspect, int anIndex )
- {
- EODisplayGroup group = (EODisplayGroup)
- aspectToGroup.objectForKey( anAspect );
- if ( group == null ) return null;
- String key = (String)
- aspectToKey.objectForKey( anAspect );
- if ( key == null ) return null;
-
- //FIXME: is this the right method to call?
- return group.valueForObjectAtIndex( anIndex, key );
- }
-
+ }
+
+ /**
+ * Returns whether this class can control the specified object. This
+ * implementation returns false.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return false;
+ }
+
+ /**
+ * Returns the object that is currently controlled by this association, or null
+ * if no object is currently controlled.
+ */
+ public Object object() {
+ return control;
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected". This implementation
+ * returns an empty list.
+ */
+ public static NSArray objectKeysTaken() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch. This implementation returns null.
+ */
+ public static String primaryAspect() {
+ return null;
+ }
+
+ /**
+ * Writes the specified value for the display group and key currently bound to
+ * the specified aspect. This implementation calls
+ * EODisplayGroup.setSelectedObjectValue().
+ *
+ * @return True if the value was successfully set, otherwise false.
+ */
+ public boolean setValueForAspect(Object aValue, String anAspect) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return false;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return false;
+
+ // FIXME: is this the right method to call
+ return group.setSelectedObjectValue(aValue, key);
+ }
+
+ /**
+ * Writes the specified value for the display group and key currently bound to
+ * the specified aspect, at the specified index (assuming it's an indexed
+ * property). This implementation calls
+ * EODisplayGroup.setValueForObjectAtIndex().
+ *
+ * @return True if the value was successfully set, otherwise false.
+ */
+ public boolean setValueForAspectAtIndex(Object aValue, String anAspect, int anIndex) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return false;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return false;
+
+ // FIXME: is this the right method to call?
+ return group.setValueForObjectAtIndex(aValue, anIndex, key);
+ }
+
+ /**
+ * Called by subclasses to notify that the user's input failed validation.
+ * Notifies the display group for the aspect, returning the result. This
+ * implementation calls EODisplayGroup.associationFailedToValidateValue() with
+ * the display group's selected object.
+ *
+ * @return True if the user should be allowed to continue, meaning that the
+ * display group with handle user notification, otherwise false meaning
+ * the caller should notify the user.
+ */
+ public boolean shouldEndEditing(String anAspect, String anInvalidInput, String anErrorDescription) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return false;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return false;
+ return group.associationFailedToValidateValue(this, anInvalidInput, key, group.selectedObject(), // FIXME: is
+ // this
+ // correct?
+ anErrorDescription);
+ }
+
+ /**
+ * Called by subclasses to notify that the user's input failed validation.
+ * Notifies the display group for the aspect, returning the result. This
+ * implementation calls EODisplayGroup.associationFailedToValidateValue() with
+ * the object in the display group's displayed objects array at the specified
+ * index.
+ *
+ * @return True if the user should be allowed to continue, meaning that the
+ * display group with handle user notification, otherwise false meaning
+ * the caller should notify the user.
+ */
+ public boolean shouldEndEditingAtIndex(String anAspect, String anInvalidInput, String anErrorDescription,
+ int anIndex) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return false;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return false;
+ return group.associationFailedToValidateValue(this, anInvalidInput, key,
+ group.displayedObjects().objectAtIndex(anIndex),
+ // FIXME: is this correct?
+ anErrorDescription);
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed. This implementation does nothing.
+ */
+ public void subjectChanged() {
+ // does nothing
+ }
+
+ /**
+ * Returns the current value for the display group and key associated with the
+ * specified aspect.
+ */
+ public Object valueForAspect(String anAspect) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return null;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return null;
+
+ // FIXME: is this correct? use selected object?
+ return group.valueForObject(group.selectedObject(), key);
+ }
+
+ /**
+ * Returns the current value for the display group and key associated with the
+ * specified aspect, and the specified index (assuming multiple values).
+ */
+ public Object valueForAspectAtIndex(String anAspect, int anIndex) {
+ EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect);
+ if (group == null)
+ return null;
+ String key = (String) aspectToKey.objectForKey(anAspect);
+ if (key == null)
+ return null;
+
+ // FIXME: is this the right method to call?
+ return group.valueForObjectAtIndex(anIndex, key);
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2005/05/11 15:21:53 cgruber
- * Change enum to enumeration, since enum is now a keyword as of Java 5.0
+ * Revision 1.7 2005/05/11 15:21:53 cgruber Change enum to enumeration, since
+ * enum is now a keyword as of Java 5.0
*
* A few other comments in the code.
*
- * Revision 1.6 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.6 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.5 2003/06/06 20:29:45 mpowers
- * Now dequeuing the association when connection is broken.
- * Coalesced change events had been processed even after breaking connection.
+ * Revision 1.5 2003/06/06 20:29:45 mpowers Now dequeuing the association when
+ * connection is broken. Coalesced change events had been processed even after
+ * breaking connection.
*
- * Revision 1.4 2001/03/06 23:43:46 mpowers
- * Implemented icon aspect for text association.
+ * Revision 1.4 2001/03/06 23:43:46 mpowers Implemented icon aspect for text
+ * association.
*
- * Revision 1.3 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.3 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.2 2001/01/25 17:46:11 mpowers
- * Clarified usage and gc expectations.
+ * Revision 1.2 2001/01/25 17:46:11 mpowers Clarified usage and gc expectations.
*
- * Revision 1.1.1.1 2000/12/21 15:48:07 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:07 mpowers Contributing wotonomy.
*
- * Revision 1.11 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.11 2000/12/20 16:25:39 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
index ed65b1c..fd80713 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
@@ -51,2309 +51,1867 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* EODisplayGroup provides an abstraction of a user interface,
-* comprising of an ordered collection of data objects, some
-* of which are displayed, and of those some are selected.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class EODisplayGroup extends Observable
- implements EOObserving, EOEditingContext.Editor
-{
- /**
- * Notification sent when the display group is about to fetch.
- */
- public static final String DisplayGroupWillFetchNotification
- = "DisplayGroupWillFetchNotification";
-
- private static boolean
- globalDefaultForValidatesChangesImmediately = true;
- private static String
- globalDefaultStringMatchFormat = "caseInsensitiveLike";
- private static String
- globalDefaultStringMatchOperator = "%@*";
-
- protected NSMutableArray allObjects;
- protected NSArray allObjectsProxy;
- protected NSMutableArray displayedObjects;
- protected NSArray displayedObjectsProxy;
- protected NSMutableArray selectedObjects;
- protected NSArray selectedObjectsProxy;
- protected NSMutableArray selectedIndexes;
-
- private String defaultStringMatchOperator;
- private String defaultStringMatchFormat;
-
- private boolean validatesChangesImmediately;
- private Object delegate;
- private EODataSource dataSource;
- private EOAssociation editingAssociation;
- private EOQualifier qualifier;
- private NSMutableArray sortOrderings;
- private NSArray sortOrderingsProxy;
-
- private NSArray localKeys;
- private NSDictionary insertedObjectDefaultValues;
- private boolean fetchesOnLoad;
- private boolean selectsFirstObjectAfterFetch;
- private boolean usesOptimisticRefresh;
- private boolean inQueryMode;
-
- // change detection: package access for helper classes
- boolean contentsChanged;
- boolean selectionChanged;
- int updatedObjectIndex;
-
- // this property is not in the spec
- private boolean compareByReference = false;
-
- private EOObserving lastGroupObserver;
-
- /**
- * Creates a new display group.
- */
- public EODisplayGroup ()
- {
- validatesChangesImmediately =
- globalDefaultForValidatesChangesImmediately();
- defaultStringMatchOperator =
- globalDefaultStringMatchFormat();
- defaultStringMatchFormat =
- globalDefaultStringMatchOperator();
-
- allObjects = new ObservableArray( this );
- allObjectsProxy = NSArray.arrayBackedByList( allObjects );
- displayedObjects = new NSMutableArray();
- displayedObjectsProxy = NSArray.arrayBackedByList( displayedObjects );
- selectedObjects = new NSMutableArray();
- selectedObjectsProxy = NSArray.arrayBackedByList( selectedObjects );
- sortOrderings = new NSMutableArray();
- sortOrderingsProxy = NSArray.arrayBackedByList( sortOrderings );
- selectedIndexes = new NSMutableArray();
-
- delegate = null;
- dataSource = null;
- editingAssociation = null;
- qualifier = null;
-
- localKeys = new NSArray(); // not implemented
- insertedObjectDefaultValues = new NSDictionary();
- fetchesOnLoad = false; // not implemented
- selectsFirstObjectAfterFetch = false;
- usesOptimisticRefresh = false;
- inQueryMode = false; // not implemented
-
- contentsChanged = false;
- selectionChanged = false;
- updatedObjectIndex = -1;
-
- // create our private delayed observer
- lastGroupObserver = new LastGroupObserver( this );
- EOObserverCenter.addObserver( lastGroupObserver, this );
- }
-
-
-
- // specify optional data source
-
- /**
- * Sets the data source that will be used by
- * this display group.
- */
- public void setDataSource ( EODataSource aDataSource )
- {
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // un-register for notifications from existing parent store
- NSNotificationCenter.defaultCenter().removeObserver(
- this, null, dataSource.editingContext() );
- dataSource.editingContext().removeEditor( this );
- if ( dataSource.editingContext().messageHandler() == this )
- {
- dataSource.editingContext().setMessageHandler( null );
- }
-
- }
-
- dataSource = aDataSource;
-
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // register for notifications from parent store
- NSNotificationCenter.defaultCenter().addObserver(
- this, new NSSelector( "objectsInvalidatedInEditingContext",
- new Class[] { NSNotification.class } ),
- null, dataSource.editingContext() );
-
- // add ourselves as editor
- dataSource.editingContext().addEditor( this );
-
- // add ourselves as message handler if no such handler exists
- if ( dataSource.editingContext().messageHandler() == null )
- {
- dataSource.editingContext().setMessageHandler( this );
- }
- }
- }
-
- /**
- * Returns the current data source backing this display group,
- * or null if no dataSource is currently used.
- */
- public EODataSource dataSource ()
- {
- return dataSource;
- }
-
-
-
- // specify optional delegate
-
- /**
- * Sets the display group delegate that
- * will be used by this display group.
- */
- public void setDelegate ( Object aDelegate )
- {
- delegate = aDelegate;
- }
-
- /**
- * Returns the current delegate for this display group,
- * or null if no delegate is currently set.
- */
- public Object delegate ()
- {
- return delegate;
- }
-
-
-
- // display group configuration
-
- /**
- * Returns the current string matching format.
- * If not set, defaults to "%@*".
- */
- public String defaultStringMatchFormat ()
- {
- return defaultStringMatchFormat;
- }
-
- /**
- * Returns the current string matching operator.
- * If not set, defaults to "caseInsensitiveLike".
- */
- public String defaultStringMatchOperator ()
- {
- return defaultStringMatchOperator;
- }
-
- /**
- * Sets the display group and associations to edit a
- * "query by example" query object. This method is
- * used for target/action connections.
- */
- public void enterQueryMode ( Object aSender )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this display group should immediate
- * fetch when loaded.
- */
- public boolean fetchesOnLoad ()
- {
- return fetchesOnLoad;
- }
-
- /**
- * Returns whether this display group is in "query by
- * example" mode.
- */
- public boolean inQueryMode ()
- {
- return inQueryMode;
- }
-
- /**
- * Returns a Map of default values that are applied
- * to new objects that are inserted into the list.
- */
- public NSDictionary insertedObjectDefaultValues ()
- {
- return insertedObjectDefaultValues;
- }
-
- /**
- * Returns the keys that were declared when read from
- * an external resource file.
- */
- public NSArray localKeys ()
- {
- return localKeys;
- }
-
- /**
- * Sets whether this display group will select the
- * first object in the list after a fetch.
- */
- public boolean selectsFirstObjectAfterFetch ()
- {
- return selectsFirstObjectAfterFetch;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by this display group.
- */
- public void setDefaultStringMatchFormat ( String aFormat )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by this display group.
- */
- public void setDefaultStringMatchOperator ( String anOperator )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether this display group will fetch objects
- * from its data source on load.
- */
- public void setFetchesOnLoad ( boolean willFetch )
- {
- fetchesOnLoad = willFetch;
- }
-
- /**
- * Sets whether this display group is in "query by example"
- * mode. If true, all associations will bind to a special
- * "example" object.
- */
- public void setInQueryMode ( boolean isInQueryMode )
- {
- inQueryMode = isInQueryMode;
- }
-
- /**
- * Sets the mapping that contains the values that will
- * be applied to new objects inserted into the display group.
- */
- public void setInsertedObjectDefaultValues ( Map aMap )
- {
- insertedObjectDefaultValues = new NSDictionary( aMap );
- }
-
- /**
- * Sets the keys that are declared when instantiated from
- * an external resource file.
- */
- public void setLocalKeys ( List aKeyList )
- {
- localKeys = new NSArray( (Collection) aKeyList );
- }
-
- /**
- * Sets whether the first object in the list will be
- * selected after a fetch.
- */
- public void setSelectsFirstObjectAfterFetch (
- boolean selectsFirst )
- {
- selectsFirstObjectAfterFetch = selectsFirst;
- }
-
- /**
- * Sets the order of the keys by which this display group
- * will be ordered after a fetch or after a call to
- * updateDisplayedObjects(). The elements in the display
- * group will be sorted first by the first key, within
- * the first key, by the second key, and so on.
- */
- public void setSortOrderings ( List aList )
- {
- sortOrderings.removeAllObjects();
-
- Object o;
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- // handle the convenience of specifying just a key
- if ( ! ( o instanceof EOSortOrdering ) )
- {
- o = new EOSortOrdering(
- o.toString(), EOSortOrdering.CompareAscending );
- }
- sortOrderings.add( o );
- }
- }
-
- /**
- * Sets whether only changed objects are refreshed (optimistic),
- * or whether all objects are refreshed (pessimistic, default).
- * By default, when the display group receives notification that
- * one of its objects has changed, updateDisplayedObjects is called.
- */
- public void setUsesOptimisticRefresh ( boolean isOptimistic )
- {
- usesOptimisticRefresh = isOptimistic;
- }
-
- /**
- * Sets whether changes made by associations are validated
- * immediately, or when changes are saved.
- */
- public void setValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- validatesChangesImmediately = validatesImmediately;
- }
-
- /**
- * Returns a read-only List of sort orderings for this display group.
- */
- public NSArray sortOrderings ()
- {
- return sortOrderingsProxy;
- }
-
- /**
- * Returns whether this display group refreshes only
- * the changed objects or all objects on refresh.
- */
- public boolean usesOptimisticRefresh ()
- {
- return usesOptimisticRefresh;
- }
-
- /**
- * Returns whether this display group validates changes
- * immediately. Otherwise, validation should occur when
- * changes are saved. Default is the global default,
- * which is initially true.
- */
- public boolean validatesChangesImmediately ()
- {
- return validatesChangesImmediately;
- }
-
-
- // qualification
-
- /**
- * Returns a qualifier that will be applied all the objects
- * in this display group to determine which objects will
- * be displayed.
- */
- public EOQualifier qualifier ()
- {
- return qualifier;
- }
-
- /**
- * Returns a new qualifier built from the three query
- * value maps: greater than, equal to, and less than.
- */
- public EOQualifier qualifierFromQueryValues ()
- {
- //TODO: assemble qualifier from query values
-
- return new EOQualifier()
- {
- // use inner class until we actually implement one
- public EOQualifier qualifierWithBindings(
- Map aMap,
- boolean requireAll )
- {
- return null;
- }
- public Throwable
- validateKeysWithRootClassDescription( Class aClass )
- {
- return null;
- }
- public boolean evaluateWithObject(Object o)
- {
- return false;
- }
- };
- }
-
- /**
- * Calls qualifierFromQueryValues(), applies the result
- * to the data source, and calls fetch().
- */
- public void qualifyDataSource ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Calls qualifierFromQueryValues(), sets the qualifier
- * with setQualifier(), and calls updateDisplayedObjects().
- */
- public void qualifyDisplayGroup ()
- {
- setQualifier( qualifierFromQueryValues() );
- updateDisplayedObjects();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSDictionary queryBindingValues ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSDictionary queryOperatorValues ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the qualifier that will be used by
- * updateDisplayedObjects() to filter displayed objects.
- */
- public void setQualifier ( EOQualifier aQualifier )
- {
- qualifier = aQualifier;
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to binding values.
- */
- public void setQueryBindingValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to operator values.
- */
- public void setQueryOperatorValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
-
-
- // qualifier query values
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for equality.
- */
- public NSDictionary equalToQueryValues ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public NSDictionary greaterThanQueryValues ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public NSDictionary lessThanQueryValues ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the Map that contains the mappings of keys
- * to query values that will be used to test for equality.
- */
- public void setEqualToQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public void setGreaterThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public void setLessThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
-
- // interface to associations
-
- /**
- * Called by an association when it begins editing.
- */
- public void associationDidBeginEditing ( EOAssociation anAssociation )
- { // System.out.println( "EODisplayGroup.associationDidBeginEditing: " + anAssociation );
- if ( dataSource != null )
- {
- if ( dataSource.editingContext() != null )
- {
- dataSource.editingContext().setMessageHandler( this );
- }
- }
- editingAssociation = anAssociation;
- }
-
- /**
- * Called by an association when it is finished editing.
- */
- public void associationDidEndEditing ( EOAssociation anAssociation )
- { // System.out.println( "EODisplayGroup.associationDidEndEditing: " + anAssociation );
- editingAssociation = null;
- }
-
- /**
- * Called by associations to determine whether the contents
- * of any objects have been changed. Returns true if the
- * contents have changed and not all observers have been
- * notified.
- */
- public boolean contentsChanged ()
- {
- return contentsChanged;
- }
-
- /**
- * Called by associations to determine whether the
- * selection has been changed. Returns true if the
- * selection has changed and not all observers have
- * been notified.
- */
- public boolean selectionChanged ()
- {
- return selectionChanged;
- }
-
- /**
- * Called by an association when a user-specified value fails the association's
- * validation rules. This implementation returns true, unless the delegate
- * prevents this.
- * @return True to allow the association to handle user notification,
- * otherwise return false to let the association know that the
- * display group notified the user.
- */
- public boolean associationFailedToValidateValue (
- EOAssociation anAssociation,
- String aValue,
- String aKey,
- Object anObject,
- String anErrorDescription )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { EODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Validation Failed", anErrorDescription } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- return true;
- }
- return false;
- }
-
- /**
- * Called by an association to determine whether it should enable
- * a component that displayes a value for the specified key.
- * @return true if an object is selected, or if
- * the specified key is a query key. Otherwise false.
- */
- public boolean enabledToSetSelectedObjectValueForKey ( String aKey )
- {
- if ( ( aKey != null ) && ( aKey.startsWith( "@" ) ) ) return true;
- return ( selectedObject() != null );
- }
-
-
- // association management
-
- /**
- * Returns the association that is currently being edited,
- * or null if no editing is taking place.
- */
- public EOAssociation editingAssociation ()
- {
- return editingAssociation;
- }
-
- /**
- * Asks the association currently editing to stop editing.
- * @returns true if editing was stopped, false if the
- * association refused to stop editing (if a modal dialog
- * is displayed or a value failed to validate).
- */
- public boolean endEditing ()
- {
- if ( editingAssociation == null ) return true;
- return editingAssociation.endEditing();
- }
-
- /**
- * Returns a read-only List of associations that are observing
- * this display group.
- */
- public NSArray observingAssociations ()
- {
- NSArray observers =
- EOObserverCenter.observersForObject( this );
- NSMutableArray result = new NSMutableArray();
-
- Object o;
- Enumeration e = observers.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- o = e.nextElement();
- if ( o instanceof EOAssociation )
- {
- result.addObject( o );
- }
- }
- return result;
- }
-
-
-
- // object management
-
- /**
- * Returns a read-only List containing all objects managed by the display group.
- * This includes those objects not visible due to disqualification.
- */
- public NSArray allObjects ()
- { //System.out.println( "avoided allocation: allObjects" );
- return allObjectsProxy;
- }
-
- /**
- * Clears the current selection.
- * @return True is the selection was cleared,
- * False if the selection could not be cleared
- * @see #setSelectionIndexes
- */
- public boolean clearSelection ()
- {
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { EODisplayGroup.class, List.class },
- new Object[] { this, new NSArray( selectedObjects ) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- selectionChanged = true;
- willChange();
-
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Deletes the object at the specified index,
- * notifying the delegate before and after the operation,
- * and then updating the selection if needed.
- * @return True if delete was successful, false if the
- * object was not deleted.
- */
- public boolean deleteObjectAtIndex ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- Object result = notifyDelegate(
- "displayGroupShouldDeleteObject",
- new Class[] { EODisplayGroup.class, Object.class },
- new Object[] { this, target } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- contentsChanged = true;
-
- deleteObjectAtIndexNoNotify( anIndex );
-
- if ( dataSource != null )
- {
- dataSource.deleteObject( target );
- }
-
- notifyDelegate(
- "displayGroupDidDeleteObject",
- new Class[] { EODisplayGroup.class, Object.class },
- new Object[] { this, target } );
-
- return true;
- }
-
- private void deleteObjectAtIndexNoNotify ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- int i;
-
- // remove from selected objects if necessary
- i = indexOf( selectedObjects, target );
- if ( i != NSArray.NotFound )
- {
- selectionChanged = true;
- willChange(); // notify before removing
- selectedObjects.removeObjectAtIndex( i );
- selectedIndexes.remove( new Integer( i ) ); // comps by value
- }
- else // notify - no selection change needed
- {
- willChange();
- }
-
- // remove from all objects
- i = indexOf( allObjects, target );
- if ( i != NSArray.NotFound )
- {
- allObjects.removeObjectAtIndex( i );
- }
- else // otherwise should never happen
- {
+ * EODisplayGroup provides an abstraction of a user interface, comprising of an
+ * ordered collection of data objects, some of which are displayed, and of those
+ * some are selected.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class EODisplayGroup extends Observable implements EOObserving, EOEditingContext.Editor {
+ /**
+ * Notification sent when the display group is about to fetch.
+ */
+ public static final String DisplayGroupWillFetchNotification = "DisplayGroupWillFetchNotification";
+
+ private static boolean globalDefaultForValidatesChangesImmediately = true;
+ private static String globalDefaultStringMatchFormat = "caseInsensitiveLike";
+ private static String globalDefaultStringMatchOperator = "%@*";
+
+ protected NSMutableArray allObjects;
+ protected NSArray allObjectsProxy;
+ protected NSMutableArray displayedObjects;
+ protected NSArray displayedObjectsProxy;
+ protected NSMutableArray selectedObjects;
+ protected NSArray selectedObjectsProxy;
+ protected NSMutableArray selectedIndexes;
+
+ private String defaultStringMatchOperator;
+ private String defaultStringMatchFormat;
+
+ private boolean validatesChangesImmediately;
+ private Object delegate;
+ private EODataSource dataSource;
+ private EOAssociation editingAssociation;
+ private EOQualifier qualifier;
+ private NSMutableArray sortOrderings;
+ private NSArray sortOrderingsProxy;
+
+ private NSArray localKeys;
+ private NSDictionary insertedObjectDefaultValues;
+ private boolean fetchesOnLoad;
+ private boolean selectsFirstObjectAfterFetch;
+ private boolean usesOptimisticRefresh;
+ private boolean inQueryMode;
+
+ // change detection: package access for helper classes
+ boolean contentsChanged;
+ boolean selectionChanged;
+ int updatedObjectIndex;
+
+ // this property is not in the spec
+ private boolean compareByReference = false;
+
+ private EOObserving lastGroupObserver;
+
+ /**
+ * Creates a new display group.
+ */
+ public EODisplayGroup() {
+ validatesChangesImmediately = globalDefaultForValidatesChangesImmediately();
+ defaultStringMatchOperator = globalDefaultStringMatchFormat();
+ defaultStringMatchFormat = globalDefaultStringMatchOperator();
+
+ allObjects = new ObservableArray(this);
+ allObjectsProxy = NSArray.arrayBackedByList(allObjects);
+ displayedObjects = new NSMutableArray();
+ displayedObjectsProxy = NSArray.arrayBackedByList(displayedObjects);
+ selectedObjects = new NSMutableArray();
+ selectedObjectsProxy = NSArray.arrayBackedByList(selectedObjects);
+ sortOrderings = new NSMutableArray();
+ sortOrderingsProxy = NSArray.arrayBackedByList(sortOrderings);
+ selectedIndexes = new NSMutableArray();
+
+ delegate = null;
+ dataSource = null;
+ editingAssociation = null;
+ qualifier = null;
+
+ localKeys = new NSArray(); // not implemented
+ insertedObjectDefaultValues = new NSDictionary();
+ fetchesOnLoad = false; // not implemented
+ selectsFirstObjectAfterFetch = false;
+ usesOptimisticRefresh = false;
+ inQueryMode = false; // not implemented
+
+ contentsChanged = false;
+ selectionChanged = false;
+ updatedObjectIndex = -1;
+
+ // create our private delayed observer
+ lastGroupObserver = new LastGroupObserver(this);
+ EOObserverCenter.addObserver(lastGroupObserver, this);
+ }
+
+ // specify optional data source
+
+ /**
+ * Sets the data source that will be used by this display group.
+ */
+ public void setDataSource(EODataSource aDataSource) {
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // un-register for notifications from existing parent store
+ NSNotificationCenter.defaultCenter().removeObserver(this, null, dataSource.editingContext());
+ dataSource.editingContext().removeEditor(this);
+ if (dataSource.editingContext().messageHandler() == this) {
+ dataSource.editingContext().setMessageHandler(null);
+ }
+
+ }
+
+ dataSource = aDataSource;
+
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // register for notifications from parent store
+ NSNotificationCenter.defaultCenter().addObserver(this,
+ new NSSelector("objectsInvalidatedInEditingContext", new Class[] { NSNotification.class }), null,
+ dataSource.editingContext());
+
+ // add ourselves as editor
+ dataSource.editingContext().addEditor(this);
+
+ // add ourselves as message handler if no such handler exists
+ if (dataSource.editingContext().messageHandler() == null) {
+ dataSource.editingContext().setMessageHandler(this);
+ }
+ }
+ }
+
+ /**
+ * Returns the current data source backing this display group, or null if no
+ * dataSource is currently used.
+ */
+ public EODataSource dataSource() {
+ return dataSource;
+ }
+
+ // specify optional delegate
+
+ /**
+ * Sets the display group delegate that will be used by this display group.
+ */
+ public void setDelegate(Object aDelegate) {
+ delegate = aDelegate;
+ }
+
+ /**
+ * Returns the current delegate for this display group, or null if no delegate
+ * is currently set.
+ */
+ public Object delegate() {
+ return delegate;
+ }
+
+ // display group configuration
+
+ /**
+ * Returns the current string matching format. If not set, defaults to "%@*".
+ */
+ public String defaultStringMatchFormat() {
+ return defaultStringMatchFormat;
+ }
+
+ /**
+ * Returns the current string matching operator. If not set, defaults to
+ * "caseInsensitiveLike".
+ */
+ public String defaultStringMatchOperator() {
+ return defaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the display group and associations to edit a "query by example" query
+ * object. This method is used for target/action connections.
+ */
+ public void enterQueryMode(Object aSender) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this display group should immediate fetch when loaded.
+ */
+ public boolean fetchesOnLoad() {
+ return fetchesOnLoad;
+ }
+
+ /**
+ * Returns whether this display group is in "query by example" mode.
+ */
+ public boolean inQueryMode() {
+ return inQueryMode;
+ }
+
+ /**
+ * Returns a Map of default values that are applied to new objects that are
+ * inserted into the list.
+ */
+ public NSDictionary insertedObjectDefaultValues() {
+ return insertedObjectDefaultValues;
+ }
+
+ /**
+ * Returns the keys that were declared when read from an external resource file.
+ */
+ public NSArray localKeys() {
+ return localKeys;
+ }
+
+ /**
+ * Sets whether this display group will select the first object in the list
+ * after a fetch.
+ */
+ public boolean selectsFirstObjectAfterFetch() {
+ return selectsFirstObjectAfterFetch;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchFormat(String aFormat) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchOperator(String anOperator) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether this display group will fetch objects from its data source on
+ * load.
+ */
+ public void setFetchesOnLoad(boolean willFetch) {
+ fetchesOnLoad = willFetch;
+ }
+
+ /**
+ * Sets whether this display group is in "query by example" mode. If true, all
+ * associations will bind to a special "example" object.
+ */
+ public void setInQueryMode(boolean isInQueryMode) {
+ inQueryMode = isInQueryMode;
+ }
+
+ /**
+ * Sets the mapping that contains the values that will be applied to new objects
+ * inserted into the display group.
+ */
+ public void setInsertedObjectDefaultValues(Map aMap) {
+ insertedObjectDefaultValues = new NSDictionary(aMap);
+ }
+
+ /**
+ * Sets the keys that are declared when instantiated from an external resource
+ * file.
+ */
+ public void setLocalKeys(List aKeyList) {
+ localKeys = new NSArray((Collection) aKeyList);
+ }
+
+ /**
+ * Sets whether the first object in the list will be selected after a fetch.
+ */
+ public void setSelectsFirstObjectAfterFetch(boolean selectsFirst) {
+ selectsFirstObjectAfterFetch = selectsFirst;
+ }
+
+ /**
+ * Sets the order of the keys by which this display group will be ordered after
+ * a fetch or after a call to updateDisplayedObjects(). The elements in the
+ * display group will be sorted first by the first key, within the first key, by
+ * the second key, and so on.
+ */
+ public void setSortOrderings(List aList) {
+ sortOrderings.removeAllObjects();
+
+ Object o;
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ // handle the convenience of specifying just a key
+ if (!(o instanceof EOSortOrdering)) {
+ o = new EOSortOrdering(o.toString(), EOSortOrdering.CompareAscending);
+ }
+ sortOrderings.add(o);
+ }
+ }
+
+ /**
+ * Sets whether only changed objects are refreshed (optimistic), or whether all
+ * objects are refreshed (pessimistic, default). By default, when the display
+ * group receives notification that one of its objects has changed,
+ * updateDisplayedObjects is called.
+ */
+ public void setUsesOptimisticRefresh(boolean isOptimistic) {
+ usesOptimisticRefresh = isOptimistic;
+ }
+
+ /**
+ * Sets whether changes made by associations are validated immediately, or when
+ * changes are saved.
+ */
+ public void setValidatesChangesImmediately(boolean validatesImmediately) {
+ validatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Returns a read-only List of sort orderings for this display group.
+ */
+ public NSArray sortOrderings() {
+ return sortOrderingsProxy;
+ }
+
+ /**
+ * Returns whether this display group refreshes only the changed objects or all
+ * objects on refresh.
+ */
+ public boolean usesOptimisticRefresh() {
+ return usesOptimisticRefresh;
+ }
+
+ /**
+ * Returns whether this display group validates changes immediately. Otherwise,
+ * validation should occur when changes are saved. Default is the global
+ * default, which is initially true.
+ */
+ public boolean validatesChangesImmediately() {
+ return validatesChangesImmediately;
+ }
+
+ // qualification
+
+ /**
+ * Returns a qualifier that will be applied all the objects in this display
+ * group to determine which objects will be displayed.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns a new qualifier built from the three query value maps: greater than,
+ * equal to, and less than.
+ */
+ public EOQualifier qualifierFromQueryValues() {
+ // TODO: assemble qualifier from query values
+
+ return new EOQualifier() {
+ // use inner class until we actually implement one
+ public EOQualifier qualifierWithBindings(Map aMap, boolean requireAll) {
+ return null;
+ }
+
+ public Throwable validateKeysWithRootClassDescription(Class aClass) {
+ return null;
+ }
+
+ public boolean evaluateWithObject(Object o) {
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), applies the result to the data source, and
+ * calls fetch().
+ */
+ public void qualifyDataSource() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), sets the qualifier with setQualifier(), and
+ * calls updateDisplayedObjects().
+ */
+ public void qualifyDisplayGroup() {
+ setQualifier(qualifierFromQueryValues());
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSDictionary queryBindingValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSDictionary queryOperatorValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the qualifier that will be used by updateDisplayedObjects() to filter
+ * displayed objects.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to binding values.
+ */
+ public void setQueryBindingValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to operator values.
+ */
+ public void setQueryOperatorValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ // qualifier query values
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public NSDictionary equalToQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for greater value.
+ */
+ public NSDictionary greaterThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for lesser value.
+ */
+ public NSDictionary lessThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the Map that contains the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public void setEqualToQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for greater value.
+ */
+ public void setGreaterThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for lesser value.
+ */
+ public void setLessThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ // interface to associations
+
+ /**
+ * Called by an association when it begins editing.
+ */
+ public void associationDidBeginEditing(EOAssociation anAssociation) { // System.out.println(
+ // "EODisplayGroup.associationDidBeginEditing:
+ // " + anAssociation );
+ if (dataSource != null) {
+ if (dataSource.editingContext() != null) {
+ dataSource.editingContext().setMessageHandler(this);
+ }
+ }
+ editingAssociation = anAssociation;
+ }
+
+ /**
+ * Called by an association when it is finished editing.
+ */
+ public void associationDidEndEditing(EOAssociation anAssociation) { // System.out.println(
+ // "EODisplayGroup.associationDidEndEditing: " +
+ // anAssociation );
+ editingAssociation = null;
+ }
+
+ /**
+ * Called by associations to determine whether the contents of any objects have
+ * been changed. Returns true if the contents have changed and not all observers
+ * have been notified.
+ */
+ public boolean contentsChanged() {
+ return contentsChanged;
+ }
+
+ /**
+ * Called by associations to determine whether the selection has been changed.
+ * Returns true if the selection has changed and not all observers have been
+ * notified.
+ */
+ public boolean selectionChanged() {
+ return selectionChanged;
+ }
+
+ /**
+ * Called by an association when a user-specified value fails the association's
+ * validation rules. This implementation returns true, unless the delegate
+ * prevents this.
+ *
+ * @return True to allow the association to handle user notification, otherwise
+ * return false to let the association know that the display group
+ * notified the user.
+ */
+ public boolean associationFailedToValidateValue(EOAssociation anAssociation, String aValue, String aKey,
+ Object anObject, String anErrorDescription) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { EODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Validation Failed", anErrorDescription });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Called by an association to determine whether it should enable a component
+ * that displayes a value for the specified key.
+ *
+ * @return true if an object is selected, or if the specified key is a query
+ * key. Otherwise false.
+ */
+ public boolean enabledToSetSelectedObjectValueForKey(String aKey) {
+ if ((aKey != null) && (aKey.startsWith("@")))
+ return true;
+ return (selectedObject() != null);
+ }
+
+ // association management
+
+ /**
+ * Returns the association that is currently being edited, or null if no editing
+ * is taking place.
+ */
+ public EOAssociation editingAssociation() {
+ return editingAssociation;
+ }
+
+ /**
+ * Asks the association currently editing to stop editing.
+ *
+ * @returns true if editing was stopped, false if the association refused to
+ * stop editing (if a modal dialog is displayed or a value failed to
+ * validate).
+ */
+ public boolean endEditing() {
+ if (editingAssociation == null)
+ return true;
+ return editingAssociation.endEditing();
+ }
+
+ /**
+ * Returns a read-only List of associations that are observing this display
+ * group.
+ */
+ public NSArray observingAssociations() {
+ NSArray observers = EOObserverCenter.observersForObject(this);
+ NSMutableArray result = new NSMutableArray();
+
+ Object o;
+ Enumeration e = observers.objectEnumerator();
+ while (e.hasMoreElements()) {
+ o = e.nextElement();
+ if (o instanceof EOAssociation) {
+ result.addObject(o);
+ }
+ }
+ return result;
+ }
+
+ // object management
+
+ /**
+ * Returns a read-only List containing all objects managed by the display group.
+ * This includes those objects not visible due to disqualification.
+ */
+ public NSArray allObjects() { // System.out.println( "avoided allocation: allObjects" );
+ return allObjectsProxy;
+ }
+
+ /**
+ * Clears the current selection.
+ *
+ * @return True is the selection was cleared, False if the selection could not
+ * be cleared
+ * @see #setSelectionIndexes
+ */
+ public boolean clearSelection() {
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { EODisplayGroup.class, List.class }, new Object[] { this, new NSArray(selectedObjects) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ selectionChanged = true;
+ willChange();
+
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { EODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Deletes the object at the specified index, notifying the delegate before and
+ * after the operation, and then updating the selection if needed.
+ *
+ * @return True if delete was successful, false if the object was not deleted.
+ */
+ public boolean deleteObjectAtIndex(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ Object result = notifyDelegate("displayGroupShouldDeleteObject",
+ new Class[] { EODisplayGroup.class, Object.class }, new Object[] { this, target });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ contentsChanged = true;
+
+ deleteObjectAtIndexNoNotify(anIndex);
+
+ if (dataSource != null) {
+ dataSource.deleteObject(target);
+ }
+
+ notifyDelegate("displayGroupDidDeleteObject", new Class[] { EODisplayGroup.class, Object.class },
+ new Object[] { this, target });
+
+ return true;
+ }
+
+ private void deleteObjectAtIndexNoNotify(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ int i;
+
+ // remove from selected objects if necessary
+ i = indexOf(selectedObjects, target);
+ if (i != NSArray.NotFound) {
+ selectionChanged = true;
+ willChange(); // notify before removing
+ selectedObjects.removeObjectAtIndex(i);
+ selectedIndexes.remove(new Integer(i)); // comps by value
+ } else // notify - no selection change needed
+ {
+ willChange();
+ }
+
+ // remove from all objects
+ i = indexOf(allObjects, target);
+ if (i != NSArray.NotFound) {
+ allObjects.removeObjectAtIndex(i);
+ } else // otherwise should never happen
+ {
// throw new WotonomyException(
// "Displayed object not found in allObjects" );
- }
-
- // remove from displayed objects
- displayedObjects.removeObjectAtIndex( anIndex );
- }
-
- /**
- * Deletes the currently selected objects.
- * This implementation calls deleteObjectAtIndex() for
- * each index in the selection list, immediately returning
- * false if any delete operation fails.
- * @return True if all selected objects were deleted,
- * false if any deletion failed.
- */
- public boolean deleteSelection ()
- {
- int i;
- boolean result = true;
-
- Enumeration e = new NSArray( selectedObjects ).objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i == NSArray.NotFound )
- {
- // should never happen
- throw new WotonomyException(
- "Selected object not found in displayedObjects" );
- }
- result = result && deleteObjectAtIndex( i );
- }
-
- return result;
- }
-
- /**
- * Returns a read-only List of all objects in the display group
- * that are currently displayed by the associations.
- */
- public NSArray displayedObjects ()
- { // System.out.println( "avoided allocation: displayedObjects" );
- return displayedObjectsProxy;
- }
-
- /**
- * Requests a list of objects from the DataSource
- * and calls setObjectArray to populate the list.
- * More specifically, calls endEditing(), asks the
- * delegate, fetches the objects, notifies the delegate,
- * and populates the list.
- */
- public boolean fetch ()
- {
- endEditing();
-
- if ( dataSource == null )
- {
- return false;
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldFetch",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- NSNotificationCenter.defaultCenter().postNotification(
- DisplayGroupWillFetchNotification, this, new NSDictionary() );
-
- NSArray objectList = dataSource.fetchObjects();
-
- notifyDelegate(
- "displayGroupDidFetchObjects",
- new Class[] { EODisplayGroup.class, List.class },
- new Object[] { this, objectList } );
-
- if ( selectsFirstObjectAfterFetch )
- {
- //note: there's a good chance this logic ought to be in master-detail assoc:
- // we're doing this because changes in the master object trigger a refetch
- // on the child display group which annoyingly changes the selection.
- NSArray original = new NSArray( allObjects );
- setObjectArray( objectList );
- if ( displayedObjects.size() > 0
- && !original.equals( allObjects ) ) // don't change if no change
- {
- setSelectionIndexes( new NSArray( new Integer( 0 ) ) );
- }
- }
- else
- {
- setObjectArray( objectList );
- }
-
- return true;
- }
-
- /**
- * Creates a new object at the specified index.
- * Calls insertObjectAtIndex() with the result
- * from sending createObject() to the data source.
- * Presents a JOptionPane if the create fails, unless
- * the delegate implements displayGroupCreateObjectFailed.
- * @return the newly created object.
- */
- public Object insertNewObjectAtIndex ( int anIndex )
- {
- Object result = null;
- if ( dataSource != null )
- {
- result = dataSource.createObject();
- }
- if ( result != null )
- {
- if ( insertedObjectDefaultValues != null )
- {
- Duplicator.writePropertiesForObject(
- insertedObjectDefaultValues, result );
- }
- insertObjectAtIndex( result, anIndex );
- }
- else // create failed
- {
- if ( delegate() != null )
- {
- NSSelector selector = new NSSelector(
- "displayGroupCreateObjectFailed",
- new Class[] { EODisplayGroup.class, EODataSource.class } );
- if ( selector.implementedByObject( delegate() ) )
- {
- try
- {
- selector.invoke( delegate(), new Object[] { this, dataSource } );
- return result;
- }
- catch ( Exception exc )
- {
- System.err.println( "Error notifying delegate: displayGroupCreateObjectFailed" );
- exc.printStackTrace();
- }
- }
- }
-
- // no delegate or delegate does not implement displayGroupCreateObjectFailed
-
- String message = "Data source could not create new object";
- Object delegateResult = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { EODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", message } );
- if ( ( delegateResult == null ) || ( Boolean.TRUE.equals( delegateResult ) ) )
- {
- JOptionPane.showMessageDialog( null, message );
- }
- }
- return result;
- }
-
- /**
- * Inserts the specified object into the list at
- * the specified index.
- */
- public void insertObjectAtIndex ( Object anObject, int anIndex )
- {
- Object result = notifyDelegate(
- "displayGroupShouldInsertObject",
- new Class[] { EODisplayGroup.class, Object.class, int.class },
- new Object[] { this, anObject, new Integer(anIndex) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return;
- }
-
- contentsChanged = true;
- updatedObjectIndex = anIndex;
- willChange();
-
-
- // add to all objects
- if ( anIndex == displayedObjects.size() )
- {
- allObjects.addObject( anObject );
- }
- else // insert before same object
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
- int targetIndex = indexOf( allObjects, target );
- if ( targetIndex != NSArray.NotFound )
- {
- allObjects.insertObjectAtIndex( anObject, targetIndex );
- }
- else // should never happen
- {
- throw new WotonomyException(
- "Could not find displayed object in all objects list: "
- + target );
- }
- }
-
- // add to displayed objects
- displayedObjects.insertObjectAtIndex( anObject, anIndex );
-
- if ( dataSource != null )
- {
- if ( dataSource instanceof OrderedDataSource )
- {
- ((OrderedDataSource)dataSource).insertObjectAtIndex(
- anObject, anIndex );
- }
- else
- {
- dataSource.insertObject( anObject );
- }
- }
-
- notifyDelegate(
- "displayGroupDidInsertObject",
- new Class[] { EODisplayGroup.class, Object.class },
- new Object[] { this, anObject } );
- }
-
- /**
- * Sets contentsChanged to true and notifies all observers.
- */
- public void redisplay ()
- {
- contentsChanged = true;
- willChange();
- }
-
- /**
- * Sets the selection to the next displayed object after the current
- * selection. If the last object is selected, or if no object
- * is selected, then the first object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return true if an object was selected.
- */
- public boolean selectNext ()
- {
- int count = displayedObjects.count();
- if ( count == 0 ) return false;
- if ( count == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return true;
- }
-
- int i = -1;
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = -1;
-
- // select next object
- i++;
- if ( i != displayedObjects.count() )
- {
- // set to next object
- selectedObject = displayedObjects.objectAtIndex( i );
- }
- else // out of range
- {
- // set to null
- selectedObject = displayedObjects.objectAtIndex( 0 );
- }
-
- return selectObject( selectedObject );
- }
-
- /**
- * Sets the selection to the specified object.
- * If the specified object is null or does not exist
- * in the list of displayed objects, the selection
- * will be cleared.
- * @return true if the object was selected.
- */
- public boolean selectObject ( Object anObject )
- {
- if ( ( anObject == null ) ||
- ( indexOf( displayedObjects, anObject )
- == NSArray.NotFound ) )
- {
- clearSelection();
- return false;
- }
-
- selectObjectsIdenticalTo( new NSArray( new Object[] { anObject } ) );
- return true;
- }
-
- /**
- * Sets the selection to the specified objects.
- * If the specified list is null or if none of the objects
- * in the list exist in the list of displayed objects, the
- * selection will be cleared.
- * @return true if all specified objects were selected.
- */
- public boolean selectObjectsIdenticalTo ( List anObjectList )
- {
- // optimization: check for resetting of selection
- if ( ( anObjectList != null ) && ( selectedObjects.size() == anObjectList.size() ) )
- {
- boolean identical = true;
- int size = selectedObjects.size();
- for ( int i = 0; ( i < size ) && identical; i++ )
- {
- // compare by reference
- if ( anObjectList.get( i ) != selectedObjects.get( i ) )
- {
- identical = false;
- }
- else if ( displayedObjects.indexOfIdenticalObject(
- anObjectList.get( i ) ) == NSArray.NotFound )
- {
- identical = false;
- }
- }
- if ( identical )
- {
- return true;
- }
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { EODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- // need to notify the calling component
- // to revert back to the previous selection
- selectionChanged = true;
- willChange();
- return false;
- }
-
- int i;
- selectionChanged = true;
- willChange();
- Object o;
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- != NSArray.NotFound )
- {
- selectedObjects.addObject( o );
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Sets the selection to the previous displayed object before the current
- * selection. If the first object is selected, or if no object
- * is selected, then the last object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return true if an object was selected.
- */
- public boolean selectPrevious ()
- {
- int i = displayedObjects.count();
- if ( i == 0 ) return false;
- if ( i == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return true;
- }
-
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = displayedObjects.count();
-
- // select next object
- i--;
- if ( i < 0 )
- {
- // out of range - select last object
- i = displayedObjects.count() - 1;
- }
-
- return selectObject( displayedObjects.objectAtIndex( i ) );
- }
-
- /**
- * Returns the currently selected object, or null if
- * there is no selection.
- */
- public Object selectedObject ()
- {
- if ( selectedObjects.count() == 0 )
- {
- return null;
- }
- return selectedObjects.objectAtIndex( 0 );
- }
-
- /**
- * Returns a read-only List containing all selected objects, if any.
- * Returns an empty list if no objects are selected.
- */
- public NSArray selectedObjects ()
- { // System.out.println( "avoided allocation: selectedObjects" );
- return selectedObjectsProxy;
- }
-
- /**
- * Returns a read-only List containing the indexes of all selected
- * objects, if any. The list contains instances of
- * java.lang.Number; call intValue() to retrieve the index.
- */
- public NSArray selectionIndexes ()
- {
+ }
+
+ // remove from displayed objects
+ displayedObjects.removeObjectAtIndex(anIndex);
+ }
+
+ /**
+ * Deletes the currently selected objects. This implementation calls
+ * deleteObjectAtIndex() for each index in the selection list, immediately
+ * returning false if any delete operation fails.
+ *
+ * @return True if all selected objects were deleted, false if any deletion
+ * failed.
+ */
+ public boolean deleteSelection() {
+ int i;
+ boolean result = true;
+
+ Enumeration e = new NSArray(selectedObjects).objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i == NSArray.NotFound) {
+ // should never happen
+ throw new WotonomyException("Selected object not found in displayedObjects");
+ }
+ result = result && deleteObjectAtIndex(i);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a read-only List of all objects in the display group that are
+ * currently displayed by the associations.
+ */
+ public NSArray displayedObjects() { // System.out.println( "avoided allocation: displayedObjects" );
+ return displayedObjectsProxy;
+ }
+
+ /**
+ * Requests a list of objects from the DataSource and calls setObjectArray to
+ * populate the list. More specifically, calls endEditing(), asks the delegate,
+ * fetches the objects, notifies the delegate, and populates the list.
+ */
+ public boolean fetch() {
+ endEditing();
+
+ if (dataSource == null) {
+ return false;
+ }
+
+ Object result = notifyDelegate("displayGroupShouldFetch", new Class[] { EODisplayGroup.class },
+ new Object[] { this });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ NSNotificationCenter.defaultCenter().postNotification(DisplayGroupWillFetchNotification, this,
+ new NSDictionary());
+
+ NSArray objectList = dataSource.fetchObjects();
+
+ notifyDelegate("displayGroupDidFetchObjects", new Class[] { EODisplayGroup.class, List.class },
+ new Object[] { this, objectList });
+
+ if (selectsFirstObjectAfterFetch) {
+ // note: there's a good chance this logic ought to be in master-detail assoc:
+ // we're doing this because changes in the master object trigger a refetch
+ // on the child display group which annoyingly changes the selection.
+ NSArray original = new NSArray(allObjects);
+ setObjectArray(objectList);
+ if (displayedObjects.size() > 0 && !original.equals(allObjects)) // don't change if no change
+ {
+ setSelectionIndexes(new NSArray(new Integer(0)));
+ }
+ } else {
+ setObjectArray(objectList);
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates a new object at the specified index. Calls insertObjectAtIndex() with
+ * the result from sending createObject() to the data source. Presents a
+ * JOptionPane if the create fails, unless the delegate implements
+ * displayGroupCreateObjectFailed.
+ *
+ * @return the newly created object.
+ */
+ public Object insertNewObjectAtIndex(int anIndex) {
+ Object result = null;
+ if (dataSource != null) {
+ result = dataSource.createObject();
+ }
+ if (result != null) {
+ if (insertedObjectDefaultValues != null) {
+ Duplicator.writePropertiesForObject(insertedObjectDefaultValues, result);
+ }
+ insertObjectAtIndex(result, anIndex);
+ } else // create failed
+ {
+ if (delegate() != null) {
+ NSSelector selector = new NSSelector("displayGroupCreateObjectFailed",
+ new Class[] { EODisplayGroup.class, EODataSource.class });
+ if (selector.implementedByObject(delegate())) {
+ try {
+ selector.invoke(delegate(), new Object[] { this, dataSource });
+ return result;
+ } catch (Exception exc) {
+ System.err.println("Error notifying delegate: displayGroupCreateObjectFailed");
+ exc.printStackTrace();
+ }
+ }
+ }
+
+ // no delegate or delegate does not implement displayGroupCreateObjectFailed
+
+ String message = "Data source could not create new object";
+ Object delegateResult = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { EODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", message });
+ if ((delegateResult == null) || (Boolean.TRUE.equals(delegateResult))) {
+ JOptionPane.showMessageDialog(null, message);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified object into the list at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ Object result = notifyDelegate("displayGroupShouldInsertObject",
+ new Class[] { EODisplayGroup.class, Object.class, int.class },
+ new Object[] { this, anObject, new Integer(anIndex) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return;
+ }
+
+ contentsChanged = true;
+ updatedObjectIndex = anIndex;
+ willChange();
+
+ // add to all objects
+ if (anIndex == displayedObjects.size()) {
+ allObjects.addObject(anObject);
+ } else // insert before same object
+ {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+ int targetIndex = indexOf(allObjects, target);
+ if (targetIndex != NSArray.NotFound) {
+ allObjects.insertObjectAtIndex(anObject, targetIndex);
+ } else // should never happen
+ {
+ throw new WotonomyException("Could not find displayed object in all objects list: " + target);
+ }
+ }
+
+ // add to displayed objects
+ displayedObjects.insertObjectAtIndex(anObject, anIndex);
+
+ if (dataSource != null) {
+ if (dataSource instanceof OrderedDataSource) {
+ ((OrderedDataSource) dataSource).insertObjectAtIndex(anObject, anIndex);
+ } else {
+ dataSource.insertObject(anObject);
+ }
+ }
+
+ notifyDelegate("displayGroupDidInsertObject", new Class[] { EODisplayGroup.class, Object.class },
+ new Object[] { this, anObject });
+ }
+
+ /**
+ * Sets contentsChanged to true and notifies all observers.
+ */
+ public void redisplay() {
+ contentsChanged = true;
+ willChange();
+ }
+
+ /**
+ * Sets the selection to the next displayed object after the current selection.
+ * If the last object is selected, or if no object is selected, then the first
+ * object becomes selected. If multiple items are selected, the first selected
+ * item is considered the selected item for the purposes of this method. Does
+ * not call redisplay().
+ *
+ * @return true if an object was selected.
+ */
+ public boolean selectNext() {
+ int count = displayedObjects.count();
+ if (count == 0)
+ return false;
+ if (count == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return true;
+ }
+
+ int i = -1;
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = -1;
+
+ // select next object
+ i++;
+ if (i != displayedObjects.count()) {
+ // set to next object
+ selectedObject = displayedObjects.objectAtIndex(i);
+ } else // out of range
+ {
+ // set to null
+ selectedObject = displayedObjects.objectAtIndex(0);
+ }
+
+ return selectObject(selectedObject);
+ }
+
+ /**
+ * Sets the selection to the specified object. If the specified object is null
+ * or does not exist in the list of displayed objects, the selection will be
+ * cleared.
+ *
+ * @return true if the object was selected.
+ */
+ public boolean selectObject(Object anObject) {
+ if ((anObject == null) || (indexOf(displayedObjects, anObject) == NSArray.NotFound)) {
+ clearSelection();
+ return false;
+ }
+
+ selectObjectsIdenticalTo(new NSArray(new Object[] { anObject }));
+ return true;
+ }
+
+ /**
+ * Sets the selection to the specified objects. If the specified list is null or
+ * if none of the objects in the list exist in the list of displayed objects,
+ * the selection will be cleared.
+ *
+ * @return true if all specified objects were selected.
+ */
+ public boolean selectObjectsIdenticalTo(List anObjectList) {
+ // optimization: check for resetting of selection
+ if ((anObjectList != null) && (selectedObjects.size() == anObjectList.size())) {
+ boolean identical = true;
+ int size = selectedObjects.size();
+ for (int i = 0; (i < size) && identical; i++) {
+ // compare by reference
+ if (anObjectList.get(i) != selectedObjects.get(i)) {
+ identical = false;
+ } else if (displayedObjects.indexOfIdenticalObject(anObjectList.get(i)) == NSArray.NotFound) {
+ identical = false;
+ }
+ }
+ if (identical) {
+ return true;
+ }
+ }
+
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { EODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ // need to notify the calling component
+ // to revert back to the previous selection
+ selectionChanged = true;
+ willChange();
+ return false;
+ }
+
+ int i;
+ selectionChanged = true;
+ willChange();
+ Object o;
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) != NSArray.NotFound) {
+ selectedObjects.addObject(o);
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { EODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Sets the selection to the previous displayed object before the current
+ * selection. If the first object is selected, or if no object is selected, then
+ * the last object becomes selected. If multiple items are selected, the first
+ * selected item is considered the selected item for the purposes of this
+ * method. Does not call redisplay().
+ *
+ * @return true if an object was selected.
+ */
+ public boolean selectPrevious() {
+ int i = displayedObjects.count();
+ if (i == 0)
+ return false;
+ if (i == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return true;
+ }
+
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = displayedObjects.count();
+
+ // select next object
+ i--;
+ if (i < 0) {
+ // out of range - select last object
+ i = displayedObjects.count() - 1;
+ }
+
+ return selectObject(displayedObjects.objectAtIndex(i));
+ }
+
+ /**
+ * Returns the currently selected object, or null if there is no selection.
+ */
+ public Object selectedObject() {
+ if (selectedObjects.count() == 0) {
+ return null;
+ }
+ return selectedObjects.objectAtIndex(0);
+ }
+
+ /**
+ * Returns a read-only List containing all selected objects, if any. Returns an
+ * empty list if no objects are selected.
+ */
+ public NSArray selectedObjects() { // System.out.println( "avoided allocation: selectedObjects" );
+ return selectedObjectsProxy;
+ }
+
+ /**
+ * Returns a read-only List containing the indexes of all selected objects, if
+ * any. The list contains instances of java.lang.Number; call intValue() to
+ * retrieve the index.
+ */
+ public NSArray selectionIndexes() {
// return selectedIndexes;
- int i;
- NSMutableArray result = new NSMutableArray();
- Enumeration e = selectedObjects.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i != NSArray.NotFound )
- {
- result.addObject( new Integer( i ) );
- }
- else
- {
- System.err.println(
- "Should never happen: selected objects not in displayed objects" );
- new RuntimeException().printStackTrace( System.err );
- }
- }
- return result;
- }
-
- /**
- * Sets the objects managed by this display group.
- * updateDisplayedObjects() is called to filter the
- * display objects. The previous selection will be
- * maintained if possible. The data source is not
- * notified.
- */
- public void setObjectArray ( List anObjectList )
- {
- if ( anObjectList == null ) anObjectList = new NSArray();
-
- Object result = notifyDelegate(
- "displayGroupDisplayArrayForObjects",
- new Class[] { EODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( result != null )
- {
- anObjectList = (List) result;
- }
-
- contentsChanged = true;
- willChange();
-
- NSArray oldSelectedObjects = new NSArray( selectedObjects ); // copy
-
- // reset allObjects to new list
- allObjects.removeAllObjects();
- allObjects.addObjectsFromArray( anObjectList );
-
- // update the displayed object list
- updateDisplayedObjects();
-
- // restore the selection if possible
- selectObjectsIdenticalTo( oldSelectedObjects );
- }
-
- /**
- * Sets the currently selected object, or clears the
- * selection if the object is not found or is null.
- * Note: it's not clear how this differs from
- * selectObject in the spec. It is recommended that
- * you call selectObject for now.
- */
- public void setSelectedObject ( Object anObject )
- {
- selectObject( anObject );
- }
-
- /**
- * Sets the current selection to the specified objects.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- * Note: it's not clear how this differs from
- * selectObjectsIdenticalTo in the spec.
- * It is recommended that you call that method for now.
- */
- public void setSelectedObjects ( List aList )
- {
- selectObjectsIdenticalTo( aList );
- }
-
- /**
- * Sets the current selection to the objects at the
- * specified indexes. Items in the list are assumed
- * to be instances of java.lang.Number.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- */
- public boolean setSelectionIndexes ( List aList )
- {
- Object o;
- int index;
- NSMutableArray objects = new NSMutableArray();
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- index = ((Number)it.next()).intValue();
- if ( index < displayedObjects.count() )
- {
- o = displayedObjects.objectAtIndex( index );
- if ( o != null )
- {
- objects.add( o );
- }
- }
- }
- return selectObjectsIdenticalTo( objects );
- }
-
- /**
- * Applies the qualifier to all objects and sorts
- * the results to update the list of displayed objects.
- * Observing associations are notified to reflect the changes.
- */
- public void updateDisplayedObjects ()
- {
- contentsChanged = true;
- updatedObjectIndex = -1;
- willChange();
-
- displayedObjects.removeAllObjects();
-
- displayedObjects.addObjectsFromArray( allObjects );
-
- // apply qualifier, if any
- if ( qualifier() != null )
- {
- EOQualifier.filterArrayWithQualifier(
- displayedObjects, qualifier() );
- }
-
- // apply sort orderings, if any
- NSArray orderings = sortOrderings();
- if ( orderings != null )
- {
- if ( orderings.count() > 0 )
- {
- selectionChanged = true;
- willChange();
- EOSortOrdering.sortArrayUsingKeyOrderArray(
- displayedObjects, orderings );
- }
- }
-
- // make sure the selectedObjects is a subset of displayedObjects
- int i;
- Object o;
- Iterator it = new LinkedList( selectedObjects ).iterator();
- boolean removeflag = false;
- selectedIndexes.removeAllObjects();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- == NSArray.NotFound )
- {
- selectedObjects.removeIdenticalObject( o );
- removeflag = true;
- }
- else
- {
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- //Note: it is important to put the
- //selectionChanged = true line below remove.
- if (removeflag)
- {
- selectionChanged = true;
- willChange();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { EODisplayGroup.class },
- new Object[] { this } );
- }
- }
-
- /**
- * Returns the index of the changed object. If more than
- * one object has changed, -1 is returned.
- */
- public int updatedObjectIndex ()
- {
- return updatedObjectIndex;
- }
-
- // getting and setting values in objects
-
- /**
- * Returns a value on the selected object for the specified key.
- */
- public Object selectedObjectValueForKey ( String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return null;
- return valueForObject( selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * all selected objects.
- */
- public boolean setSelectedObjectValue (
- Object aValue, String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return false;
- return setValueForObject( aValue, selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * the specified object. Validations may be triggered,
- * and error dialogs may appear to the user.
- * @return True if the value was set successfully,
- * false if the value could not be set and the update
- * operation should not continue.
- */
- public boolean setValueForObject (
- Object aValue, Object anObject, String aKey )
- {
- // notify object's observers:
- // this includes us, and will notify our observers
- EOObserverCenter.notifyObserversObjectWillChange( anObject );
-
- //TODO: if key is null, need to remove old object
- // and add new object instead of simply replacing it.
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( anObject, aValue, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { EODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return false;
- }
-
- notifyDelegate(
- "displayGroupDidSetValueForObject",
- new Class[] { EODisplayGroup.class, Object.class, Object.class, String.class },
- new Object[] { this, aValue, anObject, aKey } );
-
- return true;
- }
-
- /**
- * Calls setValueForObject() for the object at
- * the specified index.
- */
- public boolean setValueForObjectAtIndex (
- Object aValue, int anIndex, String aKey )
- {
- return setValueForObject(
- aValue, displayedObjects.objectAtIndex( anIndex ), aKey );
- }
-
- /**
- * Returns the value for the specified key on the specified object.
- */
- public Object valueForObject ( Object anObject, String aKey )
- {
- // empty string is considered the identity property
- if ( aKey == null ) return anObject;
- if ( aKey.equals( "" ) ) return anObject;
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)anObject).valueForKey( aKey );
- }
- else
- {
- return EOKeyValueCodingSupport.valueForKey( anObject, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { EODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return null;
- }
- }
-
- /**
- * Calls valueForObject() for the object at the specified index.
- */
- public Object valueForObjectAtIndex ( int anIndex, String aKey )
- {
- Object o = displayedObjects.objectAtIndex( anIndex );
- return valueForObject( o, aKey );
- }
-
- /**
- * Prints out the list of displayed objects.
- */
- public String toString()
- {
- return displayedObjects.toString();
- }
-
-
- /**
- * Handles notifications from the data source's editing context,
- * looking for InvalidatedAllObjectsInStoreNotification and
- * ObjectsChangedInEditingContextNotification, refetching in
- * the former case and updating displayed objects in the latter.
- * Note: This method is not in the public specification.
- */
- public void objectsInvalidatedInEditingContext( NSNotification aNotification )
- {
- if ( EOObjectStore.InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRefetch",
- new Class[] { EODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- fetch();
- }
- }
- else
- if ( EOEditingContext.ObjectsChangedInEditingContextNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRedisplay",
- new Class[] { EODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- int index;
- Enumeration e;
- boolean didChange = false;
- NSDictionary userInfo = aNotification.userInfo();
-
- // inserts are ignored
-
- // mark updated objects as updated
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- e = updates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "EODisplayGroup: updated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- contentsChanged = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // treat invalidated objects as updated
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- e = invalidates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "EODisplayGroup: invalidated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- contentsChanged = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // remove deletes from display group if they exist
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- e = deletes.objectEnumerator();
- Object o;
- while ( e.hasMoreElements() )
- {
- o = e.nextElement();
- index = indexOf( displayedObjects, o );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "EODisplayGroup: deleted: " + o );
- deleteObjectAtIndexNoNotify( index );
- }
- }
-
- if ( !usesOptimisticRefresh() )
- {
- updateDisplayedObjects();
- }
- }
- }
-
- }
-
- // static methods
-
- /**
- * Specifies the default behavior for whether changes
- * should be validated immediately for all display groups.
- */
- public static boolean
- globalDefaultForValidatesChangesImmediately ()
- {
- return globalDefaultForValidatesChangesImmediately;
- }
-
- /**
- * Specifies the default string matching format for all
- * display groups.
- */
- public static String globalDefaultStringMatchFormat ()
- {
- return globalDefaultStringMatchFormat;
- }
-
- /**
- * Specifies the default string matching operator for all
- * display groups.
- */
- public static String globalDefaultStringMatchOperator ()
- {
- return globalDefaultStringMatchOperator;
- }
-
- /**
- * Sets the default behavior for validating changes
- * for all display groups.
- */
- public static void
- setGlobalDefaultForValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- globalDefaultForValidatesChangesImmediately =
- validatesImmediately;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchFormat ( String aFormat )
- {
- globalDefaultStringMatchFormat = aFormat;
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchOperator ( String anOperator )
- {
- globalDefaultStringMatchOperator = anOperator;
- }
-
- /**
- * Needed because we don't inherit from NSObject.
- * Calls EOObserverCenter.notifyObserversObjectWillChange.
- */
- protected void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- /**
- * Called by LastGroupObserver to clear flags.
- */
- protected void processRecentChanges()
- {
- contentsChanged = false;
- selectionChanged = false;
- }
-
- /**
- * Returns the index of the specified object in the
- * specified NSArray, comparing by value or by reference
- * as determined by the private instance variable
- * compareByReference. If not found, returns NSArray.NotFound.
- */
- private int indexOf( NSArray anArray, Object anObject )
- {
- if ( compareByReference )
- {
- return anArray.indexOfIdenticalObject( anObject );
- }
- else
- {
- return anArray.indexOf( anObject );
- }
- }
-
- // interface EOObserving
-
- /**
- * Receives notifications of changes from objects that
- * are managed by this display group. This implementation
- * sets updatedObjectIndex and contentsChanged as appropriate.
- */
- public void objectWillChange(Object anObject)
- {
- int index = indexOf( displayedObjects, anObject );
- if ( index != NSArray.NotFound )
- {
- updatedObjectIndex = index;
- contentsChanged = true;
- willChange();
- }
- }
-
- // interface EOEditingContext.Editor
-
- /**
- * Called before the editing context begins to save changes.
- * This implementation calls endEditing().
- */
- public void editingContextWillSaveChanges(
- EOEditingContext anEditingContext )
- {
- endEditing();
- }
-
- /**
- * Called to determine whether this editor has changes
- * that have not been committed to the object in the context.
- */
- public boolean editorHasChangesForEditingContext(
- EOEditingContext anEditingContext )
- {
- return ( editingAssociation() != null );
- }
-
- // interface EOEditingContext.MessageHandler
-
- /**
- * Called to display a message for an error that occurred
- * in the specified editing context. If the delegate allows,
- * this implementation presents an informational JOptionPane.
- * Override to customize.
- */
- public void editingContextPresentErrorMessage(
- EOEditingContext anEditingContext,
- String aMessage )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { EODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", aMessage } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- JOptionPane.showMessageDialog( null, aMessage );
- }
- }
-
- /**
- * Called by the specified object store to determine whether
- * fetching should continue, where count is the current count
- * and limit is the limit as specified by the fetch specification.
- * This implementation presents an JOptionPane allowing the user
- * to specify whether to continue. Override to customize.
- */
- public boolean editingContextShouldContinueFetching(
- EOEditingContext anEditingContext,
- int count,
- int limit,
- EOObjectStore anObjectStore )
- {
- return ( JOptionPane.showConfirmDialog( null,
- "Fetch limit reached: do you wish to continue?",
- "Continue?",
- JOptionPane.YES_NO_OPTION ) == JOptionPane.YES_OPTION );
- }
-
- /**
- * Sends the specified message to the delegate.
- * Returns the return value of the method,
- * or null if no return value or no delegate
- * or no implementation.
- */
- private Object notifyDelegate(
- String aMethodName, Class[] types, Object[] params )
- {
- try
- {
- Object delegate = delegate();
- if ( delegate == null ) return null;
- return NSSelector.invoke(
- aMethodName, types, delegate, params );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while messaging delegate: " +
- delegate + " : " + aMethodName );
- exc.printStackTrace();
- }
-
- return null;
- }
-
- /**
- * DisplayGroups can delegate important decisions to a Delegate.
- * Note that DisplayGroup doesn't require its delegates to implement
- * this interface: rather, this interface defines the methods that
- * DisplayGroup will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- void displayGroupCreateObjectFailed (
- EODisplayGroup aDisplayGroup,
- EODataSource aDataSource );
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- void displayGroupDidChangeDataSource (
- EODisplayGroup aDisplayGroup );
-
- /**
- * Called after a change occurs in the specified
- * display group's selected objects.
- */
- void displayGroupDidChangeSelectedObjects (
- EODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- void displayGroupDidChangeSelection (
- EODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group has
- * deleted the specified object.
- */
- void displayGroupDidDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- void displayGroupDidFetchObjects (
- EODisplayGroup aDisplayGroup,
- List anObjectList );
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- void displayGroupDidInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- void displayGroupDidSetValueForObject (
- EODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey );
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- NSArray displayGroupDisplayArrayForObjects (
- EODisplayGroup aDisplayGroup,
- List aList );
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- boolean displayGroupShouldChangeSelection (
- EODisplayGroup aDisplayGroup,
- List aSelectionList );
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- boolean displayGroupShouldDeleteObject (
- EODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- boolean displayGroupShouldDisplayAlert (
- EODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage );
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- boolean displayGroupShouldFetch (
- EODisplayGroup aDisplayGroup );
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- boolean displayGroupShouldInsertObject (
- EODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * ObjectsChangedInEditingContextNotification.
- * @return True to allow the display group to
- * update the display (recommended), false
- * to prevent the update.
- */
- boolean displayGroupShouldRedisplay (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * InvalidatedAllObjectsInStoreNotification.
- * @return True to allow the display group to
- * refetch (recommended), false to prevent the
- * refetch.
- */
- boolean displayGroupShouldRefetch (
- EODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- }
+ int i;
+ NSMutableArray result = new NSMutableArray();
+ Enumeration e = selectedObjects.objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i != NSArray.NotFound) {
+ result.addObject(new Integer(i));
+ } else {
+ System.err.println("Should never happen: selected objects not in displayed objects");
+ new RuntimeException().printStackTrace(System.err);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the objects managed by this display group. updateDisplayedObjects() is
+ * called to filter the display objects. The previous selection will be
+ * maintained if possible. The data source is not notified.
+ */
+ public void setObjectArray(List anObjectList) {
+ if (anObjectList == null)
+ anObjectList = new NSArray();
+
+ Object result = notifyDelegate("displayGroupDisplayArrayForObjects",
+ new Class[] { EODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if (result != null) {
+ anObjectList = (List) result;
+ }
+
+ contentsChanged = true;
+ willChange();
+
+ NSArray oldSelectedObjects = new NSArray(selectedObjects); // copy
+
+ // reset allObjects to new list
+ allObjects.removeAllObjects();
+ allObjects.addObjectsFromArray(anObjectList);
+
+ // update the displayed object list
+ updateDisplayedObjects();
+
+ // restore the selection if possible
+ selectObjectsIdenticalTo(oldSelectedObjects);
+ }
+
+ /**
+ * Sets the currently selected object, or clears the selection if the object is
+ * not found or is null. Note: it's not clear how this differs from selectObject
+ * in the spec. It is recommended that you call selectObject for now.
+ */
+ public void setSelectedObject(Object anObject) {
+ selectObject(anObject);
+ }
+
+ /**
+ * Sets the current selection to the specified objects. The previous selection
+ * is cleared, and any objects in the display group that are in the specified
+ * list are then selected. If no items in the specified list are found in the
+ * display group, then the selection is effectively cleared. Note: it's not
+ * clear how this differs from selectObjectsIdenticalTo in the spec. It is
+ * recommended that you call that method for now.
+ */
+ public void setSelectedObjects(List aList) {
+ selectObjectsIdenticalTo(aList);
+ }
+
+ /**
+ * Sets the current selection to the objects at the specified indexes. Items in
+ * the list are assumed to be instances of java.lang.Number. The previous
+ * selection is cleared, and any objects in the display group that are in the
+ * specified list are then selected. If no items in the specified list are found
+ * in the display group, then the selection is effectively cleared.
+ */
+ public boolean setSelectionIndexes(List aList) {
+ Object o;
+ int index;
+ NSMutableArray objects = new NSMutableArray();
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ index = ((Number) it.next()).intValue();
+ if (index < displayedObjects.count()) {
+ o = displayedObjects.objectAtIndex(index);
+ if (o != null) {
+ objects.add(o);
+ }
+ }
+ }
+ return selectObjectsIdenticalTo(objects);
+ }
+
+ /**
+ * Applies the qualifier to all objects and sorts the results to update the list
+ * of displayed objects. Observing associations are notified to reflect the
+ * changes.
+ */
+ public void updateDisplayedObjects() {
+ contentsChanged = true;
+ updatedObjectIndex = -1;
+ willChange();
+
+ displayedObjects.removeAllObjects();
+
+ displayedObjects.addObjectsFromArray(allObjects);
+
+ // apply qualifier, if any
+ if (qualifier() != null) {
+ EOQualifier.filterArrayWithQualifier(displayedObjects, qualifier());
+ }
+
+ // apply sort orderings, if any
+ NSArray orderings = sortOrderings();
+ if (orderings != null) {
+ if (orderings.count() > 0) {
+ selectionChanged = true;
+ willChange();
+ EOSortOrdering.sortArrayUsingKeyOrderArray(displayedObjects, orderings);
+ }
+ }
+
+ // make sure the selectedObjects is a subset of displayedObjects
+ int i;
+ Object o;
+ Iterator it = new LinkedList(selectedObjects).iterator();
+ boolean removeflag = false;
+ selectedIndexes.removeAllObjects();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) == NSArray.NotFound) {
+ selectedObjects.removeIdenticalObject(o);
+ removeflag = true;
+ } else {
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ // Note: it is important to put the
+ // selectionChanged = true line below remove.
+ if (removeflag) {
+ selectionChanged = true;
+ willChange();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { EODisplayGroup.class },
+ new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.class },
+ new Object[] { this });
+ }
+ }
+
+ /**
+ * Returns the index of the changed object. If more than one object has changed,
+ * -1 is returned.
+ */
+ public int updatedObjectIndex() {
+ return updatedObjectIndex;
+ }
+
+ // getting and setting values in objects
+
+ /**
+ * Returns a value on the selected object for the specified key.
+ */
+ public Object selectedObjectValueForKey(String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return null;
+ return valueForObject(selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on all selected objects.
+ */
+ public boolean setSelectedObjectValue(Object aValue, String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return false;
+ return setValueForObject(aValue, selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on the specified object.
+ * Validations may be triggered, and error dialogs may appear to the user.
+ *
+ * @return True if the value was set successfully, false if the value could not
+ * be set and the update operation should not continue.
+ */
+ public boolean setValueForObject(Object aValue, Object anObject, String aKey) {
+ // notify object's observers:
+ // this includes us, and will notify our observers
+ EOObserverCenter.notifyObserversObjectWillChange(anObject);
+
+ // TODO: if key is null, need to remove old object
+ // and add new object instead of simply replacing it.
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).takeValueForKey(aValue, aKey);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(anObject, aValue, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { EODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return false;
+ }
+
+ notifyDelegate("displayGroupDidSetValueForObject",
+ new Class[] { EODisplayGroup.class, Object.class, Object.class, String.class },
+ new Object[] { this, aValue, anObject, aKey });
+
+ return true;
+ }
+
+ /**
+ * Calls setValueForObject() for the object at the specified index.
+ */
+ public boolean setValueForObjectAtIndex(Object aValue, int anIndex, String aKey) {
+ return setValueForObject(aValue, displayedObjects.objectAtIndex(anIndex), aKey);
+ }
+
+ /**
+ * Returns the value for the specified key on the specified object.
+ */
+ public Object valueForObject(Object anObject, String aKey) {
+ // empty string is considered the identity property
+ if (aKey == null)
+ return anObject;
+ if (aKey.equals(""))
+ return anObject;
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) anObject).valueForKey(aKey);
+ } else {
+ return EOKeyValueCodingSupport.valueForKey(anObject, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { EODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Calls valueForObject() for the object at the specified index.
+ */
+ public Object valueForObjectAtIndex(int anIndex, String aKey) {
+ Object o = displayedObjects.objectAtIndex(anIndex);
+ return valueForObject(o, aKey);
+ }
+
+ /**
+ * Prints out the list of displayed objects.
+ */
+ public String toString() {
+ return displayedObjects.toString();
+ }
+
+ /**
+ * Handles notifications from the data source's editing context, looking for
+ * InvalidatedAllObjectsInStoreNotification and
+ * ObjectsChangedInEditingContextNotification, refetching in the former case and
+ * updating displayed objects in the latter. Note: This method is not in the
+ * public specification.
+ */
+ public void objectsInvalidatedInEditingContext(NSNotification aNotification) {
+ if (EOObjectStore.InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRefetch",
+ new Class[] { EODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ fetch();
+ }
+ } else if (EOEditingContext.ObjectsChangedInEditingContextNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRedisplay",
+ new Class[] { EODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ int index;
+ Enumeration e;
+ boolean didChange = false;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // inserts are ignored
+
+ // mark updated objects as updated
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ e = updates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "EODisplayGroup: updated: " + index );
+ if (!didChange) {
+ didChange = true;
+ contentsChanged = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // treat invalidated objects as updated
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ e = invalidates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "EODisplayGroup: invalidated: " + index );
+ if (!didChange) {
+ didChange = true;
+ contentsChanged = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // remove deletes from display group if they exist
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ e = deletes.objectEnumerator();
+ Object o;
+ while (e.hasMoreElements()) {
+ o = e.nextElement();
+ index = indexOf(displayedObjects, o);
+ if (index != NSArray.NotFound) {
+ // System.out.println( "EODisplayGroup: deleted: " + o );
+ deleteObjectAtIndexNoNotify(index);
+ }
+ }
+
+ if (!usesOptimisticRefresh()) {
+ updateDisplayedObjects();
+ }
+ }
+ }
+
+ }
+
+ // static methods
+
+ /**
+ * Specifies the default behavior for whether changes should be validated
+ * immediately for all display groups.
+ */
+ public static boolean globalDefaultForValidatesChangesImmediately() {
+ return globalDefaultForValidatesChangesImmediately;
+ }
+
+ /**
+ * Specifies the default string matching format for all display groups.
+ */
+ public static String globalDefaultStringMatchFormat() {
+ return globalDefaultStringMatchFormat;
+ }
+
+ /**
+ * Specifies the default string matching operator for all display groups.
+ */
+ public static String globalDefaultStringMatchOperator() {
+ return globalDefaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the default behavior for validating changes for all display groups.
+ */
+ public static void setGlobalDefaultForValidatesChangesImmediately(boolean validatesImmediately) {
+ globalDefaultForValidatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchFormat(String aFormat) {
+ globalDefaultStringMatchFormat = aFormat;
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchOperator(String anOperator) {
+ globalDefaultStringMatchOperator = anOperator;
+ }
+
+ /**
+ * Needed because we don't inherit from NSObject. Calls
+ * EOObserverCenter.notifyObserversObjectWillChange.
+ */
+ protected void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ /**
+ * Called by LastGroupObserver to clear flags.
+ */
+ protected void processRecentChanges() {
+ contentsChanged = false;
+ selectionChanged = false;
+ }
+
+ /**
+ * Returns the index of the specified object in the specified NSArray, comparing
+ * by value or by reference as determined by the private instance variable
+ * compareByReference. If not found, returns NSArray.NotFound.
+ */
+ private int indexOf(NSArray anArray, Object anObject) {
+ if (compareByReference) {
+ return anArray.indexOfIdenticalObject(anObject);
+ } else {
+ return anArray.indexOf(anObject);
+ }
+ }
+
+ // interface EOObserving
+
+ /**
+ * Receives notifications of changes from objects that are managed by this
+ * display group. This implementation sets updatedObjectIndex and
+ * contentsChanged as appropriate.
+ */
+ public void objectWillChange(Object anObject) {
+ int index = indexOf(displayedObjects, anObject);
+ if (index != NSArray.NotFound) {
+ updatedObjectIndex = index;
+ contentsChanged = true;
+ willChange();
+ }
+ }
+
+ // interface EOEditingContext.Editor
+
+ /**
+ * Called before the editing context begins to save changes. This implementation
+ * calls endEditing().
+ */
+ public void editingContextWillSaveChanges(EOEditingContext anEditingContext) {
+ endEditing();
+ }
+
+ /**
+ * Called to determine whether this editor has changes that have not been
+ * committed to the object in the context.
+ */
+ public boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext) {
+ return (editingAssociation() != null);
+ }
+
+ // interface EOEditingContext.MessageHandler
+
+ /**
+ * Called to display a message for an error that occurred in the specified
+ * editing context. If the delegate allows, this implementation presents an
+ * informational JOptionPane. Override to customize.
+ */
+ public void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { EODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", aMessage });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ JOptionPane.showMessageDialog(null, aMessage);
+ }
+ }
+
+ /**
+ * Called by the specified object store to determine whether fetching should
+ * continue, where count is the current count and limit is the limit as
+ * specified by the fetch specification. This implementation presents an
+ * JOptionPane allowing the user to specify whether to continue. Override to
+ * customize.
+ */
+ public boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit,
+ EOObjectStore anObjectStore) {
+ return (JOptionPane.showConfirmDialog(null, "Fetch limit reached: do you wish to continue?", "Continue?",
+ JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION);
+ }
+
+ /**
+ * Sends the specified message to the delegate. Returns the return value of the
+ * method, or null if no return value or no delegate or no implementation.
+ */
+ private Object notifyDelegate(String aMethodName, Class[] types, Object[] params) {
+ try {
+ Object delegate = delegate();
+ if (delegate == null)
+ return null;
+ return NSSelector.invoke(aMethodName, types, delegate, params);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while messaging delegate: " + delegate + " : " + aMethodName);
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * DisplayGroups can delegate important decisions to a Delegate. Note that
+ * DisplayGroup doesn't require its delegates to implement this interface:
+ * rather, this interface defines the methods that DisplayGroup will attempt to
+ * invoke dynamically on its delegate. The delegate may choose to implement only
+ * a subset of the methods on the interface.
+ */
+ public interface Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ void displayGroupCreateObjectFailed(EODisplayGroup aDisplayGroup, EODataSource aDataSource);
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after a change occurs in the specified display group's selected
+ * objects.
+ */
+ void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group has deleted the specified object.
+ */
+ void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList);
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ void displayGroupDidSetValueForObject(EODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey);
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList);
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ boolean displayGroupShouldChangeSelection(EODisplayGroup aDisplayGroup, List aSelectionList);
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ boolean displayGroupShouldDeleteObject(EODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ boolean displayGroupShouldDisplayAlert(EODisplayGroup aDisplayGroup, String aTitle, String aMessage);
+
+ /**
+ * Called by the specified display group before it attempts fetch objects.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ boolean displayGroupShouldFetch(EODisplayGroup aDisplayGroup);
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * ObjectsChangedInEditingContextNotification.
+ *
+ * @return True to allow the display group to update the display (recommended),
+ * false to prevent the update.
+ */
+ boolean displayGroupShouldRedisplay(EODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * InvalidatedAllObjectsInStoreNotification.
+ *
+ * @return True to allow the display group to refetch (recommended), false to
+ * prevent the refetch.
+ */
+ boolean displayGroupShouldRefetch(EODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ }
}
- /**
- * A private class that will serve to clear the contentsChanged
- * and selectionChanged flags after all Associations have been
- * notified.
- */
- class LastGroupObserver extends EODelayedObserver
- {
- Reference ref;
-
- public LastGroupObserver( EODisplayGroup aDisplayGroup )
- {
- ref = new WeakReference( aDisplayGroup );
- }
-
- /**
- * We want to be informed last, after all Associations
- * have been notified to changes in the DisplayGroup.
- */
- public int priority()
- {
- return ObserverPrioritySixth;
- }
-
- /**
- * After all Associations have been notified,
- * clear the contentsChanged and selectionChanged flags.
- */
- public void subjectChanged ()
- {
- EODisplayGroup group = (EODisplayGroup) ref.get();
- if ( group != null )
- {
- group.processRecentChanges();
- }
- }
- }
+/**
+ * A private class that will serve to clear the contentsChanged and
+ * selectionChanged flags after all Associations have been notified.
+ */
+class LastGroupObserver extends EODelayedObserver {
+ Reference ref;
+
+ public LastGroupObserver(EODisplayGroup aDisplayGroup) {
+ ref = new WeakReference(aDisplayGroup);
+ }
+
+ /**
+ * We want to be informed last, after all Associations have been notified to
+ * changes in the DisplayGroup.
+ */
+ public int priority() {
+ return ObserverPrioritySixth;
+ }
+
+ /**
+ * After all Associations have been notified, clear the contentsChanged and
+ * selectionChanged flags.
+ */
+ public void subjectChanged() {
+ EODisplayGroup group = (EODisplayGroup) ref.get();
+ if (group != null) {
+ group.processRecentChanges();
+ }
+ }
+}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.51 2004/01/28 18:35:40 mpowers
- * Slight optimization: only comparing list in fetch if we have to.
+ * Revision 1.51 2004/01/28 18:35:40 mpowers Slight optimization: only comparing
+ * list in fetch if we have to.
*
- * Revision 1.50 2004/01/27 20:42:30 mpowers
- * No longer reselecting first after fetch if contents are identical.
+ * Revision 1.50 2004/01/27 20:42:30 mpowers No longer reselecting first after
+ * fetch if contents are identical.
*
- * Revision 1.49 2003/12/18 11:37:45 mpowers
- * Now calling qualifier internally.
+ * Revision 1.49 2003/12/18 11:37:45 mpowers Now calling qualifier internally.
*
- * Revision 1.48 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.48 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.47 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.47 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.46 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.46 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.45 2002/10/24 18:20:20 mpowers
- * Because NSArray is read-only, we are returning our internal representations
- * to callers of allObjects(), displayedObjects(), and selectedObjects().
+ * Revision 1.45 2002/10/24 18:20:20 mpowers Because NSArray is read-only, we
+ * are returning our internal representations to callers of allObjects(),
+ * displayedObjects(), and selectedObjects().
*
- * Revision 1.44 2002/08/06 18:20:25 mpowers
- * Now posting DisplayGroupWillFetch notifications before fetch.
- * Implemented support for usesOptimisticRefresh.
- * No longer supporting inserted/updated/deleted lists: not part of spec.
+ * Revision 1.44 2002/08/06 18:20:25 mpowers Now posting DisplayGroupWillFetch
+ * notifications before fetch. Implemented support for usesOptimisticRefresh. No
+ * longer supporting inserted/updated/deleted lists: not part of spec.
*
- * Revision 1.43 2002/05/17 15:01:49 mpowers
- * Implemented dynamic lookup of delegate methods so delegates no longer
- * need to implement the DisplayGroup.Delegate interface.
+ * Revision 1.43 2002/05/17 15:01:49 mpowers Implemented dynamic lookup of
+ * delegate methods so delegates no longer need to implement the
+ * DisplayGroup.Delegate interface.
*
- * Revision 1.42 2002/03/26 21:46:06 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.42 2002/03/26 21:46:06 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
- * Revision 1.41 2002/03/11 03:17:56 mpowers
- * Provided control point for coalesced changes.
+ * Revision 1.41 2002/03/11 03:17:56 mpowers Provided control point for
+ * coalesced changes.
*
- * Revision 1.40 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.40 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.39 2002/02/19 22:26:04 mpowers
- * Implemented EOEditingContext.MessageHandler support.
+ * Revision 1.39 2002/02/19 22:26:04 mpowers Implemented
+ * EOEditingContext.MessageHandler support.
*
- * Revision 1.38 2002/02/19 16:37:38 mpowers
- * Implemented support for EOEditingContext.Editor
+ * Revision 1.38 2002/02/19 16:37:38 mpowers Implemented support for
+ * EOEditingContext.Editor
*
- * Revision 1.37 2001/12/11 22:17:48 mpowers
- * Now properly handling exceptions in valueForObject.
- * No longer trying to retain selection based only on index.
+ * Revision 1.37 2001/12/11 22:17:48 mpowers Now properly handling exceptions in
+ * valueForObject. No longer trying to retain selection based only on index.
*
- * Revision 1.36 2001/11/08 21:42:00 mpowers
- * Now we know what to do with shouldRefetch and shouldRedisplay.
+ * Revision 1.36 2001/11/08 21:42:00 mpowers Now we know what to do with
+ * shouldRefetch and shouldRedisplay.
*
- * Revision 1.35 2001/11/04 18:26:58 mpowers
- * Fixed bug where exceptions were not properly reported when updating
- * a value and the display group did not have a delegate.
+ * Revision 1.35 2001/11/04 18:26:58 mpowers Fixed bug where exceptions were not
+ * properly reported when updating a value and the display group did not have a
+ * delegate.
*
- * Revision 1.34 2001/11/02 20:59:36 mpowers
- * Now correctly ensuring selected objects are a subset of displayed objects.
+ * Revision 1.34 2001/11/02 20:59:36 mpowers Now correctly ensuring selected
+ * objects are a subset of displayed objects.
*
- * Revision 1.33 2001/10/30 22:56:45 mpowers
- * Added support for EOQualifier.
+ * Revision 1.33 2001/10/30 22:56:45 mpowers Added support for EOQualifier.
*
- * Revision 1.32 2001/10/23 22:27:53 mpowers
- * Now running at ObserverPrioritySixth.
+ * Revision 1.32 2001/10/23 22:27:53 mpowers Now running at
+ * ObserverPrioritySixth.
*
- * Revision 1.31 2001/10/23 18:45:05 mpowers
- * Rolling back changes.
+ * Revision 1.31 2001/10/23 18:45:05 mpowers Rolling back changes.
*
- * Revision 1.28 2001/08/22 19:23:41 mpowers
- * No longer asserting objects in all objects list.
+ * Revision 1.28 2001/08/22 19:23:41 mpowers No longer asserting objects in all
+ * objects list.
*
- * Revision 1.27 2001/07/30 16:17:01 mpowers
- * Minor code cleanup.
+ * Revision 1.27 2001/07/30 16:17:01 mpowers Minor code cleanup.
*
- * Revision 1.26 2001/07/10 22:49:07 mpowers
- * Fixed bug in optimization for selectObjectsIdenticalTo (found by Dongzhi).
+ * Revision 1.26 2001/07/10 22:49:07 mpowers Fixed bug in optimization for
+ * selectObjectsIdenticalTo (found by Dongzhi).
*
- * Revision 1.25 2001/06/19 15:40:21 mpowers
- * Now only changing the selection if the new selection is different
- * from the old.
+ * Revision 1.25 2001/06/19 15:40:21 mpowers Now only changing the selection if
+ * the new selection is different from the old.
*
- * Revision 1.24 2001/05/24 17:36:15 mpowers
- * Fixed problem with selectedObjectsIdenticalTo: it was using compare
- * by value instead of compare by reference.
+ * Revision 1.24 2001/05/24 17:36:15 mpowers Fixed problem with
+ * selectedObjectsIdenticalTo: it was using compare by value instead of compare
+ * by reference.
*
- * Revision 1.23 2001/05/18 21:09:19 mpowers
- * Now throwing exceptions if the delegate cannot handle error from update.
+ * Revision 1.23 2001/05/18 21:09:19 mpowers Now throwing exceptions if the
+ * delegate cannot handle error from update.
*
- * Revision 1.22 2001/05/14 15:26:12 mpowers
- * Now checking for null delegate before and after selection change.
+ * Revision 1.22 2001/05/14 15:26:12 mpowers Now checking for null delegate
+ * before and after selection change.
*
- * Revision 1.21 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.21 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.20 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.20 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.19 2001/04/13 16:38:09 mpowers
- * Alpha3 release.
+ * Revision 1.19 2001/04/13 16:38:09 mpowers Alpha3 release.
*
- * Revision 1.18 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.18 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.17 2001/03/29 03:31:13 mpowers
- * No longer using Introspector.
+ * Revision 1.17 2001/03/29 03:31:13 mpowers No longer using Introspector.
*
- * Revision 1.16 2001/02/27 03:32:18 mpowers
- * Implemented default values for new objects.
+ * Revision 1.16 2001/02/27 03:32:18 mpowers Implemented default values for new
+ * objects.
*
- * Revision 1.15 2001/02/27 02:11:17 mpowers
- * Now throwing exception when cloning fails.
- * Removed debugging printlns.
+ * Revision 1.15 2001/02/27 02:11:17 mpowers Now throwing exception when cloning
+ * fails. Removed debugging printlns.
*
- * Revision 1.14 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.14 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.13 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.13 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.12 2001/02/22 20:55:06 mpowers
- * Implemented notification handling.
+ * Revision 1.12 2001/02/22 20:55:06 mpowers Implemented notification handling.
*
- * Revision 1.11 2001/02/21 20:40:42 mpowers
- * setObjectArray now falls back to index when trying to retain the
- * same selection.
+ * Revision 1.11 2001/02/21 20:40:42 mpowers setObjectArray now falls back to
+ * index when trying to retain the same selection.
*
- * Revision 1.10 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.10 2001/02/20 16:38:55 mpowers MasterDetailAssociations now
+ * observe their controlled display group's objects for changes to that the
+ * parent object will be marked as updated. Before, only inserts and deletes to
+ * an object's items are registered. Also, moved ObservableArray to package
+ * access.
*
- * Revision 1.9 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.9 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.8 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.7 2001/01/24 16:35:37 mpowers
- * Improved documentation on TreeAssociation.
- * SortOrderings are now inherited from parent nodes.
- * Updates after sorting are still lost on TreeController.
+ * Revision 1.7 2001/01/24 16:35:37 mpowers Improved documentation on
+ * TreeAssociation. SortOrderings are now inherited from parent nodes. Updates
+ * after sorting are still lost on TreeController.
*
- * Revision 1.6 2001/01/24 14:23:05 mpowers
- * Added support for OrderedDataSource.
+ * Revision 1.6 2001/01/24 14:23:05 mpowers Added support for OrderedDataSource.
*
- * Revision 1.5 2001/01/12 17:21:37 mpowers
- * Implicit creation of EOSortOrderings now happens in setSortOrderings.
+ * Revision 1.5 2001/01/12 17:21:37 mpowers Implicit creation of EOSortOrderings
+ * now happens in setSortOrderings.
*
- * Revision 1.4 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.4 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.3 2001/01/10 22:49:44 mpowers
- * Implemented similarly named selection methods instead of
- * throwing exceptions.
+ * Revision 1.3 2001/01/10 22:49:44 mpowers Implemented similarly named
+ * selection methods instead of throwing exceptions.
*
- * Revision 1.2 2001/01/09 20:12:52 mpowers
- * Moved inner classes to package access.
+ * Revision 1.2 2001/01/09 20:12:52 mpowers Moved inner classes to package
+ * access.
*
- * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers Contributing wotonomy.
*
- * Revision 1.21 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.21 2000/12/20 16:25:39 michael Added log to all files.
*
- * Revision 1.20 2000/12/15 15:04:42 michael
- * Added doc.
+ * Revision 1.20 2000/12/15 15:04:42 michael Added doc.
*
- * Revision 1.19 2000/12/11 13:32:48 michael
- * Finish the much better TreeAssociation implementation.
- * TreeAssociation now has no gui dependencies.
+ * Revision 1.19 2000/12/11 13:32:48 michael Finish the much better
+ * TreeAssociation implementation. TreeAssociation now has no gui dependencies.
*
- * Revision 1.18 2000/12/05 17:41:46 michael
- * Broadcasts selection change after delegate refuses selection change
- * so the initiating association gets refreshed.
+ * Revision 1.18 2000/12/05 17:41:46 michael Broadcasts selection change after
+ * delegate refuses selection change so the initiating association gets
+ * refreshed.
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java
index 3a4ff08..3310f19 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java
@@ -28,346 +28,282 @@ import net.wotonomy.control.EOObserverCenter;
import net.wotonomy.foundation.NSArray;
/**
-* GenericAssociation binds one or more properties on an
-* observable object to a display group. The controlled
-* object is expected to use the ObserverCenter and will
-* be observed by this association. <br><br>
-*
-* Bindings for this association are <i>generic</i>: the
-* name of the aspect will be treated as a property key
-* on the displayed object(s) and synchronized with the
-* bound property on the controlled object. <br><br>
-*
-* NOTE: because we cannot assume that the controlled
-* object will retain a reference to this association,
-* you must explicitly retain a reference to prevent
-* the association from getting garbage collected.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class GenericAssociation extends EOAssociation
-{
- protected boolean objectModified;
- protected Set aspectsModified;
-
- static final NSArray aspects =
- new NSArray( new Object[] {
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- } );
-
- /**
- * Constructor specifying the object to be controlled by this
- * association. Does not establish connection.
- */
- public GenericAssociation ( Object anObject )
- {
- super( anObject );
- objectModified = false;
- aspectsModified = new HashSet();
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return true;
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return "";
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return true;
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. This implementation
- * registers with ObserverCenter for change notifications
- * from the controlled object.
- */
- public void establishConnection ()
- {
- EOObserverCenter.addObserver( this, object() );
- super.establishConnection();
-
+ * GenericAssociation binds one or more properties on an observable object to a
+ * display group. The controlled object is expected to use the ObserverCenter
+ * and will be observed by this association. <br>
+ * <br>
+ *
+ * Bindings for this association are <i>generic</i>: the name of the aspect will
+ * be treated as a property key on the displayed object(s) and synchronized with
+ * the bound property on the controlled object. <br>
+ * <br>
+ *
+ * NOTE: because we cannot assume that the controlled object will retain a
+ * reference to this association, you must explicitly retain a reference to
+ * prevent the association from getting garbage collected.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class GenericAssociation extends EOAssociation {
+ protected boolean objectModified;
+ protected Set aspectsModified;
+
+ static final NSArray aspects = new NSArray(new Object[] {});
+ static final NSArray aspectSignatures = new NSArray(new Object[] {});
+ static final NSArray objectKeysTaken = new NSArray(new Object[] {});
+
+ /**
+ * Constructor specifying the object to be controlled by this association. Does
+ * not establish connection.
+ */
+ public GenericAssociation(Object anObject) {
+ super(anObject);
+ objectModified = false;
+ aspectsModified = new HashSet();
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return true;
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return "";
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return true;
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * This implementation registers with ObserverCenter for change notifications
+ * from the controlled object.
+ */
+ public void establishConnection() {
+ EOObserverCenter.addObserver(this, object());
+ super.establishConnection();
+
// forces update from bindings
subjectChanged();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- EOObserverCenter.removeObserver( this, object() );
- super.breakConnection();
- }
-
- /**
- * Overridden to track which observed object is changing.
- */
- public void objectWillChange( Object anObject )
- {
- if ( object() == anObject )
- {
- objectModified = true;
- }
- else
- {
- aspectsModified.add( aspectToGroup.allKeysForObject( anObject ) );
- }
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
- String aspect;
- String key;
- Object value;
- EODisplayGroup displayGroup;
- Iterator iterator;
-
- iterator = aspectsModified.iterator();
- while ( iterator.hasNext() )
- {
- aspect = (String) iterator.next();
- key = displayGroupKeyForAspect( aspect );
- displayGroup = displayGroupForAspect( aspect );
-
- value = readValueFromDisplayGroupForKey( displayGroup, key );
- writeValueForKey( object(), value, key );
- }
- aspectsModified.clear();
-
- if ( objectModified )
- {
- iterator = aspectToGroup.keySet().iterator();
- while ( iterator.hasNext() )
- {
- aspect = (String) iterator.next();
- key = displayGroupKeyForAspect( aspect );
- value = readValueForKey( object(), key );
- displayGroup = displayGroupForAspect( aspect );
- displayGroup.setSelectedObjectValue( value, key );
- }
- }
- }
-
- protected Object readValueForKey( Object object, String key )
- {
- if ( object instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)object).valueForKey( key );
- }
- return EOKeyValueCodingSupport.valueForKey( object, key );
- }
-
- protected void writeValueForKey( Object object, Object value, String key )
- {
- if ( object instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)object).takeValueForKey( value, key );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( object, value, key );
- }
- }
-
- protected Object readValueFromDisplayGroupForKey(
- EODisplayGroup displayGroup, String key )
- {
- Object value;
-
- if ( displayGroup.selectedObjects().size() > 1 )
- {
- // if there're more than one object selected, set
- // the value to blank for all of them.
- Object previousValue;
-
- Iterator indexIterator = displayGroup.selectionIndexes().
- iterator();
-
- // get value for the first selected object.
- int initialIndex = ( (Integer)indexIterator.next() ).intValue();
- previousValue = displayGroup.valueForObjectAtIndex(
- initialIndex, key );
- value = null;
-
- // go through the rest of the selected objects, compare each
- // value with the previous one. continue comparing if two
- // values are equal, break the while loop if they're different.
- // the final value will be the common value of all selected objects
- // if there is one, or be blank if there is not.
- while ( indexIterator.hasNext() )
- {
- int index = ( (Integer)indexIterator.next() ).intValue();
- Object currentValue = displayGroup.valueForObjectAtIndex(
- index, key );
- if ( currentValue != null && !currentValue.equals( previousValue ) )
- {
- value = null;
- break;
- }
- else
- {
- // currentValue is the same as the previous one
- value = currentValue;
- }
-
- } // end while
-
- } else {
-
- value = displayGroup.selectedObjectValueForKey( key );
- } // end checking size of displayGroup
-
- return value;
- }
-
+ }
+
/**
- * Writes the value currently in the component
- * to the selected object in the display group
- * bound to the value aspect.
- * @return false if there were problems validating,
- * or true to continue.
- */
- protected boolean writeValueForAspect( Object value, String aspect )
- {
- EODisplayGroup displayGroup =
- displayGroupForAspect( aspect );
- if ( displayGroup != null )
- {
- String key = displayGroupKeyForAspect( aspect );
-
- boolean returnValue = true;
- Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
- while ( selectedIterator.hasNext() )
- {
- int index = ( (Integer)selectedIterator.next() ).intValue();
-
- if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
- {
- returnValue = false;
- }
- }
- return returnValue;
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ EOObserverCenter.removeObserver(this, object());
+ super.breakConnection();
+ }
+
+ /**
+ * Overridden to track which observed object is changing.
+ */
+ public void objectWillChange(Object anObject) {
+ if (object() == anObject) {
+ objectModified = true;
+ } else {
+ aspectsModified.add(aspectToGroup.allKeysForObject(anObject));
+ }
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
+ String aspect;
+ String key;
+ Object value;
+ EODisplayGroup displayGroup;
+ Iterator iterator;
+
+ iterator = aspectsModified.iterator();
+ while (iterator.hasNext()) {
+ aspect = (String) iterator.next();
+ key = displayGroupKeyForAspect(aspect);
+ displayGroup = displayGroupForAspect(aspect);
+
+ value = readValueFromDisplayGroupForKey(displayGroup, key);
+ writeValueForKey(object(), value, key);
+ }
+ aspectsModified.clear();
+
+ if (objectModified) {
+ iterator = aspectToGroup.keySet().iterator();
+ while (iterator.hasNext()) {
+ aspect = (String) iterator.next();
+ key = displayGroupKeyForAspect(aspect);
+ value = readValueForKey(object(), key);
+ displayGroup = displayGroupForAspect(aspect);
+ displayGroup.setSelectedObjectValue(value, key);
+ }
+ }
+ }
+
+ protected Object readValueForKey(Object object, String key) {
+ if (object instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) object).valueForKey(key);
+ }
+ return EOKeyValueCodingSupport.valueForKey(object, key);
+ }
+
+ protected void writeValueForKey(Object object, Object value, String key) {
+ if (object instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) object).takeValueForKey(value, key);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(object, value, key);
+ }
+ }
+
+ protected Object readValueFromDisplayGroupForKey(EODisplayGroup displayGroup, String key) {
+ Object value;
+
+ if (displayGroup.selectedObjects().size() > 1) {
+ // if there're more than one object selected, set
+ // the value to blank for all of them.
+ Object previousValue;
+
+ Iterator indexIterator = displayGroup.selectionIndexes().iterator();
+
+ // get value for the first selected object.
+ int initialIndex = ((Integer) indexIterator.next()).intValue();
+ previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key);
+ value = null;
+
+ // go through the rest of the selected objects, compare each
+ // value with the previous one. continue comparing if two
+ // values are equal, break the while loop if they're different.
+ // the final value will be the common value of all selected objects
+ // if there is one, or be blank if there is not.
+ while (indexIterator.hasNext()) {
+ int index = ((Integer) indexIterator.next()).intValue();
+ Object currentValue = displayGroup.valueForObjectAtIndex(index, key);
+ if (currentValue != null && !currentValue.equals(previousValue)) {
+ value = null;
+ break;
+ } else {
+ // currentValue is the same as the previous one
+ value = currentValue;
+ }
+
+ } // end while
+
+ } else {
+
+ value = displayGroup.selectedObjectValueForKey(key);
+ } // end checking size of displayGroup
+
+ return value;
+ }
+
+ /**
+ * Writes the value currently in the component to the selected object in the
+ * display group bound to the value aspect.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ protected boolean writeValueForAspect(Object value, String aspect) {
+ EODisplayGroup displayGroup = displayGroupForAspect(aspect);
+ if (displayGroup != null) {
+ String key = displayGroupKeyForAspect(aspect);
+
+ boolean returnValue = true;
+ Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
+ while (selectedIterator.hasNext()) {
+ int index = ((Integer) selectedIterator.next()).intValue();
+
+ if (!displayGroup.setValueForObjectAtIndex(value, index, key)) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
}
return false;
}
- /**
- * Forces this association to cause the object to
- * stop editing and validate the user's input.
- * @return false if there were problems validating,
- * or true to continue.
- */
- public boolean endEditing ()
- {
- return false;
+ /**
+ * Forces this association to cause the object to stop editing and validate the
+ * user's input.
+ *
+ * @return false if there were problems validating, or true to continue.
+ */
+ public boolean endEditing() {
+ return false;
//! return writeValueToDisplayGroup();
- }
-
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2001/11/08 19:51:24 mpowers
- * Draft implementation.
+ * Revision 1.2 2001/11/08 19:51:24 mpowers Draft implementation.
*
- * Revision 1.1 2001/11/02 23:15:04 mpowers
- * Contributing "generic association".
+ * Revision 1.1 2001/11/02 23:15:04 mpowers Contributing "generic association".
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java
index 2aea8d3..54cd04e 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java
@@ -27,380 +27,303 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSMutableArray;
/**
-* MasterDetailAssociation binds a display group to a property
-* on the selected object of another display group.
-* Bindings are:
-* <ul>
-* <li>parent: The property on the selected object of the
-* bound display group that is expected to be an indexed property.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 904 $
-*/
-public class MasterDetailAssociation extends EOAssociation
-{
- static final NSArray aspects =
- new NSArray( new Object[] {
- ParentAspect
- } );
- static final NSArray aspectSignatures =
- new NSArray( new Object[] {
- AttributeToOneAspectSignature
- } );
- static final NSArray objectKeysTaken =
- new NSArray( new Object[] {
- "allObjects"
- } );
-
- /**
- * Used to be notified of changes to objects in the
- * controlled display group. requalify() should place
- * all objects fetched into the controlled group into
- * this array.
- * Otherwise, the parent object is only marked as
- * changed for inserts and deletes.
- */
- protected NSMutableArray observableArray;
-
- /**
- * Constructor expecting an EODisplayGroup.
- * If the controlled display group does not have a data source,
- * a new PropertyDataSource will be used.
- */
- public MasterDetailAssociation ( Object anObject )
- {
- super( anObject );
- observableArray = new ObservableArray( this );
- }
-
- /**
- * Returns a List of aspect signatures whose contents
- * correspond with the aspects list. Each element is
- * a string whose characters represent a capability of
- * the corresponding aspect. <ul>
- * <li>"A" attribute: the aspect can be bound to
- * an attribute.</li>
- * <li>"1" to-one: the aspect can be bound to a
- * property that returns a single object.</li>
- * <li>"M" to-one: the aspect can be bound to a
- * property that returns multiple objects.</li>
- * </ul>
- * An empty signature "" means that the aspect can
- * bind without needing a key.
- * This implementation returns "A1M" for each
- * element in the aspects array.
- */
- public static NSArray aspectSignatures ()
- {
- return aspectSignatures;
- }
-
- /**
- * Returns a List that describes the aspects supported
- * by this class. Each element in the list is the string
- * name of the aspect. This implementation returns an
- * empty list.
- */
- public static NSArray aspects ()
- {
- return aspects;
- }
-
- /**
- * Returns a List of EOAssociation subclasses that,
- * for the objects that are usable for this association,
- * are less suitable than this association.
- */
- public static NSArray associationClassesSuperseded ()
- {
- return new NSArray();
- }
-
- /**
- * Returns whether this class can control the specified
- * object.
- */
- public static boolean isUsableWithObject ( Object anObject )
- {
- return ( anObject instanceof EODisplayGroup );
- }
-
- /**
- * Returns a List of properties of the controlled object
- * that are controlled by this class. For example,
- * "stringValue", or "selected".
- */
- public static NSArray objectKeysTaken ()
- {
- return objectKeysTaken;
- }
-
- /**
- * Returns the aspect that is considered primary
- * or default. This is typically "value" or somesuch.
- */
- public static String primaryAspect ()
- {
- return ParentAspect;
- }
-
- /**
- * Returns whether this association can bind to the
- * specified display group on the specified key for
- * the specified aspect.
- */
- public boolean canBindAspect (
- String anAspect, EODisplayGroup aDisplayGroup, String aKey)
- {
- return ( aspects.containsObject( anAspect ) );
- }
-
- /**
- * Establishes a connection between this association
- * and the controlled object. Subclasses should begin
- * listening for events from their controlled object here.
- */
- public void establishConnection ()
- {
- //NOTE: if nothing refers to this assocation, it gets gc'd.
- // otherwise, this is not needed.
- component().addObserver( this );
-
- EODisplayGroup displayGroup =
- displayGroupForAspect( ParentAspect );
- String key =
- displayGroupKeyForAspect( ParentAspect );
-
- // obtain and qualify new data source from existing source if necessary
- if ( component().dataSource() == null )
- {
- if ( ( displayGroup != null ) && ( displayGroup.dataSource() != null ) )
- {
- component().setDataSource(
- displayGroup.dataSource().
- dataSourceQualifiedByKey( key ) );
- }
- }
-
- // set up proxy data source if necessary
- if ( component().dataSource() == null )
- {
- // get context and class desc from master group
- EOEditingContext editingContext = null;
- EOClassDescription classDesc = null;
- if ( displayGroup != null )
- {
- EODataSource dataSource = displayGroup.dataSource();
- if ( dataSource != null )
- {
- editingContext = dataSource.editingContext();
- EOClassDescription parentDesc = dataSource.classDescriptionForObjects();
- if ( parentDesc != null )
- {
- classDesc = parentDesc.classDescriptionForDestinationKey( key );
- }
- }
- }
-
- //FIXME: should this be called DetailDataSource?
- component().setDataSource(
- new PropertyDataSource( editingContext, classDesc ) );
- }
-
- super.establishConnection();
+ * MasterDetailAssociation binds a display group to a property on the selected
+ * object of another display group. Bindings are:
+ * <ul>
+ * <li>parent: The property on the selected object of the bound display group
+ * that is expected to be an indexed property.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 904 $
+ */
+public class MasterDetailAssociation extends EOAssociation {
+ static final NSArray aspects = new NSArray(new Object[] { ParentAspect });
+ static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature });
+ static final NSArray objectKeysTaken = new NSArray(new Object[] { "allObjects" });
+
+ /**
+ * Used to be notified of changes to objects in the controlled display group.
+ * requalify() should place all objects fetched into the controlled group into
+ * this array. Otherwise, the parent object is only marked as changed for
+ * inserts and deletes.
+ */
+ protected NSMutableArray observableArray;
+
+ /**
+ * Constructor expecting an EODisplayGroup. If the controlled display group does
+ * not have a data source, a new PropertyDataSource will be used.
+ */
+ public MasterDetailAssociation(Object anObject) {
+ super(anObject);
+ observableArray = new ObservableArray(this);
+ }
+
+ /**
+ * Returns a List of aspect signatures whose contents correspond with the
+ * aspects list. Each element is a string whose characters represent a
+ * capability of the corresponding aspect.
+ * <ul>
+ * <li>"A" attribute: the aspect can be bound to an attribute.</li>
+ * <li>"1" to-one: the aspect can be bound to a property that returns a single
+ * object.</li>
+ * <li>"M" to-one: the aspect can be bound to a property that returns multiple
+ * objects.</li>
+ * </ul>
+ * An empty signature "" means that the aspect can bind without needing a key.
+ * This implementation returns "A1M" for each element in the aspects array.
+ */
+ public static NSArray aspectSignatures() {
+ return aspectSignatures;
+ }
+
+ /**
+ * Returns a List that describes the aspects supported by this class. Each
+ * element in the list is the string name of the aspect. This implementation
+ * returns an empty list.
+ */
+ public static NSArray aspects() {
+ return aspects;
+ }
+
+ /**
+ * Returns a List of EOAssociation subclasses that, for the objects that are
+ * usable for this association, are less suitable than this association.
+ */
+ public static NSArray associationClassesSuperseded() {
+ return new NSArray();
+ }
+
+ /**
+ * Returns whether this class can control the specified object.
+ */
+ public static boolean isUsableWithObject(Object anObject) {
+ return (anObject instanceof EODisplayGroup);
+ }
+
+ /**
+ * Returns a List of properties of the controlled object that are controlled by
+ * this class. For example, "stringValue", or "selected".
+ */
+ public static NSArray objectKeysTaken() {
+ return objectKeysTaken;
+ }
+
+ /**
+ * Returns the aspect that is considered primary or default. This is typically
+ * "value" or somesuch.
+ */
+ public static String primaryAspect() {
+ return ParentAspect;
+ }
+
+ /**
+ * Returns whether this association can bind to the specified display group on
+ * the specified key for the specified aspect.
+ */
+ public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) {
+ return (aspects.containsObject(anAspect));
+ }
+
+ /**
+ * Establishes a connection between this association and the controlled object.
+ * Subclasses should begin listening for events from their controlled object
+ * here.
+ */
+ public void establishConnection() {
+ // NOTE: if nothing refers to this assocation, it gets gc'd.
+ // otherwise, this is not needed.
+ component().addObserver(this);
+
+ EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect);
+ String key = displayGroupKeyForAspect(ParentAspect);
+
+ // obtain and qualify new data source from existing source if necessary
+ if (component().dataSource() == null) {
+ if ((displayGroup != null) && (displayGroup.dataSource() != null)) {
+ component().setDataSource(displayGroup.dataSource().dataSourceQualifiedByKey(key));
+ }
+ }
+
+ // set up proxy data source if necessary
+ if (component().dataSource() == null) {
+ // get context and class desc from master group
+ EOEditingContext editingContext = null;
+ EOClassDescription classDesc = null;
+ if (displayGroup != null) {
+ EODataSource dataSource = displayGroup.dataSource();
+ if (dataSource != null) {
+ editingContext = dataSource.editingContext();
+ EOClassDescription parentDesc = dataSource.classDescriptionForObjects();
+ if (parentDesc != null) {
+ classDesc = parentDesc.classDescriptionForDestinationKey(key);
+ }
+ }
+ }
+
+ // FIXME: should this be called DetailDataSource?
+ component().setDataSource(new PropertyDataSource(editingContext, classDesc));
+ }
+
+ super.establishConnection();
requalify();
- }
-
- /**
- * Breaks the connection between this association and
- * its object. Override to stop listening for events
- * from the object.
- */
- public void breakConnection ()
- {
- //NOTE: if nothing refers to this assocation, it gets gc'd.
- // otherwise, this is not needed.
- component().deleteObserver( this );
-
- super.breakConnection();
- }
-
- /**
- * Called when either the selection or the contents
- * of an associated display group have changed.
- */
- public void subjectChanged ()
- {
+ }
+
+ /**
+ * Breaks the connection between this association and its object. Override to
+ * stop listening for events from the object.
+ */
+ public void breakConnection() {
+ // NOTE: if nothing refers to this assocation, it gets gc'd.
+ // otherwise, this is not needed.
+ component().deleteObserver(this);
+
+ super.breakConnection();
+ }
+
+ /**
+ * Called when either the selection or the contents of an associated display
+ * group have changed.
+ */
+ public void subjectChanged() {
EODisplayGroup displayGroup;
// parent aspect
- displayGroup = displayGroupForAspect( ParentAspect );
- if ( displayGroup != null )
- {
- if ( displayGroup.selectionChanged() )
- {
- requalify();
+ displayGroup = displayGroupForAspect(ParentAspect);
+ if (displayGroup != null) {
+ if (displayGroup.selectionChanged()) {
+ requalify();
+ } else if (displayGroup.contentsChanged()) {
+ requalify();
}
- else
- if ( displayGroup.contentsChanged() )
- {
- requalify();
+ }
+ }
+
+ /**
+ * Overridden to intercept notifications of changes to objects in the controlled
+ * display group and broadcast a change on the parent group's selected object.
+ * All other notifications are passed to the super implementation.
+ */
+ public void objectWillChange(Object anObject) {
+ // if child display group is notifying
+ if (!(anObject instanceof EODisplayGroup)) {
+ // mark parent group's object as changed
+ EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect);
+ if (displayGroup != null) {
+ Object selected = displayGroup.selectedObject();
+ if (selected != null) {
+ // only notify if childrenKey is an attribute of parentDesc
+ // (and therefore not a toOne or toMany relationship)
+ EOClassDescription parentDesc = EOClassDescription.classDescriptionForClass(selected.getClass());
+ String key = displayGroupKeyForAspect(ParentAspect);
+ if (key != null) {
+ int idx = key.indexOf('.');
+ if (idx != -1)
+ key = key.substring(0, idx);
+ if (parentDesc.attributeKeys().contains(key)) {
+ // only notify if we are an attribute key
+ EOObserverCenter.notifyObserversObjectWillChange(selected);
+ }
+ }
+ }
}
+ } else // display group is notifying
+ {
+ // call super so subjectChanged will be called
+ super.objectWillChange(anObject);
}
- }
-
- /**
- * Overridden to intercept notifications of changes to objects
- * in the controlled display group and broadcast a change on the
- * parent group's selected object. All other notifications are
- * passed to the super implementation.
- */
- public void objectWillChange ( Object anObject )
- {
- // if child display group is notifying
- if ( ! ( anObject instanceof EODisplayGroup ) )
- {
- // mark parent group's object as changed
- EODisplayGroup displayGroup = displayGroupForAspect( ParentAspect );
- if ( displayGroup != null )
- {
- Object selected = displayGroup.selectedObject();
- if ( selected != null )
- {
- // only notify if childrenKey is an attribute of parentDesc
- // (and therefore not a toOne or toMany relationship)
- EOClassDescription parentDesc =
- EOClassDescription.classDescriptionForClass(
- selected.getClass() );
- String key = displayGroupKeyForAspect( ParentAspect );
- if ( key != null )
- {
- int idx = key.indexOf( '.' );
- if ( idx != -1 ) key = key.substring( 0, idx );
- if ( parentDesc.attributeKeys().contains( key ) )
- {
- // only notify if we are an attribute key
- EOObserverCenter.notifyObserversObjectWillChange( selected );
- }
- }
- }
- }
- }
- else // display group is notifying
- {
- // call super so subjectChanged will be called
- super.objectWillChange( anObject );
- }
- }
-
- /**
- * Called by subjectChanged() to requalify the controlled
- * display group with the selected object and the bound key.
- */
- protected void requalify()
- {
+ }
+
+ /**
+ * Called by subjectChanged() to requalify the controlled display group with the
+ * selected object and the bound key.
+ */
+ protected void requalify() {
EODisplayGroup component = component();
- EODisplayGroup displayGroup = displayGroupForAspect( ParentAspect );
- String key = displayGroupKeyForAspect( ParentAspect );
-
- if ( ( displayGroup.selectedObject() != null )
- && ( component.dataSource() != null ) )
- {
- component.dataSource().qualifyWithRelationshipKey(
- key, displayGroup.selectedObject() );
+ EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect);
+ String key = displayGroupKeyForAspect(ParentAspect);
+
+ if ((displayGroup.selectedObject() != null) && (component.dataSource() != null)) {
+ component.dataSource().qualifyWithRelationshipKey(key, displayGroup.selectedObject());
component.fetch();
- observableArray.setArray( component.allObjects() );
- }
- else // no selection or no data source, clear
+ observableArray.setArray(component.allObjects());
+ } else // no selection or no data source, clear
{
- component.setObjectArray( null );
- observableArray.removeAllObjects();
+ component.setObjectArray(null);
+ observableArray.removeAllObjects();
}
- component.updateDisplayedObjects();
+ component.updateDisplayedObjects();
+ }
+
+ /**
+ * This implementation returns ObserverPrioritySecond so that master detail
+ * assocations are notified before other associations.
+ */
+ public int priority() {
+ return ObserverPrioritySecond;
}
-
- /**
- * This implementation returns ObserverPrioritySecond
- * so that master detail assocations are notified before
- * other associations.
- */
- public int priority ()
- {
- return ObserverPrioritySecond;
- }
// convenience
- private EODisplayGroup component()
- {
- return (EODisplayGroup) object();
- }
-
+ private EODisplayGroup component() {
+ return (EODisplayGroup) object();
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.14 2004/02/04 20:00:49 mpowers
- * Improved change notification for dotted key paths.
+ * Revision 1.14 2004/02/04 20:00:49 mpowers Improved change notification for
+ * dotted key paths.
*
- * Revision 1.13 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.13 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.12 2001/10/26 18:39:05 mpowers
- * Now a delayed observer with a higher priority, so that it is processed
- * before other associations.
+ * Revision 1.12 2001/10/26 18:39:05 mpowers Now a delayed observer with a
+ * higher priority, so that it is processed before other associations.
*
- * Revision 1.11 2001/06/26 21:39:33 mpowers
- * Added check for null component data source before requalifying.
+ * Revision 1.11 2001/06/26 21:39:33 mpowers Added check for null component data
+ * source before requalifying.
*
- * Revision 1.10 2001/05/21 14:04:15 mpowers
- * No longer changing a detail group's data source if it's already specified.
+ * Revision 1.10 2001/05/21 14:04:15 mpowers No longer changing a detail group's
+ * data source if it's already specified.
*
- * Revision 1.9 2001/05/18 21:08:46 mpowers
- * Now calling updateDisplayedObjects on detail after master changes.
+ * Revision 1.9 2001/05/18 21:08:46 mpowers Now calling updateDisplayedObjects
+ * on detail after master changes.
*
- * Revision 1.8 2001/05/14 15:26:42 mpowers
- * Modified logic for controlled groups that have no data source already set.
+ * Revision 1.8 2001/05/14 15:26:42 mpowers Modified logic for controlled groups
+ * that have no data source already set.
*
- * Revision 1.7 2001/05/04 14:42:58 mpowers
- * Now getting stored values in KeyValueCoding.
- * MasterDetail now marks dirty based on whether it's an attribute
- * or relation.
- * Implemented editing context marker.
+ * Revision 1.7 2001/05/04 14:42:58 mpowers Now getting stored values in
+ * KeyValueCoding. MasterDetail now marks dirty based on whether it's an
+ * attribute or relation. Implemented editing context marker.
*
- * Revision 1.6 2001/04/29 02:29:31 mpowers
- * Debugging relationship faulting.
+ * Revision 1.6 2001/04/29 02:29:31 mpowers Debugging relationship faulting.
*
- * Revision 1.4 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.4 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.3 2001/01/18 16:57:18 mpowers
- * Fixed problem with losing connection: the association was getting
- * garbage collected because nothing referred to it. All other associations
- * make themselves listeners of their controlled object, and that has been
- * the only thing keeping them from getting gc'd. This will need to be fixed.
+ * Revision 1.3 2001/01/18 16:57:18 mpowers Fixed problem with losing
+ * connection: the association was getting garbage collected because nothing
+ * referred to it. All other associations make themselves listeners of their
+ * controlled object, and that has been the only thing keeping them from getting
+ * gc'd. This will need to be fixed.
*
- * Revision 1.2 2001/01/17 23:06:09 mpowers
- * TreeAssociation now modifies the contents of the children display
- * group rather than adding items to the titles display group.
+ * Revision 1.2 2001/01/17 23:06:09 mpowers TreeAssociation now modifies the
+ * contents of the children display group rather than adding items to the titles
+ * display group.
*
- * Revision 1.1.1.1 2000/12/21 15:48:23 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:23 mpowers Contributing wotonomy.
*
- * Revision 1.5 2000/12/20 16:25:40 michael
- * Added log to all files.
+ * Revision 1.5 2000/12/20 16:25:40 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java
index aeac376..b81f9e2 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java
@@ -17,90 +17,76 @@ License along with this library; if not, see http://www.gnu.org
*/
package net.wotonomy.ui;
+
import net.wotonomy.foundation.NSArray;
/**
-* This master detail association synchronizes the contents
-* and selection of the master group into the detail group.
-*/
-public class MirrorDetailAssociation extends MasterDetailAssociation{
+ * This master detail association synchronizes the contents and selection of the
+ * master group into the detail group.
+ */
+public class MirrorDetailAssociation extends MasterDetailAssociation {
- /**
- * Standard constructor specifying the detail display group.
- * @param displayGroup the detail display group of this
- * Master-Detail Association
- */
- public MirrorDetailAssociation(EODisplayGroup displayGroup){
- super(displayGroup);
- }
+ /**
+ * Standard constructor specifying the detail display group.
+ *
+ * @param displayGroup the detail display group of this Master-Detail
+ * Association
+ */
+ public MirrorDetailAssociation(EODisplayGroup displayGroup) {
+ super(displayGroup);
+ }
- /**
- * Called by subjectChanged() to requalify the controlled
- * display group with the indexed object and the bound key.
- * This implementation ignores both and sets the object array
- * of the detail group to the displayed objects of the master
- * and sets the selection to match.
- */
- protected void requalify()
- {
- EODisplayGroup detail = (EODisplayGroup) object();
- EODisplayGroup master =
- displayGroupForAspect( ParentAspect );
+ /**
+ * Called by subjectChanged() to requalify the controlled display group with the
+ * indexed object and the bound key. This implementation ignores both and sets
+ * the object array of the detail group to the displayed objects of the master
+ * and sets the selection to match.
+ */
+ protected void requalify() {
+ EODisplayGroup detail = (EODisplayGroup) object();
+ EODisplayGroup master = displayGroupForAspect(ParentAspect);
- if ( master != null )
- {
- NSArray masterObjects = master.displayedObjects();
- NSArray detailObjects = detail.displayedObjects();
- int size = masterObjects.size();
- boolean different = false;
-
- // see if lists contain the same object instances
- if ( size == detailObjects.size() )
- {
- for ( int i = 0; i < size; i++ )
- {
- if ( masterObjects.objectAtIndex(i)
- != detailObjects.objectAtIndex(i) )
- {
- different = true;
- break;
- }
- }
- }
- else // different sizes
- {
- different = true;
- }
-
- // if different, sync contents and selection with master
- if ( different )
- {
- detail.setObjectArray( masterObjects );
- detail.setSelectionIndexes( master.selectionIndexes() );
- }
- else // if selection changed, sync selection with master
- if ( master.selectionChanged() )
- {
- detail.setSelectionIndexes( master.selectionIndexes() );
- }
- }
- else // no bound display group, clear
- {
- detail.setObjectArray( null );
- }
- }
+ if (master != null) {
+ NSArray masterObjects = master.displayedObjects();
+ NSArray detailObjects = detail.displayedObjects();
+ int size = masterObjects.size();
+ boolean different = false;
+
+ // see if lists contain the same object instances
+ if (size == detailObjects.size()) {
+ for (int i = 0; i < size; i++) {
+ if (masterObjects.objectAtIndex(i) != detailObjects.objectAtIndex(i)) {
+ different = true;
+ break;
+ }
+ }
+ } else // different sizes
+ {
+ different = true;
+ }
+
+ // if different, sync contents and selection with master
+ if (different) {
+ detail.setObjectArray(masterObjects);
+ detail.setSelectionIndexes(master.selectionIndexes());
+ } else // if selection changed, sync selection with master
+ if (master.selectionChanged()) {
+ detail.setSelectionIndexes(master.selectionIndexes());
+ }
+ } else // no bound display group, clear
+ {
+ detail.setObjectArray(null);
+ }
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/07/05 22:13:28 mpowers
- * Now only updating if master has actually changed.
+ * Revision 1.2 2001/07/05 22:13:28 mpowers Now only updating if master has
+ * actually changed.
*
- * Revision 1.1 2001/05/29 19:57:47 mpowers
- * Added some neglected files.
+ * Revision 1.1 2001/05/29 19:57:47 mpowers Added some neglected files.
*
*
*/
-
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
index a398e97..e18ed3b 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
@@ -28,322 +28,272 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSRange;
/**
-* A package class that extends NSMutableArray but makes use
-* of the fact that wotonomy's implementation extends ArrayList
-* to intercept insertions and deletion and register and
-* unregister objects for change notifications as appropriate.
-* Since we can't be sure of ArrayList's implementation, we're
-* forced to override each and every add and remove method,
-* some of which probably call each other. However,
-* EOObserverCenter will only register us once per object.
-*/
-class ObservableArray extends NSMutableArray
-{
- EOObserving observer;
-
- ObservableArray( EOObserving anObserver )
- {
- observer = anObserver;
- }
-
+ * A package class that extends NSMutableArray but makes use of the fact that
+ * wotonomy's implementation extends ArrayList to intercept insertions and
+ * deletion and register and unregister objects for change notifications as
+ * appropriate. Since we can't be sure of ArrayList's implementation, we're
+ * forced to override each and every add and remove method, some of which
+ * probably call each other. However, EOObserverCenter will only register us
+ * once per object.
+ */
+class ObservableArray extends NSMutableArray {
+ EOObserving observer;
+
+ ObservableArray(EOObserving anObserver) {
+ observer = anObserver;
+ }
+
/**
- * Removes the last object from the array.
- */
- public void removeLastObject ()
- {
- remove( count() - 1 );
- }
+ * Removes the last object from the array.
+ */
+ public void removeLastObject() {
+ remove(count() - 1);
+ }
/**
- * Removes the object at the specified index.
- */
- public void removeObjectAtIndex (int index)
- {
- remove( index );
- }
+ * Removes the object at the specified index.
+ */
+ public void removeObjectAtIndex(int index) {
+ remove(index);
+ }
/**
- * Adds all objects in the specified collection.
- */
- public void addObjectsFromArray (Collection aCollection)
- {
- addAll( aCollection );
- }
+ * Adds all objects in the specified collection.
+ */
+ public void addObjectsFromArray(Collection aCollection) {
+ addAll(aCollection);
+ }
/**
- * Removes all objects from the array.
- */
- public void removeAllObjects ()
- {
- clear();
- }
+ * Removes all objects from the array.
+ */
+ public void removeAllObjects() {
+ clear();
+ }
/**
- * Removes all objects equivalent to the specified object
- * within the range of specified indices.
- */
- public void removeObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( get( i ) ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all objects equivalent to the specified object within the range of
+ * specified indices.
+ */
+ public void removeObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(get(i))) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all instances of the specified object within the
- * range of specified indices, comparing by reference.
- */
- public void removeIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == get( i ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all instances of the specified object within the range of specified
+ * indices, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == get(i)) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all objects in the specified collection from the array.
- */
- public void removeObjectsInArray (Collection aCollection)
- {
- removeAll( aCollection );
- }
+ * Removes all objects in the specified collection from the array.
+ */
+ public void removeObjectsInArray(Collection aCollection) {
+ removeAll(aCollection);
+ }
/**
- * Removes all objects in the indices within the specified range
- * from the array.
- */
- public void removeObjectsInRange (NSRange aRange)
- {
- if ( aRange == null ) return;
-
- for ( int i = 0; i < aRange.length(); i++ )
- {
- remove( aRange.location() );
- }
- }
+ * Removes all objects in the indices within the specified range from the array.
+ */
+ public void removeObjectsInRange(NSRange aRange) {
+ if (aRange == null)
+ return;
+
+ for (int i = 0; i < aRange.length(); i++) {
+ remove(aRange.location());
+ }
+ }
/**
- * Replaces objects in the current range with objects from
- * the specified range of the specified array. If currentRange
- * is larger than otherRange, the extra objects are removed.
- * If otherRange is larger than currentRange, the extra objects
- * are added.
- */
- public void replaceObjectsInRange (NSRange currentRange,
- List otherArray, NSRange otherRange)
- {
- if ( ( currentRange == null ) || ( otherArray == null ) ||
- ( otherRange == null ) ) return;
-
+ * Replaces objects in the current range with objects from the specified range
+ * of the specified array. If currentRange is larger than otherRange, the extra
+ * objects are removed. If otherRange is larger than currentRange, the extra
+ * objects are added.
+ */
+ public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ if ((currentRange == null) || (otherArray == null) || (otherRange == null))
+ return;
+
// transform otherRange if out of bounds for array
- if ( otherRange.maxRange() > otherArray.size() )
- {
+ if (otherRange.maxRange() > otherArray.size()) {
// TODO: Test this logic.
- int loc = Math.min( otherRange.location(), otherArray.size() - 1 );
- otherRange = new NSRange( loc, otherArray.size() - loc );
+ int loc = Math.min(otherRange.location(), otherArray.size() - 1);
+ otherRange = new NSRange(loc, otherArray.size() - loc);
}
-
+
Object o;
- List subList = subList(
- currentRange.location(), currentRange.maxRange() );
+ List subList = subList(currentRange.location(), currentRange.maxRange());
int otherIndex = otherRange.location();
// TODO: Test this logic.
- for ( int i = 0; i < subList.size(); i++ )
- {
- if ( otherIndex < otherRange.maxRange() )
- { // set object
- subList.set( i, otherArray.get( otherIndex ) );
- }
- else
- { // remove extra elements from currentRange
- subList.remove( i );
- i--;
+ for (int i = 0; i < subList.size(); i++) {
+ if (otherIndex < otherRange.maxRange()) { // set object
+ subList.set(i, otherArray.get(otherIndex));
+ } else { // remove extra elements from currentRange
+ subList.remove(i);
+ i--;
}
otherIndex++;
}
// TODO: Test this logic.
- for ( int i = otherIndex; i < otherRange.maxRange(); i++ )
- {
- add( otherArray.get( i ) );
+ for (int i = otherIndex; i < otherRange.maxRange(); i++) {
+ add(otherArray.get(i));
}
}
/**
- * Clears the current array and then populates it with the
- * contents of the specified collection.
- */
- public void setArray (Collection aCollection)
- {
- clear();
- addAll( aCollection );
- }
+ * Clears the current array and then populates it with the contents of the
+ * specified collection.
+ */
+ public void setArray(Collection aCollection) {
+ clear();
+ addAll(aCollection);
+ }
/**
- * Removes all objects equivalent to the specified object.
- */
- public void removeObject (Object anObject)
- {
- remove( anObject );
- }
+ * Removes all objects equivalent to the specified object.
+ */
+ public void removeObject(Object anObject) {
+ remove(anObject);
+ }
/**
- * Removes all occurences of the specified object,
- * comparing by reference.
- */
- public void removeIdenticalObject (Object anObject)
- {
- EOObserverCenter.removeObserver( observer, anObject );
- super.removeIdenticalObject( anObject );
- }
+ * Removes all occurences of the specified object, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject) {
+ EOObserverCenter.removeObserver(observer, anObject);
+ super.removeIdenticalObject(anObject);
+ }
/**
- * Inserts the specified object into this array at the
- * specified index.
- */
- public void insertObjectAtIndex (Object anObject, int anIndex)
- {
- add( anIndex, anObject );
- }
-
+ * Inserts the specified object into this array at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ add(anIndex, anObject);
+ }
+
/**
- * Replaces the object at the specified index with the
- * specified object.
- */
- public void replaceObjectAtIndex (int anIndex, Object anObject)
- {
- set( anIndex, anObject );
- }
+ * Replaces the object at the specified index with the specified object.
+ */
+ public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ set(anIndex, anObject);
+ }
/**
- * Adds the specified object to the end of this array.
- */
- public void addObject (Object anObject)
- {
- add( anObject );
- }
-
- // interface List: mutators
-
- public void add(int index, Object element)
- {
- EOObserverCenter.addObserver( observer, element );
- super.add( index, element );
- }
-
- public boolean add(Object o)
- {
- EOObserverCenter.addObserver( observer, o );
- return super.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll( index, c );
- }
-
- public void clear()
- {
- Iterator it = iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- super.clear();
- }
-
- public Object remove(int index)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- return super.remove( index );
- }
-
- public boolean remove(Object o)
- {
- EOObserverCenter.removeObserver( observer, o );
- return super.remove(o);
- }
-
- public boolean removeAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- return super.removeAll(coll);
- }
-
- public boolean retainAll(Collection coll)
- {
- throw new UnsupportedOperationException();
- }
-
- public Object set(int index, Object element)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- EOObserverCenter.addObserver( observer, element );
- return super.set( index, element );
- }
+ * Adds the specified object to the end of this array.
+ */
+ public void addObject(Object anObject) {
+ add(anObject);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ EOObserverCenter.addObserver(observer, element);
+ super.add(index, element);
+ }
+
+ public boolean add(Object o) {
+ EOObserverCenter.addObserver(observer, o);
+ return super.add(o);
+ }
+
+ public boolean addAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(index, c);
+ }
+
+ public void clear() {
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ super.clear();
+ }
+
+ public Object remove(int index) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ return super.remove(index);
+ }
+
+ public boolean remove(Object o) {
+ EOObserverCenter.removeObserver(observer, o);
+ return super.remove(o);
+ }
+
+ public boolean removeAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ return super.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object set(int index, Object element) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ EOObserverCenter.addObserver(observer, element);
+ return super.set(index, element);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/18 23:14:35 cgruber
- * Update imports and maven dependencies.
+ * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven
+ * dependencies.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.3 2003/08/06 23:07:52 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.2 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.2 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.1 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.1 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.1 2001/01/24 14:37:24 mpowers
- * Contributing a delegate useful for debugging.
+ * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for
+ * debugging.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
index cef1372..1c91115 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/ObservableArray.java
@@ -28,324 +28,272 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSRange;
/**
-* A package class that extends NSMutableArray but makes use
-* of the fact that wotonomy's implementation extends ArrayList
-* to intercept insertions and deletion and register and
-* unregister objects for change notifications as appropriate.
-* Since we can't be sure of ArrayList's implementation, we're
-* forced to override each and every add and remove method,
-* some of which probably call each other. However,
-* EOObserverCenter will only register us once per object.
-*/
-class ObservableArray extends NSMutableArray
-{
- EOObserving observer;
-
- ObservableArray( EOObserving anObserver )
- {
- observer = anObserver;
- }
-
+ * A package class that extends NSMutableArray but makes use of the fact that
+ * wotonomy's implementation extends ArrayList to intercept insertions and
+ * deletion and register and unregister objects for change notifications as
+ * appropriate. Since we can't be sure of ArrayList's implementation, we're
+ * forced to override each and every add and remove method, some of which
+ * probably call each other. However, EOObserverCenter will only register us
+ * once per object.
+ */
+class ObservableArray extends NSMutableArray {
+ EOObserving observer;
+
+ ObservableArray(EOObserving anObserver) {
+ observer = anObserver;
+ }
+
/**
- * Removes the last object from the array.
- */
- public void removeLastObject ()
- {
- remove( count() - 1 );
- }
+ * Removes the last object from the array.
+ */
+ public void removeLastObject() {
+ remove(count() - 1);
+ }
/**
- * Removes the object at the specified index.
- */
- public void removeObjectAtIndex (int index)
- {
- remove( index );
- }
+ * Removes the object at the specified index.
+ */
+ public void removeObjectAtIndex(int index) {
+ remove(index);
+ }
/**
- * Adds all objects in the specified collection.
- */
- public void addObjectsFromArray (Collection aCollection)
- {
- addAll( aCollection );
- }
+ * Adds all objects in the specified collection.
+ */
+ public void addObjectsFromArray(Collection aCollection) {
+ addAll(aCollection);
+ }
/**
- * Removes all objects from the array.
- */
- public void removeAllObjects ()
- {
- clear();
- }
+ * Removes all objects from the array.
+ */
+ public void removeAllObjects() {
+ clear();
+ }
/**
- * Removes all objects equivalent to the specified object
- * within the range of specified indices.
- */
- public void removeObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject.equals( get( i ) ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all objects equivalent to the specified object within the range of
+ * specified indices.
+ */
+ public void removeObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject.equals(get(i))) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all instances of the specified object within the
- * range of specified indices, comparing by reference.
- */
- public void removeIdenticalObject (Object anObject, NSRange aRange)
- {
- if ( ( anObject == null ) || ( aRange == null ) ) return;
-
- int loc = aRange.location();
- int max = aRange.maxRange();
- for ( int i = loc; i < max; i++ )
- {
- if ( anObject == get( i ) )
- {
- remove( i );
- i = i - 1;
- max = max - 1;
- }
- }
- }
+ * Removes all instances of the specified object within the range of specified
+ * indices, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject, NSRange aRange) {
+ if ((anObject == null) || (aRange == null))
+ return;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for (int i = loc; i < max; i++) {
+ if (anObject == get(i)) {
+ remove(i);
+ i = i - 1;
+ max = max - 1;
+ }
+ }
+ }
/**
- * Removes all objects in the specified collection from the array.
- */
- public void removeObjectsInArray (Collection aCollection)
- {
- removeAll( aCollection );
- }
+ * Removes all objects in the specified collection from the array.
+ */
+ public void removeObjectsInArray(Collection aCollection) {
+ removeAll(aCollection);
+ }
/**
- * Removes all objects in the indices within the specified range
- * from the array.
- */
- public void removeObjectsInRange (NSRange aRange)
- {
- if ( aRange == null ) return;
-
- for ( int i = 0; i < aRange.length(); i++ )
- {
- remove( aRange.location() );
- }
- }
+ * Removes all objects in the indices within the specified range from the array.
+ */
+ public void removeObjectsInRange(NSRange aRange) {
+ if (aRange == null)
+ return;
+
+ for (int i = 0; i < aRange.length(); i++) {
+ remove(aRange.location());
+ }
+ }
/**
- * Replaces objects in the current range with objects from
- * the specified range of the specified array. If currentRange
- * is larger than otherRange, the extra objects are removed.
- * If otherRange is larger than currentRange, the extra objects
- * are added.
- */
- public void replaceObjectsInRange (NSRange currentRange,
- List otherArray, NSRange otherRange)
- {
- if ( ( currentRange == null ) || ( otherArray == null ) ||
- ( otherRange == null ) ) return;
-
+ * Replaces objects in the current range with objects from the specified range
+ * of the specified array. If currentRange is larger than otherRange, the extra
+ * objects are removed. If otherRange is larger than currentRange, the extra
+ * objects are added.
+ */
+ public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ if ((currentRange == null) || (otherArray == null) || (otherRange == null))
+ return;
+
// transform otherRange if out of bounds for array
- if ( otherRange.maxRange() > otherArray.size() )
- {
+ if (otherRange.maxRange() > otherArray.size()) {
// TODO: Test this logic.
- int loc = Math.min( otherRange.location(), otherArray.size() - 1 );
- otherRange = new NSRange( loc, otherArray.size() - loc );
+ int loc = Math.min(otherRange.location(), otherArray.size() - 1);
+ otherRange = new NSRange(loc, otherArray.size() - loc);
}
-
+
Object o;
- List subList = subList(
- currentRange.location(), currentRange.maxRange() );
+ List subList = subList(currentRange.location(), currentRange.maxRange());
int otherIndex = otherRange.location();
// TODO: Test this logic.
- for ( int i = 0; i < subList.size(); i++ )
- {
- if ( otherIndex < otherRange.maxRange() )
- { // set object
- subList.set( i, otherArray.get( otherIndex ) );
- }
- else
- { // remove extra elements from currentRange
- subList.remove( i );
- i--;
+ for (int i = 0; i < subList.size(); i++) {
+ if (otherIndex < otherRange.maxRange()) { // set object
+ subList.set(i, otherArray.get(otherIndex));
+ } else { // remove extra elements from currentRange
+ subList.remove(i);
+ i--;
}
otherIndex++;
}
// TODO: Test this logic.
- for ( int i = otherIndex; i < otherRange.maxRange(); i++ )
- {
- add( otherArray.get( i ) );
+ for (int i = otherIndex; i < otherRange.maxRange(); i++) {
+ add(otherArray.get(i));
}
}
/**
- * Clears the current array and then populates it with the
- * contents of the specified collection.
- */
- public void setArray (Collection aCollection)
- {
- clear();
- addAll( aCollection );
- }
+ * Clears the current array and then populates it with the contents of the
+ * specified collection.
+ */
+ public void setArray(Collection aCollection) {
+ clear();
+ addAll(aCollection);
+ }
/**
- * Removes all objects equivalent to the specified object.
- */
- public void removeObject (Object anObject)
- {
- remove( anObject );
- }
+ * Removes all objects equivalent to the specified object.
+ */
+ public void removeObject(Object anObject) {
+ remove(anObject);
+ }
/**
- * Removes all occurences of the specified object,
- * comparing by reference.
- */
- public void removeIdenticalObject (Object anObject)
- {
- EOObserverCenter.removeObserver( observer, anObject );
- super.removeIdenticalObject( anObject );
- }
+ * Removes all occurences of the specified object, comparing by reference.
+ */
+ public void removeIdenticalObject(Object anObject) {
+ EOObserverCenter.removeObserver(observer, anObject);
+ super.removeIdenticalObject(anObject);
+ }
/**
- * Inserts the specified object into this array at the
- * specified index.
- */
- public void insertObjectAtIndex (Object anObject, int anIndex)
- {
- add( anIndex, anObject );
- }
-
+ * Inserts the specified object into this array at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ add(anIndex, anObject);
+ }
+
/**
- * Replaces the object at the specified index with the
- * specified object.
- */
- public void replaceObjectAtIndex (int anIndex, Object anObject)
- {
- set( anIndex, anObject );
- }
+ * Replaces the object at the specified index with the specified object.
+ */
+ public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ set(anIndex, anObject);
+ }
/**
- * Adds the specified object to the end of this array.
- */
- public void addObject (Object anObject)
- {
- add( anObject );
- }
-
- // interface List: mutators
-
- public void add(int index, Object element)
- {
- EOObserverCenter.addObserver( observer, element );
- super.add( index, element );
- }
-
- public boolean add(Object o)
- {
- EOObserverCenter.addObserver( observer, o );
- return super.add(o);
- }
-
- public boolean addAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll(coll);
- }
-
- public boolean addAll(int index, Collection c)
- {
- Iterator it = c.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.addObserver( observer, it.next() );
- }
- return super.addAll( index, c );
- }
-
- public void clear()
- {
- Iterator it = iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- super.clear();
- }
-
- public Object remove(int index)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- return super.remove( index );
- }
-
- public boolean remove(Object o)
- {
- EOObserverCenter.removeObserver( observer, o );
- return super.remove(o);
- }
-
- public boolean removeAll(Collection coll)
- {
- Iterator it = coll.iterator();
- while ( it.hasNext() )
- {
- EOObserverCenter.removeObserver( observer, it.next() );
- }
- return super.removeAll(coll);
- }
-
- public boolean retainAll(Collection coll)
- {
- throw new UnsupportedOperationException();
- }
-
- public Object set(int index, Object element)
- {
- EOObserverCenter.removeObserver( observer, get(index) );
- EOObserverCenter.addObserver( observer, element );
- return super.set( index, element );
- }
+ * Adds the specified object to the end of this array.
+ */
+ public void addObject(Object anObject) {
+ add(anObject);
+ }
+
+ // interface List: mutators
+
+ public void add(int index, Object element) {
+ EOObserverCenter.addObserver(observer, element);
+ super.add(index, element);
+ }
+
+ public boolean add(Object o) {
+ EOObserverCenter.addObserver(observer, o);
+ return super.add(o);
+ }
+
+ public boolean addAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.addObserver(observer, it.next());
+ }
+ return super.addAll(index, c);
+ }
+
+ public void clear() {
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ super.clear();
+ }
+
+ public Object remove(int index) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ return super.remove(index);
+ }
+
+ public boolean remove(Object o) {
+ EOObserverCenter.removeObserver(observer, o);
+ return super.remove(o);
+ }
+
+ public boolean removeAll(Collection coll) {
+ Iterator it = coll.iterator();
+ while (it.hasNext()) {
+ EOObserverCenter.removeObserver(observer, it.next());
+ }
+ return super.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object set(int index, Object element) {
+ EOObserverCenter.removeObserver(observer, get(index));
+ EOObserverCenter.addObserver(observer, element);
+ return super.set(index, element);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/18 23:31:32 mpowers
- * Needed for WODisplayGroup.
+ * Revision 1.1 2003/01/18 23:31:32 mpowers Needed for WODisplayGroup.
*
- * Revision 1.2 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.2 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.1 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.1 2001/02/20 16:38:55 mpowers MasterDetailAssociations now observe
+ * their controlled display group's objects for changes to that the parent
+ * object will be marked as updated. Before, only inserts and deletes to an
+ * object's items are registered. Also, moved ObservableArray to package access.
*
- * Revision 1.1 2001/01/24 14:37:24 mpowers
- * Contributing a delegate useful for debugging.
+ * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for
+ * debugging.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
index 41f77f5..ba608a4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/URI.java
@@ -59,7 +59,7 @@
*
* [Additional notices, if required by prior licensing conditions]
*
- */
+ */
// excellent class borrowed from Apache Commons project:
//package org.apache.commons.httpclient;
@@ -80,30 +80,39 @@ import sun.security.action.GetPropertyAction;
/**
* The interface for the URI(Uniform Resource Identifiers) version of RFC 2396.
* This class has the purpose of supportting of parsing a URI reference to
- * extend any specific protocols, the character encoding of the protocol to
- * be transported and the charset of the document.
+ * extend any specific protocols, the character encoding of the protocol to be
+ * transported and the charset of the document.
* <p>
* A URI is always in an "escaped" form, since escaping or unescaping a
- * completed URI might change its semantics.
+ * completed URI might change its semantics.
* <p>
- * Implementers should be careful not to escape or unescape the same string
- * more than once, since unescaping an already unescaped string might lead to
- * misinterpreting a percent data character as another escaped character,
- * or vice versa in the case of escaping an already escaped string.
+ * Implementers should be careful not to escape or unescape the same string more
+ * than once, since unescaping an already unescaped string might lead to
+ * misinterpreting a percent data character as another escaped character, or
+ * vice versa in the case of escaping an already escaped string.
* <p>
* In order to avoid these problems, data types used as follows:
- * <p><blockquote><pre>
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
* URI character sequence: char
* octet sequence: byte
* original character sequence: String
- * </pre></blockquote><p>
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
*
- * So, a URI is a sequence of characters as an array of a char type, which
- * is not always represented as a sequence of octets as an array of byte.
+ * So, a URI is a sequence of characters as an array of a char type, which is
+ * not always represented as a sequence of octets as an array of byte.
* <p>
*
* URI Syntactic Components
- * <p><blockquote><pre>
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
* - In general, written as follows:
* Absolute URI = &lt;scheme&gt:&lt;scheme-specific-part&gt;
* Generic URI = &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;
@@ -113,9 +122,13 @@ import sun.security.action.GetPropertyAction;
* hier_part = ( net_path | abs_path ) [ "?" query ]
* net_path = "//" authority [ abs_path ]
* abs_path = "/" path_segments
- * </pre></blockquote><p>
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
*
* The following examples illustrate URI that are in common use.
+ *
* <pre>
* ftp://ftp.is.co.za/rfc/rfc1808.txt
* -- ftp scheme for File Transfer Protocol services
@@ -130,11 +143,14 @@ import sun.security.action.GetPropertyAction;
* telnet://melvyl.ucop.edu/
* -- telnet scheme for interactive services via the TELNET Protocol
* </pre>
+ *
* Please, notice that there are many modifications from URL(RFC 1738) and
* relative URL(RFC 1808).
* <p>
* <b>The expressions for a URI</b>
- * <p><pre>
+ * <p>
+ *
+ * <pre>
* For escaped URI forms
* - URI(char[]) // constructor
* - char[] getRawXxx() // method
@@ -144,3321 +160,3489 @@ import sun.security.action.GetPropertyAction;
* For unescaped URI forms
* - URI(String) // constructor
* - String getXXX() // method
- * </pre><p>
+ * </pre>
+ * <p>
*
* @author <a href="mailto:jericho@apache.org">Sung-Gu</a>
- * @version $Revision: 905 $ $Date: 2002/03/14 15:14:01
+ * @version $Revision: 905 $ $Date: 2002/03/14 15:14:01
*/
class URI implements Cloneable, Comparable, Serializable {
-
- // ----------------------------------------------------------- Constructors
-
- protected URI() {
- }
-
- /**
- * Construct a URI as an escaped form of a character array.
- * An URI can be placed within double-quotes or angle brackets like
- * "http://test.com/" and &lt;http://test.com/&gt;
- *
- * @param escaped the URI character sequence
- * @exception IOException
- * @throws NullPointerException if <code>escaped</code> is <code>null</code>
- */
- public URI(char[] escaped) throws IOException {
- parseUriReference(new String(escaped), true);
- }
-
-
- /**
- * Construct a URI from the given string.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * </pre></blockquote><p>
- * An URI can be placed within double-quotes or angle brackets like
- * "http://test.com/" and &lt;http://test.com/&gt;
- *
- * @param original the string to be represented to URI character sequence
- * It is one of absoluteURI and relativeURI.
- * @exception IOException
- */
- public URI(String original) throws IOException {
- parseUriReference(original, false);
- }
-
- /**
- * Construct a URI from a URL.
- *
- * @param url a valid URL.
- * @throws IOException
- * @since 2.0
- */
- public URI(URL url) throws IOException {
- this(url.toString());
- }
-
-
- /**
- * Construct a general URI from the given components.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- * It's for absolute URI = &lt;scheme&gt;:&lt;scheme-specific-part&gt;#
- * &lt;fragment&gt;.
- *
- * @param scheme the scheme string
- * @param scheme_specific_part scheme_specific_part
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String scheme_specific_part, String fragment)
- throws IOException {
-
- // validate and contruct the URI character sequence
- if (scheme == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: scheme required");
- }
- char[] s = scheme.toLowerCase().toCharArray();
- if (validate(s, URI.scheme)) {
- _scheme = s; // is_absoluteURI
- } else {
- throw new IOException(/*IOException.PARSING,*/ "URI: incorrect scheme");
- }
- _opaque = encode(scheme_specific_part, allowed_opaque_part);
- // Set flag
- _is_opaque_part = true;
- setUriReference();
- }
-
-
- /**
- * Construct a general URI from the given components.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * hier_part = ( net_path | abs_path ) [ "?" query ]
- * </pre></blockquote><p>
- * It's for absolute URI = &lt;scheme&gt;:&lt;path&gt;?&lt;query&gt;#&lt;
- * fragment&gt; and relative URI = &lt;path&gt;?&lt;query&gt;#&lt;fragment
- * &gt;.
- *
- * @param scheme the scheme string
- * @param authority the authority string
- * @param path the path string
- * @param query the query string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String authority, String path, String query,
- String fragment) throws IOException {
-
- // validate and contruct the URI character sequence
- StringBuffer buff = new StringBuffer();
- if (scheme != null) {
- buff.append(scheme);
- buff.append(':');
- }
- if (authority != null) {
- buff.append("//");
- buff.append(authority);
- }
- if (path != null) { // accept empty path
- if ((scheme != null || authority != null)
- && !path.startsWith("/")) {
- throw new IOException(/*IOException.PARSING*,*/
- "URI: abs_path requested");
- }
- buff.append(path);
- }
- if (query != null) {
- buff.append('?');
- buff.append(query);
- }
- if (fragment != null) {
- buff.append('#');
- buff.append(fragment);
- }
- parseUriReference(buff.toString(), false);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port)
- throws IOException {
-
- this(scheme, userinfo, host, port, null, null, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path) throws IOException {
-
- this(scheme, userinfo, host, port, path, null, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @param query the query string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path, String query) throws IOException {
-
- this(scheme, userinfo, host, port, path, query, null);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param userinfo the userinfo string
- * @param host the host string
- * @param port the port number
- * @param path the path string
- * @param query the query string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String userinfo, String host, int port,
- String path, String query, String fragment) throws IOException {
-
- this(scheme, (host == null) ? null :
- ((userinfo != null) ? userinfo + '@' : "") + host +
- ((port != -1) ? ":" + port : ""), path, query, fragment);
- }
-
-
- /**
- * Construct a general URI from the given components.
- *
- * @param scheme the scheme string
- * @param host the host string
- * @param path the path string
- * @param fragment the fragment string
- * @exception IOException
- */
- public URI(String scheme, String host, String path, String fragment)
- throws IOException {
-
- this(scheme, host, path, null, fragment);
- }
-
-
- /**
- * Construct a general URI with the given relative URI string.
- *
- * @param base the base URI
- * @param relative the relative URI string
- * @exception IOException
- */
- public URI(URI base, String relative) throws IOException {
- this(base, new URI(relative));
- }
-
-
- /**
- * Construct a general URI with the given relative URI.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * </pre></blockquote><p>
- * Resolving Relative References to Absolute Form.
- *
- * <strong>Examples of Resolving Relative URI References</strong>
- *
- * Within an object with a well-defined base URI of
- * <p><blockquote><pre>
- * http://a/b/c/d;p?q
- * </pre></blockquote><p>
- * the relative URI would be resolved as follows:
- *
- * Normal Examples
- *
- * <p><blockquote><pre>
- * g:h = g:h
- * g = http://a/b/c/g
- * ./g = http://a/b/c/g
- * g/ = http://a/b/c/g/
- * /g = http://a/g
- * //g = http://g
- * ?y = http://a/b/c/?y
- * g?y = http://a/b/c/g?y
- * #s = (current document)#s
- * g#s = http://a/b/c/g#s
- * g?y#s = http://a/b/c/g?y#s
- * ;x = http://a/b/c/;x
- * g;x = http://a/b/c/g;x
- * g;x?y#s = http://a/b/c/g;x?y#s
- * . = http://a/b/c/
- * ./ = http://a/b/c/
- * .. = http://a/b/
- * ../ = http://a/b/
- * ../g = http://a/b/g
- * ../.. = http://a/
- * ../../ = http://a/
- * ../../g = http://a/g
- * </pre></blockquote><p>
- *
- * Some URI schemes do not allow a hierarchical syntax matching the
- * <hier_part> syntax, and thus cannot use relative references.
- *
- * @param base the base URI
- * @param relative the relative URI
- * @exception IOException
- */
- public URI(URI base, URI relative) throws IOException {
-
- if (base._scheme == null) {
- throw new IOException(/* IOException.PARSING,*/ "URI: base URI required");
- }
- if (base._scheme != null) {
- this._scheme = base._scheme;
- this._authority = base._authority;
- }
- if (base._is_opaque_part || relative._is_opaque_part) {
- this._scheme = base._scheme;
- this._is_opaque_part = relative._is_opaque_part;
- this._opaque = relative._opaque;
- this._fragment = relative._fragment;
- this.setUriReference();
- return;
- }
- if (relative._scheme != null) {
- this._scheme = relative._scheme;
- this._is_net_path = relative._is_net_path;
- this._authority = relative._authority;
- if (relative._is_server) {
- this._userinfo = relative._userinfo;
- this._host = relative._host;
- this._port = relative._port;
- } else if (relative._is_reg_name) {
- this._is_reg_name = relative._is_reg_name;
- }
- this._is_abs_path = relative._is_abs_path;
- this._is_rel_path = relative._is_rel_path;
- this._path = relative._path;
- } else if (base._authority != null && relative._scheme == null) {
- this._is_net_path = base._is_net_path;
- this._authority = base._authority;
- if (base._is_server) {
- this._userinfo = base._userinfo;
- this._host = base._host;
- this._port = base._port;
- } else if (base._is_reg_name) {
- this._is_reg_name = base._is_reg_name;
- }
- }
- if (relative._authority != null) {
- this._is_net_path = relative._is_net_path;
- this._authority = relative._authority;
- if (relative._is_server) {
- this._is_server = relative._is_server;
- this._userinfo = relative._userinfo;
- this._host = relative._host;
- this._port = relative._port;
- } else if (relative._is_reg_name) {
- this._is_reg_name = relative._is_reg_name;
- }
- this._is_abs_path = relative._is_abs_path;
- this._is_rel_path = relative._is_rel_path;
- this._path = relative._path;
- }
- // resolve the path
- if (relative._scheme == null && relative._authority == null ||
- equals(base._scheme, relative._scheme)) {
- this._path = resolvePath(base._path, relative._path);
- }
- // base._query removed
- if (relative._query != null) {
- this._query = relative._query;
- }
- // base._fragment removed
- if (relative._fragment != null) {
- this._fragment = relative._fragment;
- }
- this.setUriReference();
- }
-
- // --------------------------------------------------- Instance Variables
-
- static final long serialVersionUID = 604752400577948726L;
-
-
- /**
- * This Uniform Resource Identifier (URI).
- * The URI is always in an "escaped" form, since escaping or unescaping
- * a completed URI might change its semantics.
- */
- protected char[] _uri = null;
-
-
- /**
- * The default charset of the protocol. RFC 2277, 2396
- */
- protected static String _protocolCharset = "UTF-8";
-
-
- /**
- * The default charset of the document. RFC 2277, 2396
- * The platform's charset is used for the document by default.
- */
- protected static String _documentCharset = null;
- // Static initializer for _documentCharset
- static {
- Locale locale = Locale.getDefault();
- if (locale != null) {
- // in order to support backward compatiblity
- _documentCharset = LocaleToCharsetMap.getCharset(locale);
- } else {
- _documentCharset = (String)AccessController.doPrivileged(
- new GetPropertyAction("file.encoding"));
- }
- }
-
- /**
- * The scheme.
- */
- protected char[] _scheme = null;
-
-
- /**
- * The opaque.
- */
- protected char[] _opaque = null;
-
-
- /**
- * The authority.
- */
- protected char[] _authority = null;
-
-
- /**
- * The userinfo.
- */
- protected char[] _userinfo = null;
-
-
- /**
- * The host.
- */
- protected char[] _host = null;
-
-
- /**
- * The port.
- */
- protected int _port = -1;
-
-
- /**
- * The path.
- */
- protected char[] _path = null;
-
-
- /**
- * The query.
- */
- protected char[] _query = null;
-
-
- /**
- * The fragment.
- */
- protected char[] _fragment = null;
-
-
- /**
- * The root path.
- */
- protected static char[] rootPath = { '/' };
-
- // ---------------------- Generous characters for each component validation
-
- /**
- * The percent "%" character always has the reserved purpose of being the
- * escape indicator, it must be escaped as "%25" in order to be used as
- * data within a URI.
- */
- protected static final BitSet percent = new BitSet(256);
- // Static initializer for percent
- static {
- percent.set('%');
- }
-
-
- /**
- * BitSet for digit.
- * <p><blockquote><pre>
- * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
- * "8" | "9"
- * </pre></blockquote><p>
- */
- protected static final BitSet digit = new BitSet(256);
- // Static initializer for digit
- static {
- for(int i = '0'; i <= '9'; i++) {
- digit.set(i);
- }
- }
-
-
- /**
- * BitSet for alpha.
- * <p><blockquote><pre>
- * alpha = lowalpha | upalpha
- * </pre></blockquote><p>
- */
- protected static final BitSet alpha = new BitSet(256);
- // Static initializer for alpha
- static {
- for (int i = 'a'; i <= 'z'; i++) {
- alpha.set(i);
- }
- for (int i = 'A'; i <= 'Z'; i++) {
- alpha.set(i);
- }
- }
-
-
- /**
- * BitSet for alphanum (join of alpha &amp; digit).
- * <p><blockquote><pre>
- * alphanum = alpha | digit
- * </pre></blockquote><p>
- */
- protected static final BitSet alphanum = new BitSet(256);
- // Static initializer for alphanum
- static {
- alphanum.or(alpha);
- alphanum.or(digit);
- }
-
-
- /**
- * BitSet for hex.
- * <p><blockquote><pre>
- * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
- * "a" | "b" | "c" | "d" | "e" | "f"
- * </pre></blockquote><p>
- */
- protected static final BitSet hex = new BitSet(256);
- // Static initializer for hex
- static {
- hex.or(digit);
- for(int i = 'a'; i <= 'f'; i++) {
- hex.set(i);
- }
- for(int i = 'A'; i <= 'F'; i++) {
- hex.set(i);
- }
- }
-
-
- /**
- * BitSet for escaped.
- * <p><blockquote><pre>
- * escaped = "%" hex hex
- * </pre></blockquote><p>
- */
- protected static final BitSet escaped = new BitSet(256);
- // Static initializer for escaped
- static {
- escaped.or(percent);
- escaped.or(hex);
- }
-
-
- /**
- * BitSet for mark.
- * <p><blockquote><pre>
- * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
- * "(" | ")"
- * </pre></blockquote><p>
- */
- protected static final BitSet mark = new BitSet(256);
- // Static initializer for mark
- static {
- mark.set('-');
- mark.set('_');
- mark.set('.');
- mark.set('!');
- mark.set('~');
- mark.set('*');
- mark.set('\'');
- mark.set('(');
- mark.set(')');
- }
-
-
- /**
- * Data characters that are allowed in a URI but do not have a reserved
- * purpose are called unreserved.
- * <p><blockquote><pre>
- * unreserved = alphanum | mark
- * </pre></blockquote><p>
- */
- protected static final BitSet unreserved = new BitSet(256);
- // Static initializer for unreserved
- static {
- unreserved.or(alphanum);
- unreserved.or(mark);
- }
-
-
- /**
- * BitSet for reserved.
- * <p><blockquote><pre>
- * reserved = ";" | "/" | "?" | ":" | "@" | "&amp;" | "=" | "+" |
- * "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet reserved = new BitSet(256);
- // Static initializer for reserved
- static {
- reserved.set(';');
- reserved.set('/');
- reserved.set('?');
- reserved.set(':');
- reserved.set('@');
- reserved.set('&');
- reserved.set('=');
- reserved.set('+');
- reserved.set('$');
- reserved.set(',');
- }
-
-
- /**
- * BitSet for uric.
- * <p><blockquote><pre>
- * uric = reserved | unreserved | escaped
- * </pre></blockquote><p>
- */
- protected static final BitSet uric = new BitSet(256);
- // Static initializer for uric
- static {
- uric.or(reserved);
- uric.or(unreserved);
- uric.or(escaped);
- }
-
-
- /**
- * BitSet for fragment (alias for uric).
- * <p><blockquote><pre>
- * fragment = *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet fragment = uric;
-
-
- /**
- * BitSet for query (alias for uric).
- * <p><blockquote><pre>
- * query = *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet query = uric;
-
-
- /**
- * BitSet for pchar.
- * <p><blockquote><pre>
- * pchar = unreserved | escaped |
- * ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet pchar = new BitSet(256);
- // Static initializer for pchar
- static {
- pchar.or(unreserved);
- pchar.or(escaped);
- pchar.set(':');
- pchar.set('@');
- pchar.set('&');
- pchar.set('=');
- pchar.set('+');
- pchar.set('$');
- pchar.set(',');
- }
-
-
- /**
- * BitSet for param (alias for pchar).
- * <p><blockquote><pre>
- * param = *pchar
- * </pre></blockquote><p>
- */
- protected static final BitSet param = pchar;
-
-
- /**
- * BitSet for segment.
- * <p><blockquote><pre>
- * segment = *pchar *( ";" param )
- * </pre></blockquote><p>
- */
- protected static final BitSet segment = new BitSet(256);
- // Static initializer for segment
- static {
- segment.or(pchar);
- segment.set(';');
- segment.or(param);
- }
-
-
- /**
- * BitSet for path segments.
- * <p><blockquote><pre>
- * path_segments = segment *( "/" segment )
- * </pre></blockquote><p>
- */
- protected static final BitSet path_segments = new BitSet(256);
- // Static initializer for path_segments
- static {
- path_segments.set('/');
- path_segments.or(segment);
- }
-
-
- /**
- * URI absolute path.
- * <p><blockquote><pre>
- * abs_path = "/" path_segments
- * </pre><blockquote><p>
- */
- protected static final BitSet abs_path = new BitSet(256);
- // Static initializer for abs_path
- static {
- abs_path.set('/');
- abs_path.or(path_segments);
- }
-
-
- /**
- * URI bitset for encoding typical non-slash characters.
- * <p><blockquote><pre>
- * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
- * "&amp;" | "=" | "+" | "$" | ","
- * </pre></blockquote><p>
- */
- protected static final BitSet uric_no_slash = new BitSet(256);
- // Static initializer for uric_no_slash
- static {
- uric_no_slash.or(unreserved);
- uric_no_slash.or(escaped);
- uric_no_slash.set(';');
- uric_no_slash.set('?');
- uric_no_slash.set(';');
- uric_no_slash.set('@');
- uric_no_slash.set('&');
- uric_no_slash.set('=');
- uric_no_slash.set('+');
- uric_no_slash.set('$');
- uric_no_slash.set(',');
- }
-
-
- /**
- * URI bitset that combines uric_no_slash and uric.
- * <p><blockquote><pre>
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- */
- protected static final BitSet opaque_part = new BitSet(256);
- // Static initializer for opaque_part
- static {
- opaque_part.or(uric_no_slash);
- opaque_part.or(uric);
- }
-
-
- /**
- * URI bitset that combines absolute path and opaque part.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- */
- protected static final BitSet path = new BitSet(256);
- // Static initializer for path
- static {
- path.or(abs_path);
- path.or(opaque_part);
- }
-
-
- /**
- * Port, a logical alias for digit.
- */
- protected static final BitSet port = digit;
-
-
- /**
- * Bitset that combines digit and dot fo IPv$address.
- * <p><blockquote><pre>
- * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv4address = new BitSet(256);
- // Static initializer for IPv4address
- static {
- IPv4address.or(digit);
- IPv4address.set('.');
- }
-
-
- /**
- * RFC 2373.
- * <p><blockquote><pre>
- * IPv6address = hexpart [ ":" IPv4address ]
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv6address = new BitSet(256);
- // Static initializer for IPv6address reference
- static {
- IPv6address.or(hex); // hexpart
- IPv6address.set(':');
- IPv6address.or(IPv4address);
- }
-
-
- /**
- * RFC 2732, 2373.
- * <p><blockquote><pre>
- * IPv6reference = "[" IPv6address "]"
- * </pre></blockquote><p>
- */
- protected static final BitSet IPv6reference = new BitSet(256);
- // Static initializer for IPv6reference
- static {
- IPv6reference.set('[');
- IPv6reference.or(IPv6address);
- IPv6reference.set(']');
- }
-
-
- /**
- * BitSet for toplabel.
- * <p><blockquote><pre>
- * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- * </pre></blockquote><p>
- */
- protected static final BitSet toplabel = new BitSet(256);
- // Static initializer for toplabel
- static {
- toplabel.or(alphanum);
- toplabel.set('-');
- }
-
-
- /**
- * BitSet for domainlabel.
- * <p><blockquote><pre>
- * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- * </pre></blockquote><p>
- */
- protected static final BitSet domainlabel = toplabel;
-
-
- /**
- * BitSet for hostname.
- * <p><blockquote><pre>
- * hostname = *( domainlabel "." ) toplabel [ "." ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hostname = new BitSet(256);
- // Static initializer for hostname
- static {
- hostname.or(toplabel);
- // hostname.or(domainlabel);
- hostname.set('.');
- }
-
-
- /**
- * BitSet for host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- */
- protected static final BitSet host = new BitSet(256);
- // Static initializer for host
- static {
- host.or(hostname);
- // host.or(IPv4address);
- host.or(IPv6reference); // IPv4address
- }
-
-
- /**
- * BitSet for hostport.
- * <p><blockquote><pre>
- * hostport = host [ ":" port ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hostport = new BitSet(256);
- // Static initializer for hostport
- static {
- hostport.or(host);
- hostport.set(':');
- hostport.or(port);
- }
-
-
- /**
- * Bitset for userinfo.
- * <p><blockquote><pre>
- * userinfo = *( unreserved | escaped |
- * ";" | ":" | "&amp;" | "=" | "+" | "$" | "," )
- * </pre></blockquote><p>
- */
- protected static final BitSet userinfo = new BitSet(256);
- // Static initializer for userinfo
- static {
- userinfo.or(unreserved);
- userinfo.or(escaped);
- userinfo.set(';');
- userinfo.set(':');
- userinfo.set('&');
- userinfo.set('=');
- userinfo.set('+');
- userinfo.set('$');
- userinfo.set(',');
- }
-
-
- /**
- * BitSet for within the userinfo component like user and password.
- */
- public static final BitSet within_userinfo = new BitSet(256);
- // Static initializer for within_userinfo
- static {
- within_userinfo.or(userinfo);
- within_userinfo.clear(';'); // reserved within authority
- within_userinfo.clear(':');
- within_userinfo.clear('@');
- within_userinfo.clear('?');
- within_userinfo.clear('/');
- }
-
-
- /**
- * Bitset for server.
- * <p><blockquote><pre>
- * server = [ [ userinfo "@" ] hostport ]
- * </pre></blockquote><p>
- */
- protected static final BitSet server = new BitSet(256);
- // Static initializer for server
- static {
- server.or(userinfo);
- server.set('@');
- server.or(hostport);
- }
-
-
- /**
- * BitSet for reg_name.
- * <p><blockquote><pre>
- * reg_name = 1*( unreserved | escaped | "$" | "," |
- * ";" | ":" | "@" | "&amp;" | "=" | "+" )
- * </pre></blockquote><p>
- */
- protected static final BitSet reg_name = new BitSet(256);
- // Static initializer for reg_name
- static {
- reg_name.or(unreserved);
- reg_name.or(escaped);
- reg_name.set('$');
- reg_name.set(',');
- reg_name.set(';');
- reg_name.set(':');
- reg_name.set('@');
- reg_name.set('&');
- reg_name.set('=');
- reg_name.set('+');
- }
-
-
- /**
- * BitSet for authority.
- * <p><blockquote><pre>
- * authority = server | reg_name
- * </pre></blockquote><p>
- */
- protected static final BitSet authority = new BitSet(256);
- // Static initializer for authority
- static {
- authority.or(server);
- authority.or(reg_name);
- }
-
-
- /**
- * BitSet for scheme.
- * <p><blockquote><pre>
- * scheme = alpha *( alpha | digit | "+" | "-" | "." )
- * </pre></blockquote><p>
- */
- protected static final BitSet scheme = new BitSet(256);
- // Static initializer for scheme
- static {
- scheme.or(alpha);
- scheme.or(digit);
- scheme.set('+');
- scheme.set('-');
- scheme.set('.');
- }
-
-
- /**
- * BitSet for rel_segment.
- * <p><blockquote><pre>
- * rel_segment = 1*( unreserved | escaped |
- * ";" | "@" | "&amp;" | "=" | "+" | "$" | "," )
- * </pre></blockquote><p>
- */
- protected static final BitSet rel_segment = new BitSet(256);
- // Static initializer for rel_segment
- static {
- rel_segment.or(unreserved);
- rel_segment.or(escaped);
- rel_segment.set(';');
- rel_segment.set('@');
- rel_segment.set('&');
- rel_segment.set('=');
- rel_segment.set('+');
- rel_segment.set('$');
- rel_segment.set(',');
- }
-
-
- /**
- * BitSet for rel_path.
- * <p><blockquote><pre>
- * rel_path = rel_segment [ abs_path ]
- * </pre></blockquote><p>
- */
- protected static final BitSet rel_path = new BitSet(256);
- // Static initializer for rel_path
- static {
- rel_path.or(rel_segment);
- rel_path.or(abs_path);
- }
-
-
- /**
- * BitSet for net_path.
- * <p><blockquote><pre>
- * net_path = "//" authority [ abs_path ]
- * </pre></blockquote><p>
- */
- protected static final BitSet net_path = new BitSet(256);
- // Static initializer for net_path
- static {
- net_path.set('/');
- net_path.or(authority);
- net_path.or(abs_path);
- }
-
-
- /**
- * BitSet for hier_part.
- * <p><blockquote><pre>
- * hier_part = ( net_path | abs_path ) [ "?" query ]
- * </pre></blockquote><p>
- */
- protected static final BitSet hier_part = new BitSet(256);
- // Static initializer for hier_part
- static {
- hier_part.or(net_path);
- hier_part.or(abs_path);
- // hier_part.set('?'); aleady included
- hier_part.or(query);
- }
-
-
- /**
- * BitSet for relativeURI.
- * <p><blockquote><pre>
- * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- * </pre></blockquote><p>
- */
- protected static final BitSet relativeURI = new BitSet(256);
- // Static initializer for relativeURI
- static {
- relativeURI.or(net_path);
- relativeURI.or(abs_path);
- relativeURI.or(rel_path);
- // relativeURI.set('?'); aleady included
- relativeURI.or(query);
- }
-
-
- /**
- * BitSet for absoluteURI.
- * <p><blockquote><pre>
- * absoluteURI = scheme ":" ( hier_part | opaque_part )
- * </pre></blockquote><p>
- */
- protected static final BitSet absoluteURI = new BitSet(256);
- // Static initializer for absoluteURI
- static {
- absoluteURI.or(scheme);
- absoluteURI.set(':');
- absoluteURI.or(hier_part);
- absoluteURI.or(opaque_part);
- }
-
-
- /**
- * BitSet for URI-reference.
- * <p><blockquote><pre>
- * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- * </pre></blockquote><p>
- */
- protected static final BitSet URI_reference = new BitSet(256);
- // Static initializer for URI_reference
- static {
- URI_reference.or(absoluteURI);
- URI_reference.or(relativeURI);
- URI_reference.set('#');
- URI_reference.or(fragment);
- }
-
- // ---------------------------- Characters disallowed within the URI syntax
- // Excluded US-ASCII Characters are like control, space, delims and unwise
-
- /**
- * BitSet for control.
- */
- public static final BitSet control = new BitSet(256);
- // Static initializer for control
- static {
- for (int i = 0; i <= 0x1F; i++) {
- control.set(i);
- }
- control.set(0x7F);
- }
-
- /**
- * BitSet for space.
- */
- public static final BitSet space = new BitSet(256);
- // Static initializer for space
- static {
- space.set(0x20);
- }
-
-
- /**
- * BitSet for delims.
- */
- public static final BitSet delims = new BitSet(256);
- // Static initializer for delims
- static {
- delims.set('<');
- delims.set('>');
- delims.set('#');
- delims.set('%');
- delims.set('"');
- }
-
-
- /**
- * BitSet for unwise.
- */
- public static final BitSet unwise = new BitSet(256);
- // Static initializer for unwise
- static {
- unwise.set('{');
- unwise.set('}');
- unwise.set('|');
- unwise.set('\\');
- unwise.set('^');
- unwise.set('[');
- unwise.set(']');
- unwise.set('`');
- }
-
-
- /**
- * Disallowed rel_path before escaping.
- */
- public static final BitSet disallowed_rel_path = new BitSet(256);
- // Static initializer for disallowed_rel_path
- static {
- disallowed_rel_path.or(uric);
- disallowed_rel_path.andNot(rel_path);
- }
-
-
- /**
- * Disallowed opaque_part before escaping.
- */
- public static final BitSet disallowed_opaque_part = new BitSet(256);
- // Static initializer for disallowed_opaque_part
- static {
- disallowed_opaque_part.or(uric);
- disallowed_opaque_part.andNot(opaque_part);
- }
-
- // ----------------------- Characters allowed within and for each component
-
- /**
- * Those characters that are allowed for the authority component.
- */
- public static final BitSet allowed_authority = new BitSet(256);
- // Static initializer for allowed_authority
- static {
- allowed_authority.or(authority);
- allowed_authority.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the opaque_part.
- */
- public static final BitSet allowed_opaque_part = new BitSet(256);
- // Static initializer for allowed_opaque_part
- static {
- allowed_opaque_part.or(opaque_part);
- allowed_opaque_part.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the reg_name.
- */
- public static final BitSet allowed_reg_name = new BitSet(256);
- // Static initializer for allowed_reg_name
- static {
- allowed_reg_name.or(reg_name);
- // allowed_reg_name.andNot(percent);
- allowed_reg_name.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the userinfo component.
- */
- public static final BitSet allowed_userinfo = new BitSet(256);
- // Static initializer for allowed_userinfo
- static {
- allowed_userinfo.or(userinfo);
- // allowed_userinfo.andNot(percent);
- allowed_userinfo.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for within the userinfo component.
- */
- public static final BitSet allowed_within_userinfo = new BitSet(256);
- // Static initializer for allowed_within_userinfo
- static {
- allowed_within_userinfo.or(within_userinfo);
- allowed_within_userinfo.clear('%');
- }
-
-
- /**
- * Those characters that are allowed for the IPv6reference component.
- * The characters '[', ']' in IPv6reference should be excluded.
- */
- public static final BitSet allowed_IPv6reference = new BitSet(256);
- // Static initializer for allowed_IPv6reference
- static {
- allowed_IPv6reference.or(IPv6reference);
- // allowed_IPv6reference.andNot(unwise);
- allowed_IPv6reference.clear('[');
- allowed_IPv6reference.clear(']');
- }
-
-
- /**
- * Those characters that are allowed for the host component.
- * The characters '[', ']' in IPv6reference should be excluded.
- */
- public static final BitSet allowed_host = new BitSet(256);
- // Static initializer for allowed_host
- static {
- allowed_host.or(hostname);
- allowed_host.or(allowed_IPv6reference);
- }
-
-
- /**
- * Those characters that are allowed for the authority component.
- */
- public static final BitSet allowed_within_authority = new BitSet(256);
- // Static initializer for allowed_within_authority
- static {
- allowed_within_authority.or(server);
- allowed_within_authority.or(reg_name);
- allowed_within_authority.clear(';');
- allowed_within_authority.clear(':');
- allowed_within_authority.clear('@');
- allowed_within_authority.clear('?');
- allowed_within_authority.clear('/');
- }
-
-
- /**
- * Those characters that are allowed for the abs_path.
- */
- public static final BitSet allowed_abs_path = new BitSet(256);
- // Static initializer for allowed_abs_path
- static {
- allowed_abs_path.or(abs_path);
- // allowed_abs_path.set('/'); // aleady included
- allowed_abs_path.andNot(percent);
- }
-
-
- /**
- * Those characters that are allowed for the rel_path.
- */
- public static final BitSet allowed_rel_path = new BitSet(256);
- // Static initializer for allowed_rel_path
- static {
- allowed_rel_path.or(rel_path);
- allowed_rel_path.clear('%');
- }
-
-
- /**
- * Those characters that are allowed within the path.
- */
- public static final BitSet allowed_within_path = new BitSet(256);
- // Static initializer for allowed_within_path
- static {
- allowed_within_path.or(abs_path);
- allowed_within_path.clear('/');
- allowed_within_path.clear(';');
- allowed_within_path.clear('=');
- allowed_within_path.clear('?');
- }
-
-
- /**
- * Those characters that are allowed for the query component.
- */
- public static final BitSet allowed_query = new BitSet(256);
- // Static initializer for allowed_query
- static {
- allowed_query.or(uric);
- allowed_query.clear('%');
- }
-
-
- /**
- * Those characters that are allowed within the query component.
- */
- public static final BitSet allowed_within_query = new BitSet(256);
- // Static initializer for allowed_within_query
- static {
- allowed_within_query.or(allowed_query);
- allowed_within_query.andNot(reserved); // excluded 'reserved'
- allowed_within_query.clear('#'); // avoid confict with the fragment
- }
-
-
- /**
- * Those characters that are allowed for the fragment component.
- */
- public static final BitSet allowed_fragment = new BitSet(256);
- // Static initializer for allowed_fragment
- static {
- allowed_fragment.or(uric);
- allowed_fragment.clear('%');
- }
-
- // ------------------------------------------- Flags for this URI-reference
-
- // URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- // absoluteURI = scheme ":" ( hier_part | opaque_part )
- protected boolean _is_hier_part;
- protected boolean _is_opaque_part;
- // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- // hier_part = ( net_path | abs_path ) [ "?" query ]
- protected boolean _is_net_path;
- protected boolean _is_abs_path;
- protected boolean _is_rel_path;
- // net_path = "//" authority [ abs_path ]
- // authority = server | reg_name
- protected boolean _is_reg_name;
- protected boolean _is_server; // = _has_server
- // server = [ [ userinfo "@" ] hostport ]
- // host = hostname | IPv4address | IPv6reference
- protected boolean _is_hostname;
- protected boolean _is_IPv4address;
- protected boolean _is_IPv6reference;
-
- // ------------------------------------------ Character and escape encoding
-
- /**
- * Encode with the default protocol charset.
- *
- * @param original the original character sequence
- * @param allowed those characters that are allowed within a component
- * @return URI character sequence
- * @exception IOException null component or unsupported character encoding
- */
- protected static char[] encode(String original, BitSet allowed)
- throws IOException {
-
- return encode(original, allowed, _protocolCharset);
- }
-
-
- /**
- * Encodes URI string.
- *
- * This is a two mapping, one from original characters to octets, and
- * subsequently a second from octets to URI characters:
- * <p><blockquote><pre>
- * original character sequence->octet sequence->URI character sequence
- * </pre></blockquote><p>
- *
- * An escaped octet is encoded as a character triplet, consisting of the
- * percent character "%" followed by the two hexadecimal digits
- * representing the octet code. For example, "%20" is the escaped
- * encoding for the US-ASCII space character.
- * <p>
- * Conversion from the local filesystem character set to UTF-8 will
- * normally involve a two step process. First convert the local character
- * set to the UCS; then convert the UCS to UTF-8.
- * The first step in the process can be performed by maintaining a mapping
- * table that includes the local character set code and the corresponding
- * UCS code.
- * The next step is to convert the UCS character code to the UTF-8 encoding.
- * <p>
- * Mapping between vendor codepages can be done in a very similar manner
- * as described above.
- * <p>
- * The only time escape encodings can allowedly be made is when a URI is
- * being created from its component parts. The escape and validate methods
- * are internally performed within this method.
- *
- * @param original the original character sequence
- * @param allowed those characters that are allowed within a component
- * @param charset the protocol charset
- * @return URI character sequence
- * @exception IOException null component or unsupported character encoding
- */
- protected static char[] encode(String original, BitSet allowed,
- String charset) throws IOException {
-
- // encode original to uri characters.
- if (original == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: null");
- }
- // escape octet to uri characters.
- if (allowed == null) {
- throw new IOException(/*IOException.PARSING,*/
- "URI: null allowed characters");
- }
- byte[] octets;
- try {
- octets = original.getBytes(charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/*IOException.UNSUPPORTED_ENCODING,*/ "Unsupported Encoding: " + charset);
- }
- StringBuffer buf = new StringBuffer(octets.length);
- for (int i = 0; i < octets.length; i++) {
- char c = (char) octets[i];
- if (allowed.get(c)) {
- buf.append(c);
- } else {
- buf.append('%');
- byte b = octets[i]; // use the original byte value
- char hexadecimal = Character.forDigit((b >> 4) & 0xF, 16);
- buf.append(Character.toUpperCase(hexadecimal)); // high
- hexadecimal = Character.forDigit(b & 0xF, 16);
- buf.append(Character.toUpperCase(hexadecimal)); // low
- }
- }
-
- return buf.toString().toCharArray();
- }
-
-
- /**
- * Decode with the default protocol charset.
- *
- * @param component the URI character sequence
- * @return original character sequence
- * @exception IOException incomplete trailing escape pattern
- * or unsupported character encoding
- */
- protected static String decode(char[] component) throws IOException {
- return decode(component, _protocolCharset);
- }
-
-
- /**
- * Decodes URI encoded string.
- *
- * This is a two mapping, one from URI characters to octets, and
- * subsequently a second from octets to original characters:
- * <p><blockquote><pre>
- * URI character sequence->octet sequence->original character sequence
- * </pre></blockquote><p>
- *
- * A URI must be separated into its components before the escaped
- * characters within those components can be allowedly decoded.
- * <p>
- * Notice that there is a chance that URI characters that are non UTF-8
- * may be parsed as valid UTF-8. A recent non-scientific analysis found
- * that EUC encoded Japanese words had a 2.7% false reading; SJIS had a
- * 0.0005% false reading; other encoding such as ASCII or KOI-8 have a 0%
- * false reading.
- * <p>
- * The percent "%" character always has the reserved purpose of being
- * the escape indicator, it must be escaped as "%25" in order to be used
- * as data within a URI.
- * <p>
- * The unescape method is internally performed within this method.
- *
- * @param component the URI character sequence
- * @param charset the protocol charset
- * @return original character sequence
- * @exception IOException incomplete trailing escape pattern
- * or unsupported character encoding
- */
- protected static String decode(char[] component, String charset)
- throws IOException {
-
- // unescape uri characters to octets
- if (component == null) return null;
-
- byte[] octets;
- try {
- octets = new String(component).getBytes(charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
- "URI: not supported " + charset + " encoding");
- }
- int length = octets.length;
- int oi = 0; // output index
- for (int ii = 0; ii < length; oi++) {
- byte aByte = (byte) octets[ii++];
- if (aByte == '%' && ii+2 <= length) {
- byte high = (byte) Character.digit((char) octets[ii++], 16);
- byte low = (byte) Character.digit((char) octets[ii++], 16);
- if (high == -1 || low == -1) {
- throw new IOException(/* IOException.ESCAPING, */
- "URI: incomplete trailing escape pattern");
-
- }
- aByte = (byte) ((high << 4) + low);
- }
- octets[oi] = (byte) aByte;
- }
-
- String result;
- try {
- result = new String(octets, 0, oi, charset);
- } catch (UnsupportedEncodingException error) {
- throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
- "URI: not supported " + charset + " encoding");
- }
-
- return result;
- }
-
-
- /**
- * Pre-validate the unescaped URI string within a specific component.
- *
- * @param component the component string within the component
- * @param disallowed those characters disallowed within the component
- * @return if true, it doesn't have the disallowed characters
- * if false, the component is undefined or an incorrect one
- */
- protected boolean prevalidate(String component, BitSet disallowed) {
- // prevalidate the given component by disallowed characters
- if (component == null) {
- return false; // undefined
- }
- char[] target = component.toCharArray();
- for (int i = 0; i < target.length; i++) {
- if (disallowed.get(target[i])) {
- return false;
- }
- }
- return true;
- }
-
-
- /**
- * Validate the URI characters within a specific component.
- * The component must be performed after escape encoding. Or it doesn't
- * include escaped characters.
- *
- * @param component the characters sequence within the component
- * @param generous those characters that are allowed within a component
- * @return if true, it's the correct URI character sequence
- */
- protected boolean validate(char[] component, BitSet generous) {
- // validate each component by generous characters
- return validate(component, 0, -1, generous);
- }
-
-
- /**
- * Validate the URI characters within a specific component.
- * The component must be performed after escape encoding. Or it doesn't
- * include escaped characters.
- * <p>
- * It's not that much strict, generous. The strict validation might be
- * performed before being called this method.
- *
- * @param component the characters sequence within the component
- * @param soffset the starting offset of the given component
- * @param eoffset the ending offset of the given component
- * if -1, it means the length of the component
- * @param generous those characters that are allowed within a component
- * @return if true, it's the correct URI character sequence
- * @throws NullPointerException null component
- */
- protected boolean validate(char[] component, int soffset, int eoffset,
- BitSet generous) {
- // validate each component by generous characters
- if (eoffset == -1) {
- eoffset = component.length -1;
- }
- for (int i = soffset; i <= eoffset; i++) {
- if (!generous.get(component[i])) return false;
- }
- return true;
- }
-
-
- /**
- * In order to avoid any possilbity of conflict with non-ASCII characters,
- * Parse a URI reference as a <code>String</code> with the character
- * encoding of the local system or the document.
- * <p>
- * The following line is the regular expression for breaking-down a URI
- * reference into its components.
- * <p><blockquote><pre>
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * 12 3 4 5 6 7 8 9
- * </pre></blockquote><p>
- * For example, matching the above expression to
- * http://jakarta.apache.org/ietf/uri/#Related
- * results in the following subexpression matches:
- * <p><blockquote><pre>
- * $1 = http:
- * scheme = $2 = http
- * $3 = //jakarta.apache.org
- * authority = $4 = jakarta.apache.org
- * path = $5 = /ietf/uri/
- * $6 = <undefined>
- * query = $7 = <undefined>
- * $8 = #Related
- * fragment = $9 = Related
- * </pre></blockquote><p>
- *
- * @param original the original character sequence
- * @param escaped <code>true</code> if <code>original</code> is escaped
- * @return the original character sequence
- * @exception IOException
- */
- protected void parseUriReference(String original, boolean escaped)
- throws IOException {
-
- // validate and contruct the URI character sequence
- if (original == null || original.length() == 0) {
- throw new IOException("URI-Reference required");
- }
-
- /** @
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- */
- String tmp = original.trim();
-
- /**
- * The length of the string sequence of characters.
- * It may not be equal to the length of the byte array.
- */
- int length = tmp.length();
-
- /**
- * Remove the delimiters like angle brackets around an URI.
- */
- char[] firstDelimiter = { tmp.charAt(0) };
- if (validate(firstDelimiter, delims)) {
- if (length >= 2) {
- char[] lastDelimiter = { tmp.charAt(length - 1) };
- if (validate(lastDelimiter, delims)) {
- tmp = tmp.substring(1, length - 1);
- length = length - 2;
- }
- }
- }
-
- /**
- * The starting index
- */
- int from = 0;
-
- /**
- * The test flag whether the URI is started from the path component.
- */
- boolean isStartedFromPath = false;
- int atColon = tmp.indexOf(':');
- int atSlash = tmp.indexOf('/');
- if (atColon < 0 || (atSlash >= 0 && atSlash < atColon)) {
- isStartedFromPath = true;
- }
-
- /**
- * <p><blockquote><pre>
- * @@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- int at = indexFirstOf(tmp, isStartedFromPath ? "/?#" : ":/?#", from);
- if (at == -1) at = 0;
-
- /**
- * Parse the scheme.
- * <p><blockquote><pre>
- * scheme = $2 = http
- * @
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (at < length && tmp.charAt(at) == ':') {
- char[] target = tmp.substring(0, at).toLowerCase().toCharArray();
- if (validate(target, scheme)) {
- _scheme = target;
- } else {
- throw new IOException("incorrect scheme");
- }
- from = ++at;
- }
-
- /**
- * Parse the authority component.
- * <p><blockquote><pre>
- * authority = $4 = jakarta.apache.org
- * @@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- // Reset flags
- _is_net_path = _is_abs_path = _is_rel_path = _is_hier_part = false;
- if (0 <= at && at < length && tmp.charAt(at) == '/') {
- // Set flag
- _is_hier_part = true;
- if (at + 2 < length && tmp.charAt(at + 1) == '/') {
- // the temporary index to start the search from
- int next = indexFirstOf(tmp, "/?#", at + 2);
- if (next == -1) {
- next = (tmp.substring(at + 2).length() == 0) ? at + 2 :
- tmp.length();
- }
- parseAuthority(tmp.substring(at + 2, next), escaped);
- from = at = next;
- // Set flag
- _is_net_path = true;
- }
- if (from == at) {
- // Set flag
- _is_abs_path = true;
- }
- }
-
- /**
- * Parse the path component.
- * <p><blockquote><pre>
- * path = $5 = /ietf/uri/
- * @@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (from < length) {
- // rel_path = rel_segment [ abs_path ]
- int next = indexFirstOf(tmp, "?#", from);
- if (next == -1) {
- next = tmp.length();
- }
- if (!_is_abs_path) {
- if (!escaped && prevalidate(tmp.substring(from, next),
- disallowed_rel_path) || escaped &&
- validate(tmp.substring(from, next).toCharArray(),
- rel_path)) {
- // Set flag
- _is_rel_path = true;
- } else if (!escaped && prevalidate(tmp.substring(from, next),
- disallowed_opaque_part) || escaped &&
- validate(tmp.substring(from, next).toCharArray(),
- opaque_part)) {
- // Set flag
- _is_opaque_part = true;
- } else {
- // the path component may be empty
- _path = null;
- }
- }
- setPath(tmp.substring(from, next));
- at = next;
- }
-
- /**
- * Parse the query component.
- * <p><blockquote><pre>
- * query = $7 = <undefined>
- * @@@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (0 <= at && at+1 < length && tmp.charAt(at) == '?') {
- int next = tmp.indexOf('#', at + 1);
- if (next == -1) {
- next = tmp.length();
- }
- _query = (escaped) ? tmp.substring(at + 1, next).toCharArray() :
- encode(tmp.substring(at + 1, next), allowed_query);
- at = next;
- }
-
- /**
- * Parse the fragment component.
- * <p><blockquote><pre>
- * fragment = $9 = Related
- * @@@@@@@@
- * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- * </pre></blockquote><p>
- */
- if (0 <= at && at+1 < length && tmp.charAt(at) == '#') {
- _fragment = (escaped) ? tmp.substring(at + 1).toCharArray() :
- encode(tmp.substring(at + 1), allowed_fragment);
- }
-
- // set this URI.
- setUriReference();
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given string.
- *
- * @param s the string to be indexed
- * @param delims the delimiters used to index
- * @return the earlier index if there are delimiters
- */
- protected int indexFirstOf(String s, String delims) {
- return indexFirstOf(s, delims, -1);
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given string.
- *
- * @param s the string to be indexed
- * @param delims the delimiters used to index
- * @param offset the from index
- * @return the earlier index if there are delimiters
- */
- protected int indexFirstOf(String s, String delims, int offset) {
- if (s == null || s.length() == 0) {
- return -1;
- }
- if (delims == null || delims.length() == 0) {
- return -1;
- }
- // check boundaries
- if (offset < 0) {
- offset = 0;
- } else if (offset > s.length()) {
- return -1;
- }
- // s is never null
- int min = s.length();
- char[] delim = delims.toCharArray();
- for (int i = 0; i < delim.length; i++) {
- int at = s.indexOf(delim[i], offset);
- if (at >= 0 && at < min) {
- min = at;
- }
- }
- return (min == s.length()) ? -1 : min;
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given array.
- *
- * @param s the character array to be indexed
- * @param delim the delimiter used to index
- * @return the ealier index if there are a delimiter
- */
- protected int indexFirstOf(char[] s, char delim) {
- return indexFirstOf(s, delim, 0);
- }
-
-
- /**
- * Get the earlier index that to be searched for the first occurrance in
- * one of any of the given array.
- *
- * @param s the character array to be indexed
- * @param delim the delimiter used to index
- * @return the ealier index if there is a delimiter
- */
- protected int indexFirstOf(char[] s, char delim, int offset) {
- if (s == null || s.length == 0) {
- return -1;
- }
- // check boundaries
- if (offset < 0) {
- offset = 0;
- } else if (offset > s.length) {
- return -1;
- }
- for (int i = offset; i < s.length; i++) {
- if (s[i] == delim) {
- return i;
- }
- }
- return -1;
- }
-
-
- /**
- * Parse the authority component.
- *
- * @param original the original character sequence of authority component
- * @param escaped <code>true</code> if <code>original</code> is escaped
- * @exception IOException
- */
- protected void parseAuthority(String original, boolean escaped)
- throws IOException {
-
- // Reset flags
- _is_reg_name = _is_server =
- _is_hostname = _is_IPv4address = _is_IPv6reference = false;
-
- boolean has_port = true;
- int from = 0;
- int next = original.indexOf('@');
- if (next != -1) { // neither -1 and 0
- // each protocol extented from URI supports the specific userinfo
- _userinfo = (escaped) ? original.substring(0, next).toCharArray() :
- encode(original.substring(0, next), allowed_userinfo);
- from = next + 1;
- }
- next = original.indexOf('[', from);
- if (next >= from) {
- next = original.indexOf(']', from);
- if (next == -1) {
- throw new IOException(/* IOException.PARSING,*/ "URI: IPv6reference");
- } else {
- next++;
- }
- // In IPv6reference, '[', ']' should be excluded
- _host = (escaped) ? original.substring(from, next).toCharArray() :
- encode(original.substring(from, next), allowed_IPv6reference);
- // Set flag
- _is_IPv6reference = true;
- } else { // only for !_is_IPv6reference
- next = original.indexOf(':', from);
- if (next == -1) {
- next = original.length();
- has_port = false;
- }
- // REMINDME: it doesn't need the pre-validation
- _host = original.substring(from, next).toCharArray();
- if (validate(_host, IPv4address)) {
- // Set flag
- _is_IPv4address = true;
- } else if (validate(_host, hostname)) {
- // Set flag
- _is_hostname = true;
- } else {
- // Set flag
- _is_reg_name = true;
- }
- }
- if (_is_reg_name) {
- // Reset flags for a server-based naming authority
- _is_server = _is_hostname = _is_IPv4address =
- _is_IPv6reference = false;
- // set a registry-based naming authority
- _authority = (escaped) ? original.toString().toCharArray() :
- encode(original.toString(), allowed_reg_name);
- } else {
- if (original.length()-1 > next && has_port &&
- original.charAt(next) == ':') { // not empty
- from = next + 1;
- try {
- _port = Integer.parseInt(original.substring(from));
- } catch (NumberFormatException error) {
- throw new IOException(/*IOException.PARSING, */
- "URI: invalid port number");
- }
- }
- // set a server-based naming authority
- StringBuffer buf = new StringBuffer();
- if (_userinfo != null) { // has_userinfo
- buf.append(_userinfo);
- buf.append('@');
- }
- if (_host != null) {
- buf.append(_host);
- if (_port != -1) {
- buf.append(':');
- buf.append(_port);
- }
- }
- _authority = buf.toString().toCharArray();
- // Set flag
- _is_server = true;
- }
- }
-
-
- /**
- * Once it's parsed successfully, set this URI.
- *
- * @see #getRawURI
- */
- protected void setUriReference() {
- // set _uri
- StringBuffer buf = new StringBuffer();
- // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- if (_scheme != null) {
- buf.append(_scheme);
- buf.append(':');
- }
- if (_is_net_path) {
- buf.append("//");
- if (_authority != null) { // has_authority
- if (_userinfo != null) { // by default, remove userinfo part
- if (_host != null) {
- buf.append(_host);
- if (_port != -1) {
- buf.append(':');
- buf.append(_port);
- }
- }
- } else {
- buf.append(_authority);
- }
- }
- }
- if (_opaque != null && _is_opaque_part) {
- buf.append(_opaque);
- } else if (_path != null) {
- // _is_hier_part or _is_relativeURI
- if (_path.length != 0) {
- buf.append(_path);
- }
- }
- if (_query != null) { // has_query
- buf.append('?');
- buf.append(_query);
- }
- if (_fragment != null) { // has_fragment
- buf.append('#');
- buf.append(_fragment);
- }
-
- _uri = buf.toString().toCharArray();
- }
-
- // ----------------------------------------------------------- Test methods
-
-
- /**
- * Tell whether or not this URI is absolute.
- *
- * @return true iif this URI is absoluteURI
- */
- public boolean isAbsoluteURI() {
- return (_scheme != null);
- }
-
-
- /**
- * Tell whether or not this URI is relative.
- *
- * @return true iif this URI is relativeURI
- */
- public boolean isRelativeURI() {
- return (_scheme == null);
- }
-
-
- /**
- * Tell whether or not the absoluteURI of this URI is hier_part.
- *
- * @return true iif the absoluteURI is hier_part
- */
- public boolean isHierPart() {
- return _is_hier_part;
- }
-
-
- /**
- * Tell whether or not the absoluteURI of this URI is opaque_part.
- *
- * @return true iif the absoluteURI is opaque_part
- */
- public boolean isOpaquePart() {
- return _is_opaque_part;
- }
-
-
- /**
- * Tell whether or not the relativeURI or heir_part of this URI is net_path.
- * It's the same function as the has_authority() method.
- *
- * @return true iif the relativeURI or heir_part is net_path
- * @see #hasAuthority
- */
- public boolean isNetPath() {
- return _is_net_path || (_authority != null);
- }
-
-
- /**
- * Tell whether or not the relativeURI or hier_part of this URI is abs_path.
- *
- * @return true iif the relativeURI or hier_part is abs_path
- */
- public boolean isAbsPath() {
- return _is_abs_path;
- }
-
-
- /**
- * Tell whether or not the relativeURI of this URI is rel_path.
- *
- * @return true iif the relativeURI is rel_path
- */
- public boolean isRelPath() {
- return _is_rel_path;
- }
-
-
- /**
- * Tell whether or not this URI has authority.
- * It's the same function as the is_net_path() method.
- *
- * @return true iif this URI has authority
- * @see #isNetPath
- */
- public boolean hasAuthority() {
- return (_authority != null) || _is_net_path;
- }
-
- /**
- * Tell whether or not the authority component of this URI is reg_name.
- *
- * @return true iif the authority component is reg_name
- */
- public boolean isRegName() {
- return _is_reg_name;
- }
-
-
- /**
- * Tell whether or not the authority component of this URI is server.
- *
- * @return true iif the authority component is server
- */
- public boolean isServer() {
- return _is_server;
- }
-
-
- /**
- * Tell whether or not this URI has userinfo.
- *
- * @return true iif this URI has userinfo
- */
- public boolean hasUserinfo() {
- return (_userinfo != null);
- }
-
-
- /**
- * Tell whether or not the host part of this URI is hostname.
- *
- * @return true iif the host part is hostname
- */
- public boolean isHostname() {
- return _is_hostname;
- }
-
-
- /**
- * Tell whether or not the host part of this URI is IPv4address.
- *
- * @return true iif the host part is IPv4address
- */
- public boolean isIPv4address() {
- return _is_IPv4address;
- }
-
-
- /**
- * Tell whether or not the host part of this URI is IPv6reference.
- *
- * @return true iif the host part is IPv6reference
- */
- public boolean isIPv6reference() {
- return _is_IPv6reference;
- }
-
-
- /**
- * Tell whether or not this URI has query.
- *
- * @return true iif this URI has query
- */
- public boolean hasQuery() {
- return (_query != null);
- }
-
-
- /**
- * Tell whether or not this URI has fragment.
- *
- * @return true iif this URI has fragment
- */
- public boolean hasFragment() {
- return (_fragment != null);
- }
-
-
- // ---------------------------------------------------------------- Charset
-
-
- /**
- * Set the default charset of the protocol.
- * <p>
- * The character set used to store files SHALL remain a local decision and
- * MAY depend on the capability of local operating systems. Prior to the
- * exchange of URIs they SHOULD be converted into a ISO/IEC 10646 format
- * and UTF-8 encoded. This approach, while allowing international exchange
- * of URIs, will still allow backward compatibility with older systems
- * because the code set positions for ASCII characters are identical to the
- * one byte sequence in UTF-8.
- * <p>
- * An individual URI scheme may require a single charset, define a default
- * charset, or provide a way to indicate the charset used.
- *
- * @param charset the default charset for each protocol
- */
- public static void setProtocolCharset(String charset) {
- _protocolCharset = charset;
- }
-
-
- /**
- * Get the default charset of the protocol.
- * <p>
- * An individual URI scheme may require a single charset, define a default
- * charset, or provide a way to indicate the charset used.
- * <p>
- * To work globally either requires support of a number of character sets
- * and to be able to convert between them, or the use of a single preferred
- * character set.
- * For support of global compatibility it is STRONGLY RECOMMENDED that
- * clients and servers use UTF-8 encoding when exchanging URIs.
- *
- * @return the charset string
- */
- public static String getProtocolCharset() {
- return _protocolCharset;
- }
-
-
- /**
- * Set the default charset of the document.
- * <p>
- * Notice that it will be possible to contain mixed characters (e.g.
- * ftp://host/KoreanNamespace/ChineseResource). To handle the Bi-directional
- * display of these character sets, the protocol charset could be simply
- * used again. Because it's not yet implemented that the insertion of BIDI
- * control characters at different points during composition is extracted.
- *
- * @param charset the default charset for the document
- */
- public static void setDocumentCharset(String charset) {
- _documentCharset = charset;
- }
-
-
- /**
- * Get the default charset of the document.
- *
- * @return the charset string
- */
- public static String getDocumentCharset() {
- return _documentCharset;
- }
-
- // ------------------------------------------------------------- The scheme
-
- /**
- * Get the scheme.
- *
- * @return the scheme
- */
- public char[] getRawScheme() {
- return _scheme;
- }
-
-
- /**
- * Get the scheme.
- *
- * @return the scheme
- * null if undefined scheme
- */
- public String getScheme() {
- return (_scheme == null) ? null : new String(_scheme);
- }
-
- // ---------------------------------------------------------- The authority
-
- /**
- * Set the authority. It can be one type of server, hostport, hostname,
- * IPv4address, IPv6reference and reg_name.
- * <p><blockquote><pre>
- * authority = server | reg_name
- * </pre></blockquote><p>
- *
- * @param escapedAuthority the raw escaped authority
- * @exception IOException
- * @throws NullPointerException null authority
- */
- public void setRawAuthority(char[] escapedAuthority) throws IOException {
- parseAuthority(new String(escapedAuthority), true);
- setUriReference();
- }
-
-
- /**
- * Set the authority. It can be one type of server, hostport, hostname,
- * IPv4address, IPv6reference and reg_name.
- * Note that there is no setAuthority method by the escape encoding reason.
- *
- * @param escapedAuthority the escaped authority string
- * @exception IOException
- */
- public void setEscapedAuthority(String escapedAuthority)
- throws IOException {
-
- parseAuthority(escapedAuthority, true);
- setUriReference();
- }
-
-
- /**
- * Get the raw-escaped authority.
- *
- * @return the raw-escaped authority
- */
- public char[] getRawAuthority() {
- return _authority;
- }
-
-
- /**
- * Get the escaped authority.
- *
- * @return the escaped authority
- */
- public String getEscapedAuthority() {
- return (_authority == null) ? null : new String(_authority);
- }
-
-
- /**
- * Get the authority.
- *
- * @return the authority
- * @exception IOException
- * @see #decode
- */
- public String getAuthority() throws IOException {
- return (_authority == null) ? null : decode(_authority);
- }
-
- // ----------------------------------------------------------- The userinfo
-
- /**
- * Get the raw-escaped userinfo.
- *
- * @return the raw-escaped userinfo
- * @see #getAuthority
- */
- public char[] getRawUserinfo() {
- return _userinfo;
- }
-
-
- /**
- * Get the escaped userinfo.
- *
- * @return the escaped userinfo
- * @see #getAuthority
- */
- public String getEscapedUserinfo() {
- return (_userinfo == null) ? null : new String(_userinfo);
- }
-
-
- /**
- * Get the userinfo.
- *
- * @return the userinfo
- * @exception IOException
- * @see #decode
- * @see #getAuthority
- */
- public String getUserinfo() throws IOException {
- return (_userinfo == null) ? null : decode(_userinfo);
- }
-
- // --------------------------------------------------------------- The host
-
- /**
- * Get the host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- *
- * @return the host
- * @see #getAuthority
- */
- public char[] getRawHost() {
- return _host;
- }
-
-
- /**
- * Get the host.
- * <p><blockquote><pre>
- * host = hostname | IPv4address | IPv6reference
- * </pre></blockquote><p>
- *
- * @return the host
- * @exception IOException
- * @see #decode
- * @see #getAuthority
- */
- public String getHost() throws IOException {
- return decode(_host);
- }
-
- // --------------------------------------------------------------- The port
-
- /**
- * Get the port. In order to get the specfic default port, the specific
- * protocol-supported class extended from the URI class should be used.
- * It has the server-based naming authority.
- *
- * @return the port
- * if -1, it has the default port for the scheme or the server-based
- * naming authority is not supported in the specific URI.
- */
- public int getPort() {
- return _port;
- }
-
- // --------------------------------------------------------------- The path
-
- /**
- * Set the path. The method couldn't be used by API programmers.
- *
- * @param path the path string
- * @exception IOException set incorrectly or fragment only
- * @see #encode
- */
- protected void setPath(String path) throws IOException {
-
- // set path
- if (_is_net_path || _is_abs_path) {
- _path = encode(path, allowed_abs_path);
- } else if (_is_rel_path) {
- StringBuffer buff = new StringBuffer(path.length());
- int at = path.indexOf('/');
- if (at > 0) { // never 0
- buff.append(encode(path.substring(0, at), allowed_rel_path));
- buff.append(encode(path.substring(at), allowed_abs_path));
- } else {
- buff.append(encode(path, allowed_rel_path));
- }
- _path = buff.toString().toCharArray();
- } else if (_is_opaque_part) {
- _opaque = encode(path, allowed_opaque_part);
- } else {
- throw new IOException(/*IOException.PARSING, */"URI: incorrect path");
- }
- }
-
-
- /**
- * Resolve the base and relative path.
- *
- * @param base_path a character array of the base_path
- * @param rel_path a character array of the rel_path
- * @return the resolved path
- */
- protected char[] resolvePath(char[] base_path, char[] rel_path) {
-
- // REMINDME: paths are never null
- String base = (base_path == null) ? "" : new String(base_path);
- int at = base.lastIndexOf('/');
- if (at != -1) {
- base_path = base.substring(0, at + 1).toCharArray();
- }
- // _path could be empty
- if (rel_path == null || rel_path.length == 0) {
- return normalize(base_path);
- } else if (rel_path[0] == '/') {
- return rel_path;
- } else {
- StringBuffer buff = new StringBuffer(base.length() +
- rel_path.length);
- if (at != -1) {
- buff.append(base.substring(0, at + 1));
- buff.append(rel_path);
- }
- return normalize(buff.toString().toCharArray());
- }
- }
-
-
- /**
- * Get the raw-escaped current hierarchy level in the given path.
- * If the last namespace is a collection, the slash mark ('/') should be
- * ended with at the last character of the path string.
- *
- * @param path the path
- * @return the current hierarchy level
- * @exception IOException no hierarchy level
- */
- protected char[] getRawCurrentHierPath(char[] path) throws IOException {
-
- if (_is_opaque_part) {
- throw new IOException(/*IOException.PARSING,*/ "URI: no hierarchy level");
- }
- if (path == null) {
- throw new IOException(/*IOException.PARSING,*/ "URI: emtpy path");
- }
- String buff = new String(path);
- int first = buff.indexOf('/');
- int last = buff.lastIndexOf('/');
- if (last == 0) {
- return rootPath;
- } else if (first != last && last != -1) {
- return buff.substring(0, last).toCharArray();
- }
- // FIXME: it could be a document on the server side
- return path;
- }
-
-
- /**
- * Get the raw-escaped current hierarchy level.
- *
- * @return the raw-escaped current hierarchy level
- * @exception IOException no hierarchy level
- */
- public char[] getRawCurrentHierPath() throws IOException {
- return (_path == null) ? null : getRawCurrentHierPath(_path);
- }
-
-
- /**
- * Get the escaped current hierarchy level.
- *
- * @return the escaped current hierarchy level
- * @exception IOException no hierarchy level
- */
- public String getEscapedCurrentHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the current hierarchy level.
- *
- * @return the current hierarchy level
- * @exception IOException
- * @see #decode
- */
- public String getCurrentHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the raw above hierarchy level
- * @exception IOException
- */
- public char[] getRawAboveHierPath() throws IOException {
- char[] path = getRawCurrentHierPath();
- return (path == null) ? null : getRawCurrentHierPath(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the raw above hierarchy level
- * @exception IOException
- */
- public String getEscapedAboveHierPath() throws IOException {
- char[] path = getRawAboveHierPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the level above the this hierarchy level.
- *
- * @return the above hierarchy level
- * @exception IOException
- * @see #decode
- */
- public String getAboveHierPath() throws IOException {
- char[] path = getRawAboveHierPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the raw-escaped path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- *
- * @return the raw-escaped path
- */
- public char[] getRawPath() {
- return _is_opaque_part ? _opaque : _path;
- }
-
-
- /**
- * Get the escaped path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * abs_path = "/" path_segments
- * opaque_part = uric_no_slash *uric
- * </pre></blockquote><p>
- *
- * @return the escaped path string
- */
- public String getEscapedPath() {
- char[] path = getRawPath();
- return (path == null) ? null : new String(path);
- }
-
-
- /**
- * Get the path.
- * <p><blockquote><pre>
- * path = [ abs_path | opaque_part ]
- * </pre></blockquote><p>
- * @return the path string
- * @exception IOException
- * @see #decode
- */
- public String getPath() throws IOException {
- char[] path = getRawPath();
- return (path == null) ? null : decode(path);
- }
-
-
- /**
- * Get the raw-escaped basename of the path.
- *
- * @return the raw-escaped basename
- */
- public char[] getRawName() {
- if (_path == null) return null;
-
- int at = 0;
- for (int i = _path.length - 1; i >= 0; i--) {
- if (_path[i] == '/') {
- at = i + 1;
- break;
- }
- }
- int len = _path.length - at;
- char[] basename = new char[len];
- System.arraycopy(_path, at, basename, 0, len);
- return basename;
- }
-
-
- /**
- * Get the escaped basename of the path.
- *
- * @return the escaped basename string
- */
- public String getEscapedName() {
- char[] basename = getRawName();
- return (basename == null) ? null : new String(basename);
- }
-
-
- /**
- * Get the basename of the path.
- *
- * @return the basename string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getName() throws IOException {
- char[] basename = getRawName();
- return (basename == null) ? null : decode(getRawName());
- }
-
- // ----------------------------------------------------- The path and query
-
- /**
- * Get the raw-escaped path and query.
- *
- * @return the raw-escaped path and query
- */
- public char[] getRawPathQuery() {
-
- if (_path == null && _query == null) {
- return null;
- }
- StringBuffer buff = new StringBuffer();
- if (_path != null) {
- buff.append(_path);
- }
- if (_query != null) {
- buff.append('?');
- buff.append(_query);
- }
- return buff.toString().toCharArray();
- }
-
-
- /**
- * Get the escaped query.
- *
- * @return the escaped path and query string
- */
- public String getEscapedPathQuery() {
- char[] rawPathQuery = getRawPathQuery();
- return (rawPathQuery == null) ? null : new String(rawPathQuery);
- }
-
-
- /**
- * Get the path and query.
- *
- * @return the path and query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getPathQuery() throws IOException {
- char[] rawPathQuery = getRawPathQuery();
- return (rawPathQuery == null) ? null : decode(rawPathQuery);
- }
-
- // -------------------------------------------------------------- The query
-
- /**
- * Set the raw-escaped query.
- *
- * @param escapedQuery the raw-escaped query
- * @exception IOException escaped query not valid
- * @throws NullPointerException null query
- */
- public void setRawQuery(char[] escapedQuery) throws IOException {
- if (!validate(escapedQuery, query))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped query not valid");
- _query = escapedQuery;
- setUriReference();
- }
-
-
- /**
- * Set the escaped query string.
- *
- * @param escapedQuery the escaped query string
- * @exception IOException escaped query not valid
- * @throws NullPointerException null query
- */
- public void setEscapedQuery(String escapedQuery) throws IOException {
- setRawQuery(escapedQuery.toCharArray());
- }
-
-
- /**
- * Set the query.
- * When a query string is not misunderstood the reserved special characters
- * ("&amp;", "=", "+", ",", and "$") within a query component, it is
- * recommended to use in encoding the whole query with this method.
- *
- * @param query the query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @throws NullPointerException null query
- * @see #encode
- */
- public void setQuery(String query) throws IOException {
- setRawQuery(encode(query, allowed_query));
- }
-
-
- /**
- * Get the raw-escaped query.
- *
- * @return the raw-escaped query
- */
- public char[] getRawQuery() {
- return _query;
- }
-
-
- /**
- * Get the escaped query.
- *
- * @return the escaped query string
- */
- public String getEscapedQuery() {
- return (_query == null) ? null : new String(_query);
- }
-
-
- /**
- * Get the query.
- *
- * @return the query string.
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getQuery() throws IOException {
- return (_query == null) ? null : decode(_query);
- }
-
- // ----------------------------------------------------------- The fragment
-
- /**
- * Set the raw-escaped fragment.
- *
- * @param escapedFragment the raw-escaped fragment
- * @exception IOException escaped fragment not valid
- * @throws NullPointerException null fragment
- */
- public void setRawFragment(char[] escapedFragment) throws IOException {
- if (!validate(escapedFragment, fragment))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped fragment not valid");
- _fragment = escapedFragment;
- setUriReference();
- }
-
-
- /**
- * Set the escaped fragment string.
- *
- * @param escapedFragment the escaped fragment string
- * @exception IOException escaped fragment not valid
- * @throws NullPointerException null fragment
- */
- public void setEscapedFragment(String escapedFragment) throws IOException {
- char[] fragmentSequence = escapedFragment.toCharArray();
- if (!validate(fragmentSequence, fragment))
- throw new IOException(/*IOException.ESCAPING,*/
- "URI: escaped fragment not valid");
- _fragment = fragmentSequence;
- setUriReference();
- }
-
-
- /**
- * Set the fragment.
- *
- * @param the fragment string.
- * @exception IOException
- * Or unsupported character encoding
- * @throws NullPointerException null fragment
- */
- public void setFragment(String fragment) throws IOException {
- _fragment = encode(fragment, allowed_fragment);
- setUriReference();
- }
-
-
- /**
- * Get the raw-escaped fragment.
- * <p>
- * The optional fragment identifier is not part of a URI, but is often used
- * in conjunction with a URI.
- * <p>
- * The format and interpretation of fragment identifiers is dependent on
- * the media type [RFC2046] of the retrieval result.
- * <p>
- * A fragment identifier is only meaningful when a URI reference is
- * intended for retrieval and the result of that retrieval is a document
- * for which the identified fragment is consistently defined.
- *
- * @return the raw-escaped fragment
- */
- public char[] getRawFragment() {
- return _fragment;
- }
-
-
- /**
- * Get the escaped fragment.
- *
- * @return the escaped fragment string
- */
- public String getEscapedFragment() {
- return (_fragment == null) ? null : new String(_fragment);
- }
-
-
- /**
- * Get the fragment.
- *
- * @return the fragment string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getFragment() throws IOException {
- return (_fragment == null) ? null : decode(_fragment);
- }
-
- // ------------------------------------------------------------- Utilities
-
- /**
- * Normalize the given hier path part.
- *
- * @param path the path to normalize
- * @return the normalized path
- */
- protected char[] normalize(char[] path) {
-
- if (path == null) return null;
-
- String normalized = new String(path);
- boolean endsWithSlash = true;
- // precondition
- if (!normalized.endsWith("/")) {
- normalized += '/';
- endsWithSlash = false;
- }
- if (normalized.endsWith("/./") || normalized.endsWith("/../")) {
- endsWithSlash = true;
- }
- // Resolve occurrences of "/./" in the normalized path
- while (true) {
- int at = normalized.indexOf("/./");
- if (at == -1) {
- break;
- }
- normalized = normalized.substring(0, at) +
- normalized.substring(at + 2);
- }
- // Resolve occurrences of "/../" in the normalized path
- while (true) {
- int at = normalized.indexOf("/../");
- if (at == -1) {
- break;
- }
- if (at == 0) {
- normalized = "/";
- break;
- }
- int backward = normalized.lastIndexOf('/', at - 1);
- if (backward == -1) {
- // consider the rel_path
- normalized = normalized.substring(at + 4);
- } else {
- normalized = normalized.substring(0, backward) +
- normalized.substring(at + 3);
- }
- }
- // Resolve occurrences of "//" in the normalized path
- while (true) {
- int at = normalized.indexOf("//");
- if (at == -1) {
- break;
- }
- normalized = normalized.substring(0, at) +
- normalized.substring(at + 1);
- }
- if (!endsWithSlash && normalized.endsWith("/")) {
- normalized = normalized.substring(0, normalized.length()-1);
- } else if (endsWithSlash && !normalized.endsWith("/")) {
- normalized = normalized + "/";
- }
- // Set the normalized path that we have completed
- return normalized.toCharArray();
- }
-
-
- /**
- * Normalize the path part of this URI.
- */
- public void normalize() {
- _path = normalize(_path);
- }
-
-
- /**
- * Test if the first array is equal to the second array.
- *
- * @param first the first character array
- * @param second the second character array
- * @return true if they're equal
- */
- protected boolean equals(char[] first, char[] second) {
-
- if (first == null && second == null) {
- return true;
- }
- if (first == null || second == null) {
- return false;
- }
- if (first.length != second.length) {
- return false;
- }
- for (int i = 0; i < first.length; i++) {
- if (first[i] != second[i]) {
- return false;
- }
- }
- return true;
- }
-
-
- /**
- * Test an object if this URI is equal to another.
- *
- * @param obj an object to compare
- * @return true if two URI objects are equal
- */
- public boolean equals(Object obj) {
-
- // normalize and test each components
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof URI)) {
- return false;
- }
- URI another = (URI) obj;
- // scheme
- if (!equals(_scheme, another._scheme)) {
- return false;
- }
- // is_opaque_part or is_hier_part? and opaque
- if (!equals(_opaque, another._opaque)) {
- return false;
- }
- // is_hier_part
- // has_authority
- if (!equals(_authority, another._authority)) {
- return false;
- }
- // path
- if (!equals(_path, another._path)) {
- return false;
- }
- // has_query
- if (!equals(_query, another._query)) {
- return false;
- }
- // has_fragment? should be careful of the only fragment case.
- if (!equals(_fragment, another._fragment)) {
- return false;
- }
- return true;
- }
-
- // ---------------------------------------------------------- Serialization
-
- /**
- * Write the content of this URI.
- *
- * @param oos the object-output stream
- */
- protected void writeObject(java.io.ObjectOutputStream oos)
- throws IOException {
-
- oos.defaultWriteObject();
- }
-
-
- /**
- * Read a URI.
- *
- * @param ois the object-input stream
- */
- protected void readObject(java.io.ObjectInputStream ois)
- throws ClassNotFoundException, IOException {
-
- ois.defaultReadObject();
- }
-
- // ------------------------------------------------------------- Comparison
-
- /**
- * Compare this URI to another object.
- *
- * @param obj the object to be compared.
- * @return 0, if it's same,
- * -1, if failed, first being compared with in the authority component
- * @exception ClassCastException not URI argument
- * @throws NullPointerException null object
- */
- public int compareTo(Object obj) {
-
- URI another = (URI) obj;
- if (!equals(_authority, another.getRawAuthority())) return -1;
- return toString().compareTo(another.toString());
- }
-
- // ------------------------------------------------------------------ Clone
-
- /**
- * Create and return a copy of this object, the URI-reference containing
- * the userinfo component. Notice that the whole URI-reference including
- * the userinfo component counld not be gotten as a <code>String</code>.
- * <p>
- * To copy the identical <code>URI</code> object including the userinfo
- * component, it should be used.
- *
- * @return a clone of this instance
- */
- public synchronized Object clone() {
-
- URI instance = new URI();
-
- instance._uri = _uri;
- instance._scheme = _scheme;
- instance._opaque = _opaque;
- instance._authority = _authority;
- instance._userinfo = _userinfo;
- instance._host = _host;
- instance._port = _port;
- instance._path = _path;
- instance._query = _query;
- instance._fragment = _fragment;
- // flags
- instance._is_hier_part = _is_hier_part;
- instance._is_opaque_part = _is_opaque_part;
- instance._is_net_path = _is_net_path;
- instance._is_abs_path = _is_abs_path;
- instance._is_rel_path = _is_rel_path;
- instance._is_reg_name = _is_reg_name;
- instance._is_server = _is_server;
- instance._is_hostname = _is_hostname;
- instance._is_IPv4address = _is_IPv4address;
- instance._is_IPv6reference = _is_IPv6reference;
-
- return instance;
- }
-
- // ------------------------------------------------------------ Get the URI
-
- /**
- * It can be gotten the URI character sequence. It's raw-escaped.
- * For the purpose of the protocol to be transported, it will be useful.
- * <p>
- * It is clearly unwise to use a URL that contains a password which is
- * intended to be secret. In particular, the use of a password within
- * the 'userinfo' component of a URL is strongly disrecommended except
- * in those rare cases where the 'password' parameter is intended to be
- * public.
- * <p>
- * When you want to get each part of the userinfo, you need to use the
- * specific methods in the specific URL. It depends on the specific URL.
- *
- * @return URI character sequence
- */
- public char[] getRawURI() {
- return _uri;
- }
-
-
- /**
- * It can be gotten the URI character sequence. It's escaped.
- * For the purpose of the protocol to be transported, it will be useful.
- *
- * @return the URI string
- */
- public String getEscapedURI() {
- return (_uri == null) ? null : new String(_uri);
- }
-
-
- /**
- * It can be gotten the URI character sequence.
- *
- * @return the URI string
- * @exception IOException incomplete trailing escape pattern
- * Or unsupported character encoding
- * @see #decode
- */
- public String getURI() throws IOException {
- return (_uri == null) ? null : decode(_uri);
- }
-
-
- /**
- * Get the escaped URI string.
- * <p>
- * On the document, the URI-reference form is only used without the userinfo
- * component like http://jakarta.apache.org/ by the security reason.
- * But the URI-reference form with the userinfo component could be parsed.
- * <p>
- * In other words, this URI and any its subclasses must not expose the
- * URI-reference expression with the userinfo component like
- * http://user:password@hostport/restricted_zone.<br>
- * It means that the API client programmer should extract each user and
- * password to access manually. Probably it will be supported in the each
- * subclass, however, not a whole URI-reference expression.
- *
- * @return the URI string
- * @see #clone()
- */
- public String toString() {
- return getEscapedURI();
- }
-
-
- // ------------------------------------------------------------ Inner class
-
- /**
- * A mapping to determine the (somewhat arbitrarily) preferred charset for
- * a given locale. Supports all locales recognized in JDK 1.1.
- * <p>
- * The distribution of this class is Servlets.com. It was originally
- * written by Jason Hunter [jhunter at acm.org] and used by with permission.
- */
- public static class LocaleToCharsetMap {
-
- private static Hashtable map;
- static {
- map = new Hashtable();
- map.put("ar", "ISO-8859-6");
- map.put("be", "ISO-8859-5");
- map.put("bg", "ISO-8859-5");
- map.put("ca", "ISO-8859-1");
- map.put("cs", "ISO-8859-2");
- map.put("da", "ISO-8859-1");
- map.put("de", "ISO-8859-1");
- map.put("el", "ISO-8859-7");
- map.put("en", "ISO-8859-1");
- map.put("es", "ISO-8859-1");
- map.put("et", "ISO-8859-1");
- map.put("fi", "ISO-8859-1");
- map.put("fr", "ISO-8859-1");
- map.put("hr", "ISO-8859-2");
- map.put("hu", "ISO-8859-2");
- map.put("is", "ISO-8859-1");
- map.put("it", "ISO-8859-1");
- map.put("iw", "ISO-8859-8");
- map.put("ja", "Shift_JIS");
- map.put("ko", "EUC-KR");
- map.put("lt", "ISO-8859-2");
- map.put("lv", "ISO-8859-2");
- map.put("mk", "ISO-8859-5");
- map.put("nl", "ISO-8859-1");
- map.put("no", "ISO-8859-1");
- map.put("pl", "ISO-8859-2");
- map.put("pt", "ISO-8859-1");
- map.put("ro", "ISO-8859-2");
- map.put("ru", "ISO-8859-5");
- map.put("sh", "ISO-8859-5");
- map.put("sk", "ISO-8859-2");
- map.put("sl", "ISO-8859-2");
- map.put("sq", "ISO-8859-2");
- map.put("sr", "ISO-8859-5");
- map.put("sv", "ISO-8859-1");
- map.put("tr", "ISO-8859-9");
- map.put("uk", "ISO-8859-5");
- map.put("zh", "GB2312");
- map.put("zh_TW", "Big5");
- }
-
- /**
- * Get the preferred charset for the given locale.
- *
- * @param locale the locale
- * @return the preferred charset
- * or null if the locale is not recognized
- */
- public static String getCharset(Locale locale) {
- // try for an full name match (may include country)
- String charset = (String) map.get(locale.toString());
- if (charset != null) return charset;
-
- // if a full name didn't match, try just the language
- charset = (String) map.get(locale.getLanguage());
- return charset; // may be null
- }
-
- }
+ // ----------------------------------------------------------- Constructors
+
+ protected URI() {
+ }
+
+ /**
+ * Construct a URI as an escaped form of a character array. An URI can be placed
+ * within double-quotes or angle brackets like "http://test.com/" and
+ * &lt;http://test.com/&gt;
+ *
+ * @param escaped the URI character sequence
+ * @exception IOException
+ * @throws NullPointerException if <code>escaped</code> is <code>null</code>
+ */
+ public URI(char[] escaped) throws IOException {
+ parseUriReference(new String(escaped), true);
+ }
+
+ /**
+ * Construct a URI from the given string.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * An URI can be placed within double-quotes or angle brackets like
+ * "http://test.com/" and &lt;http://test.com/&gt;
+ *
+ * @param original the string to be represented to URI character sequence It is
+ * one of absoluteURI and relativeURI.
+ * @exception IOException
+ */
+ public URI(String original) throws IOException {
+ parseUriReference(original, false);
+ }
+
+ /**
+ * Construct a URI from a URL.
+ *
+ * @param url a valid URL.
+ * @throws IOException
+ * @since 2.0
+ */
+ public URI(URL url) throws IOException {
+ this(url.toString());
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * opaque_part = uric_no_slash *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * It's for absolute URI = &lt;scheme&gt;:&lt;scheme-specific-part&gt;#
+ * &lt;fragment&gt;.
+ *
+ * @param scheme the scheme string
+ * @param scheme_specific_part scheme_specific_part
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String scheme_specific_part, String fragment) throws IOException {
+
+ // validate and contruct the URI character sequence
+ if (scheme == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: scheme required");
+ }
+ char[] s = scheme.toLowerCase().toCharArray();
+ if (validate(s, URI.scheme)) {
+ _scheme = s; // is_absoluteURI
+ } else {
+ throw new IOException(/* IOException.PARSING, */ "URI: incorrect scheme");
+ }
+ _opaque = encode(scheme_specific_part, allowed_opaque_part);
+ // Set flag
+ _is_opaque_part = true;
+ setUriReference();
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * hier_part = ( net_path | abs_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * It's for absolute URI = &lt;scheme&gt;:&lt;path&gt;?&lt;query&gt;#&lt;
+ * fragment&gt; and relative URI = &lt;path&gt;?&lt;query&gt;#&lt;fragment &gt;.
+ *
+ * @param scheme the scheme string
+ * @param authority the authority string
+ * @param path the path string
+ * @param query the query string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String authority, String path, String query, String fragment) throws IOException {
+
+ // validate and contruct the URI character sequence
+ StringBuffer buff = new StringBuffer();
+ if (scheme != null) {
+ buff.append(scheme);
+ buff.append(':');
+ }
+ if (authority != null) {
+ buff.append("//");
+ buff.append(authority);
+ }
+ if (path != null) { // accept empty path
+ if ((scheme != null || authority != null) && !path.startsWith("/")) {
+ throw new IOException(/* IOException.PARSING*, */
+ "URI: abs_path requested");
+ }
+ buff.append(path);
+ }
+ if (query != null) {
+ buff.append('?');
+ buff.append(query);
+ }
+ if (fragment != null) {
+ buff.append('#');
+ buff.append(fragment);
+ }
+ parseUriReference(buff.toString(), false);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port) throws IOException {
+
+ this(scheme, userinfo, host, port, null, null, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path) throws IOException {
+
+ this(scheme, userinfo, host, port, path, null, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @param query the query string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path, String query) throws IOException {
+
+ this(scheme, userinfo, host, port, path, query, null);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param userinfo the userinfo string
+ * @param host the host string
+ * @param port the port number
+ * @param path the path string
+ * @param query the query string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String userinfo, String host, int port, String path, String query, String fragment)
+ throws IOException {
+
+ this(scheme,
+ (host == null) ? null
+ : ((userinfo != null) ? userinfo + '@' : "") + host + ((port != -1) ? ":" + port : ""),
+ path, query, fragment);
+ }
+
+ /**
+ * Construct a general URI from the given components.
+ *
+ * @param scheme the scheme string
+ * @param host the host string
+ * @param path the path string
+ * @param fragment the fragment string
+ * @exception IOException
+ */
+ public URI(String scheme, String host, String path, String fragment) throws IOException {
+
+ this(scheme, host, path, null, fragment);
+ }
+
+ /**
+ * Construct a general URI with the given relative URI string.
+ *
+ * @param base the base URI
+ * @param relative the relative URI string
+ * @exception IOException
+ */
+ public URI(URI base, String relative) throws IOException {
+ this(base, new URI(relative));
+ }
+
+ /**
+ * Construct a general URI with the given relative URI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * Resolving Relative References to Absolute Form.
+ *
+ * <strong>Examples of Resolving Relative URI References</strong>
+ *
+ * Within an object with a well-defined base URI of
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * http://a/b/c/d;p?q
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * the relative URI would be resolved as follows:
+ *
+ * Normal Examples
+ *
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * g:h = g:h
+ * g = http://a/b/c/g
+ * ./g = http://a/b/c/g
+ * g/ = http://a/b/c/g/
+ * /g = http://a/g
+ * //g = http://g
+ * ?y = http://a/b/c/?y
+ * g?y = http://a/b/c/g?y
+ * #s = (current document)#s
+ * g#s = http://a/b/c/g#s
+ * g?y#s = http://a/b/c/g?y#s
+ * ;x = http://a/b/c/;x
+ * g;x = http://a/b/c/g;x
+ * g;x?y#s = http://a/b/c/g;x?y#s
+ * . = http://a/b/c/
+ * ./ = http://a/b/c/
+ * .. = http://a/b/
+ * ../ = http://a/b/
+ * ../g = http://a/b/g
+ * ../.. = http://a/
+ * ../../ = http://a/
+ * ../../g = http://a/g
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * Some URI schemes do not allow a hierarchical syntax matching the <hier_part>
+ * syntax, and thus cannot use relative references.
+ *
+ * @param base the base URI
+ * @param relative the relative URI
+ * @exception IOException
+ */
+ public URI(URI base, URI relative) throws IOException {
+
+ if (base._scheme == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: base URI required");
+ }
+ if (base._scheme != null) {
+ this._scheme = base._scheme;
+ this._authority = base._authority;
+ }
+ if (base._is_opaque_part || relative._is_opaque_part) {
+ this._scheme = base._scheme;
+ this._is_opaque_part = relative._is_opaque_part;
+ this._opaque = relative._opaque;
+ this._fragment = relative._fragment;
+ this.setUriReference();
+ return;
+ }
+ if (relative._scheme != null) {
+ this._scheme = relative._scheme;
+ this._is_net_path = relative._is_net_path;
+ this._authority = relative._authority;
+ if (relative._is_server) {
+ this._userinfo = relative._userinfo;
+ this._host = relative._host;
+ this._port = relative._port;
+ } else if (relative._is_reg_name) {
+ this._is_reg_name = relative._is_reg_name;
+ }
+ this._is_abs_path = relative._is_abs_path;
+ this._is_rel_path = relative._is_rel_path;
+ this._path = relative._path;
+ } else if (base._authority != null && relative._scheme == null) {
+ this._is_net_path = base._is_net_path;
+ this._authority = base._authority;
+ if (base._is_server) {
+ this._userinfo = base._userinfo;
+ this._host = base._host;
+ this._port = base._port;
+ } else if (base._is_reg_name) {
+ this._is_reg_name = base._is_reg_name;
+ }
+ }
+ if (relative._authority != null) {
+ this._is_net_path = relative._is_net_path;
+ this._authority = relative._authority;
+ if (relative._is_server) {
+ this._is_server = relative._is_server;
+ this._userinfo = relative._userinfo;
+ this._host = relative._host;
+ this._port = relative._port;
+ } else if (relative._is_reg_name) {
+ this._is_reg_name = relative._is_reg_name;
+ }
+ this._is_abs_path = relative._is_abs_path;
+ this._is_rel_path = relative._is_rel_path;
+ this._path = relative._path;
+ }
+ // resolve the path
+ if (relative._scheme == null && relative._authority == null || equals(base._scheme, relative._scheme)) {
+ this._path = resolvePath(base._path, relative._path);
+ }
+ // base._query removed
+ if (relative._query != null) {
+ this._query = relative._query;
+ }
+ // base._fragment removed
+ if (relative._fragment != null) {
+ this._fragment = relative._fragment;
+ }
+ this.setUriReference();
+ }
+
+ // --------------------------------------------------- Instance Variables
+
+ static final long serialVersionUID = 604752400577948726L;
+
+ /**
+ * This Uniform Resource Identifier (URI). The URI is always in an "escaped"
+ * form, since escaping or unescaping a completed URI might change its
+ * semantics.
+ */
+ protected char[] _uri = null;
+
+ /**
+ * The default charset of the protocol. RFC 2277, 2396
+ */
+ protected static String _protocolCharset = "UTF-8";
+
+ /**
+ * The default charset of the document. RFC 2277, 2396 The platform's charset is
+ * used for the document by default.
+ */
+ protected static String _documentCharset = null;
+ // Static initializer for _documentCharset
+ static {
+ Locale locale = Locale.getDefault();
+ if (locale != null) {
+ // in order to support backward compatiblity
+ _documentCharset = LocaleToCharsetMap.getCharset(locale);
+ } else {
+ _documentCharset = (String) AccessController.doPrivileged(new GetPropertyAction("file.encoding"));
+ }
+ }
+
+ /**
+ * The scheme.
+ */
+ protected char[] _scheme = null;
+
+ /**
+ * The opaque.
+ */
+ protected char[] _opaque = null;
+
+ /**
+ * The authority.
+ */
+ protected char[] _authority = null;
+
+ /**
+ * The userinfo.
+ */
+ protected char[] _userinfo = null;
+
+ /**
+ * The host.
+ */
+ protected char[] _host = null;
+
+ /**
+ * The port.
+ */
+ protected int _port = -1;
+
+ /**
+ * The path.
+ */
+ protected char[] _path = null;
+
+ /**
+ * The query.
+ */
+ protected char[] _query = null;
+
+ /**
+ * The fragment.
+ */
+ protected char[] _fragment = null;
+
+ /**
+ * The root path.
+ */
+ protected static char[] rootPath = { '/' };
+
+ // ---------------------- Generous characters for each component validation
+
+ /**
+ * The percent "%" character always has the reserved purpose of being the escape
+ * indicator, it must be escaped as "%25" in order to be used as data within a
+ * URI.
+ */
+ protected static final BitSet percent = new BitSet(256);
+ // Static initializer for percent
+ static {
+ percent.set('%');
+ }
+
+ /**
+ * BitSet for digit.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet digit = new BitSet(256);
+ // Static initializer for digit
+ static {
+ for (int i = '0'; i <= '9'; i++) {
+ digit.set(i);
+ }
+ }
+
+ /**
+ * BitSet for alpha.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * alpha = lowalpha | upalpha
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet alpha = new BitSet(256);
+ // Static initializer for alpha
+ static {
+ for (int i = 'a'; i <= 'z'; i++) {
+ alpha.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ alpha.set(i);
+ }
+ }
+
+ /**
+ * BitSet for alphanum (join of alpha &amp; digit).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * alphanum = alpha | digit
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet alphanum = new BitSet(256);
+ // Static initializer for alphanum
+ static {
+ alphanum.or(alpha);
+ alphanum.or(digit);
+ }
+
+ /**
+ * BitSet for hex.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hex = new BitSet(256);
+ // Static initializer for hex
+ static {
+ hex.or(digit);
+ for (int i = 'a'; i <= 'f'; i++) {
+ hex.set(i);
+ }
+ for (int i = 'A'; i <= 'F'; i++) {
+ hex.set(i);
+ }
+ }
+
+ /**
+ * BitSet for escaped.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * escaped = "%" hex hex
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet escaped = new BitSet(256);
+ // Static initializer for escaped
+ static {
+ escaped.or(percent);
+ escaped.or(hex);
+ }
+
+ /**
+ * BitSet for mark.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet mark = new BitSet(256);
+ // Static initializer for mark
+ static {
+ mark.set('-');
+ mark.set('_');
+ mark.set('.');
+ mark.set('!');
+ mark.set('~');
+ mark.set('*');
+ mark.set('\'');
+ mark.set('(');
+ mark.set(')');
+ }
+
+ /**
+ * Data characters that are allowed in a URI but do not have a reserved purpose
+ * are called unreserved.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * unreserved = alphanum | mark
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet unreserved = new BitSet(256);
+ // Static initializer for unreserved
+ static {
+ unreserved.or(alphanum);
+ unreserved.or(mark);
+ }
+
+ /**
+ * BitSet for reserved.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * reserved = ";" | "/" | "?" | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet reserved = new BitSet(256);
+ // Static initializer for reserved
+ static {
+ reserved.set(';');
+ reserved.set('/');
+ reserved.set('?');
+ reserved.set(':');
+ reserved.set('@');
+ reserved.set('&');
+ reserved.set('=');
+ reserved.set('+');
+ reserved.set('$');
+ reserved.set(',');
+ }
+
+ /**
+ * BitSet for uric.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * uric = reserved | unreserved | escaped
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet uric = new BitSet(256);
+ // Static initializer for uric
+ static {
+ uric.or(reserved);
+ uric.or(unreserved);
+ uric.or(escaped);
+ }
+
+ /**
+ * BitSet for fragment (alias for uric).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * fragment = *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet fragment = uric;
+
+ /**
+ * BitSet for query (alias for uric).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * query = *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet query = uric;
+
+ /**
+ * BitSet for pchar.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * pchar = unreserved | escaped | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet pchar = new BitSet(256);
+ // Static initializer for pchar
+ static {
+ pchar.or(unreserved);
+ pchar.or(escaped);
+ pchar.set(':');
+ pchar.set('@');
+ pchar.set('&');
+ pchar.set('=');
+ pchar.set('+');
+ pchar.set('$');
+ pchar.set(',');
+ }
+
+ /**
+ * BitSet for param (alias for pchar).
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * param = *pchar
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet param = pchar;
+
+ /**
+ * BitSet for segment.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * segment = *pchar *( ";" param )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet segment = new BitSet(256);
+ // Static initializer for segment
+ static {
+ segment.or(pchar);
+ segment.set(';');
+ segment.or(param);
+ }
+
+ /**
+ * BitSet for path segments.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path_segments = segment *( "/" segment )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet path_segments = new BitSet(256);
+ // Static initializer for path_segments
+ static {
+ path_segments.set('/');
+ path_segments.or(segment);
+ }
+
+ /**
+ * URI absolute path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * abs_path = "/" path_segments
+ * </pre>
+ *
+ * <blockquote>
+ * <p>
+ */
+ protected static final BitSet abs_path = new BitSet(256);
+ // Static initializer for abs_path
+ static {
+ abs_path.set('/');
+ abs_path.or(path_segments);
+ }
+
+ /**
+ * URI bitset for encoding typical non-slash characters.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | "&amp;" | "=" | "+" | "$" | ","
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet uric_no_slash = new BitSet(256);
+ // Static initializer for uric_no_slash
+ static {
+ uric_no_slash.or(unreserved);
+ uric_no_slash.or(escaped);
+ uric_no_slash.set(';');
+ uric_no_slash.set('?');
+ uric_no_slash.set(';');
+ uric_no_slash.set('@');
+ uric_no_slash.set('&');
+ uric_no_slash.set('=');
+ uric_no_slash.set('+');
+ uric_no_slash.set('$');
+ uric_no_slash.set(',');
+ }
+
+ /**
+ * URI bitset that combines uric_no_slash and uric.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * opaque_part = uric_no_slash * uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet opaque_part = new BitSet(256);
+ // Static initializer for opaque_part
+ static {
+ opaque_part.or(uric_no_slash);
+ opaque_part.or(uric);
+ }
+
+ /**
+ * URI bitset that combines absolute path and opaque part.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet path = new BitSet(256);
+ // Static initializer for path
+ static {
+ path.or(abs_path);
+ path.or(opaque_part);
+ }
+
+ /**
+ * Port, a logical alias for digit.
+ */
+ protected static final BitSet port = digit;
+
+ /**
+ * Bitset that combines digit and dot fo IPv$address.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv4address = new BitSet(256);
+ // Static initializer for IPv4address
+ static {
+ IPv4address.or(digit);
+ IPv4address.set('.');
+ }
+
+ /**
+ * RFC 2373.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv6address = hexpart [ ":" IPv4address ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv6address = new BitSet(256);
+ // Static initializer for IPv6address reference
+ static {
+ IPv6address.or(hex); // hexpart
+ IPv6address.set(':');
+ IPv6address.or(IPv4address);
+ }
+
+ /**
+ * RFC 2732, 2373.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * IPv6reference = "[" IPv6address "]"
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet IPv6reference = new BitSet(256);
+ // Static initializer for IPv6reference
+ static {
+ IPv6reference.set('[');
+ IPv6reference.or(IPv6address);
+ IPv6reference.set(']');
+ }
+
+ /**
+ * BitSet for toplabel.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet toplabel = new BitSet(256);
+ // Static initializer for toplabel
+ static {
+ toplabel.or(alphanum);
+ toplabel.set('-');
+ }
+
+ /**
+ * BitSet for domainlabel.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet domainlabel = toplabel;
+
+ /**
+ * BitSet for hostname.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hostname = new BitSet(256);
+ // Static initializer for hostname
+ static {
+ hostname.or(toplabel);
+ // hostname.or(domainlabel);
+ hostname.set('.');
+ }
+
+ /**
+ * BitSet for host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet host = new BitSet(256);
+ // Static initializer for host
+ static {
+ host.or(hostname);
+ // host.or(IPv4address);
+ host.or(IPv6reference); // IPv4address
+ }
+
+ /**
+ * BitSet for hostport.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hostport = host [ ":" port ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hostport = new BitSet(256);
+ // Static initializer for hostport
+ static {
+ hostport.or(host);
+ hostport.set(':');
+ hostport.or(port);
+ }
+
+ /**
+ * Bitset for userinfo.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * userinfo = *( unreserved | escaped |
+ * ";" | ":" | "&amp;" | "=" | "+" | "$" | "," )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet userinfo = new BitSet(256);
+ // Static initializer for userinfo
+ static {
+ userinfo.or(unreserved);
+ userinfo.or(escaped);
+ userinfo.set(';');
+ userinfo.set(':');
+ userinfo.set('&');
+ userinfo.set('=');
+ userinfo.set('+');
+ userinfo.set('$');
+ userinfo.set(',');
+ }
+
+ /**
+ * BitSet for within the userinfo component like user and password.
+ */
+ public static final BitSet within_userinfo = new BitSet(256);
+ // Static initializer for within_userinfo
+ static {
+ within_userinfo.or(userinfo);
+ within_userinfo.clear(';'); // reserved within authority
+ within_userinfo.clear(':');
+ within_userinfo.clear('@');
+ within_userinfo.clear('?');
+ within_userinfo.clear('/');
+ }
+
+ /**
+ * Bitset for server.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * server = [ [ userinfo "@" ] hostport ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet server = new BitSet(256);
+ // Static initializer for server
+ static {
+ server.or(userinfo);
+ server.set('@');
+ server.or(hostport);
+ }
+
+ /**
+ * BitSet for reg_name.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * reg_name = 1 * (unreserved | escaped | "$" | "," | ";" | ":" | "@" | "&amp;" | "=" | "+")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet reg_name = new BitSet(256);
+ // Static initializer for reg_name
+ static {
+ reg_name.or(unreserved);
+ reg_name.or(escaped);
+ reg_name.set('$');
+ reg_name.set(',');
+ reg_name.set(';');
+ reg_name.set(':');
+ reg_name.set('@');
+ reg_name.set('&');
+ reg_name.set('=');
+ reg_name.set('+');
+ }
+
+ /**
+ * BitSet for authority.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = server | reg_name
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet authority = new BitSet(256);
+ // Static initializer for authority
+ static {
+ authority.or(server);
+ authority.or(reg_name);
+ }
+
+ /**
+ * BitSet for scheme.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * scheme = alpha * (alpha | digit | "+" | "-" | ".")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet scheme = new BitSet(256);
+ // Static initializer for scheme
+ static {
+ scheme.or(alpha);
+ scheme.or(digit);
+ scheme.set('+');
+ scheme.set('-');
+ scheme.set('.');
+ }
+
+ /**
+ * BitSet for rel_segment.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * rel_segment = 1 * (unreserved | escaped | ";" | "@" | "&amp;" | "=" | "+" | "$" | ",")
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet rel_segment = new BitSet(256);
+ // Static initializer for rel_segment
+ static {
+ rel_segment.or(unreserved);
+ rel_segment.or(escaped);
+ rel_segment.set(';');
+ rel_segment.set('@');
+ rel_segment.set('&');
+ rel_segment.set('=');
+ rel_segment.set('+');
+ rel_segment.set('$');
+ rel_segment.set(',');
+ }
+
+ /**
+ * BitSet for rel_path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * rel_path = rel_segment[abs_path]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet rel_path = new BitSet(256);
+ // Static initializer for rel_path
+ static {
+ rel_path.or(rel_segment);
+ rel_path.or(abs_path);
+ }
+
+ /**
+ * BitSet for net_path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * net_path = "//" authority [ abs_path ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet net_path = new BitSet(256);
+ // Static initializer for net_path
+ static {
+ net_path.set('/');
+ net_path.or(authority);
+ net_path.or(abs_path);
+ }
+
+ /**
+ * BitSet for hier_part.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * hier_part = ( net_path | abs_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet hier_part = new BitSet(256);
+ // Static initializer for hier_part
+ static {
+ hier_part.or(net_path);
+ hier_part.or(abs_path);
+ // hier_part.set('?'); aleady included
+ hier_part.or(query);
+ }
+
+ /**
+ * BitSet for relativeURI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet relativeURI = new BitSet(256);
+ // Static initializer for relativeURI
+ static {
+ relativeURI.or(net_path);
+ relativeURI.or(abs_path);
+ relativeURI.or(rel_path);
+ // relativeURI.set('?'); aleady included
+ relativeURI.or(query);
+ }
+
+ /**
+ * BitSet for absoluteURI.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * absoluteURI = scheme ":" ( hier_part | opaque_part )
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet absoluteURI = new BitSet(256);
+ // Static initializer for absoluteURI
+ static {
+ absoluteURI.or(scheme);
+ absoluteURI.set(':');
+ absoluteURI.or(hier_part);
+ absoluteURI.or(opaque_part);
+ }
+
+ /**
+ * BitSet for URI-reference.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ protected static final BitSet URI_reference = new BitSet(256);
+ // Static initializer for URI_reference
+ static {
+ URI_reference.or(absoluteURI);
+ URI_reference.or(relativeURI);
+ URI_reference.set('#');
+ URI_reference.or(fragment);
+ }
+
+ // ---------------------------- Characters disallowed within the URI syntax
+ // Excluded US-ASCII Characters are like control, space, delims and unwise
+
+ /**
+ * BitSet for control.
+ */
+ public static final BitSet control = new BitSet(256);
+ // Static initializer for control
+ static {
+ for (int i = 0; i <= 0x1F; i++) {
+ control.set(i);
+ }
+ control.set(0x7F);
+ }
+
+ /**
+ * BitSet for space.
+ */
+ public static final BitSet space = new BitSet(256);
+ // Static initializer for space
+ static {
+ space.set(0x20);
+ }
+
+ /**
+ * BitSet for delims.
+ */
+ public static final BitSet delims = new BitSet(256);
+ // Static initializer for delims
+ static {
+ delims.set('<');
+ delims.set('>');
+ delims.set('#');
+ delims.set('%');
+ delims.set('"');
+ }
+
+ /**
+ * BitSet for unwise.
+ */
+ public static final BitSet unwise = new BitSet(256);
+ // Static initializer for unwise
+ static {
+ unwise.set('{');
+ unwise.set('}');
+ unwise.set('|');
+ unwise.set('\\');
+ unwise.set('^');
+ unwise.set('[');
+ unwise.set(']');
+ unwise.set('`');
+ }
+
+ /**
+ * Disallowed rel_path before escaping.
+ */
+ public static final BitSet disallowed_rel_path = new BitSet(256);
+ // Static initializer for disallowed_rel_path
+ static {
+ disallowed_rel_path.or(uric);
+ disallowed_rel_path.andNot(rel_path);
+ }
+
+ /**
+ * Disallowed opaque_part before escaping.
+ */
+ public static final BitSet disallowed_opaque_part = new BitSet(256);
+ // Static initializer for disallowed_opaque_part
+ static {
+ disallowed_opaque_part.or(uric);
+ disallowed_opaque_part.andNot(opaque_part);
+ }
+
+ // ----------------------- Characters allowed within and for each component
+
+ /**
+ * Those characters that are allowed for the authority component.
+ */
+ public static final BitSet allowed_authority = new BitSet(256);
+ // Static initializer for allowed_authority
+ static {
+ allowed_authority.or(authority);
+ allowed_authority.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the opaque_part.
+ */
+ public static final BitSet allowed_opaque_part = new BitSet(256);
+ // Static initializer for allowed_opaque_part
+ static {
+ allowed_opaque_part.or(opaque_part);
+ allowed_opaque_part.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the reg_name.
+ */
+ public static final BitSet allowed_reg_name = new BitSet(256);
+ // Static initializer for allowed_reg_name
+ static {
+ allowed_reg_name.or(reg_name);
+ // allowed_reg_name.andNot(percent);
+ allowed_reg_name.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the userinfo component.
+ */
+ public static final BitSet allowed_userinfo = new BitSet(256);
+ // Static initializer for allowed_userinfo
+ static {
+ allowed_userinfo.or(userinfo);
+ // allowed_userinfo.andNot(percent);
+ allowed_userinfo.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for within the userinfo component.
+ */
+ public static final BitSet allowed_within_userinfo = new BitSet(256);
+ // Static initializer for allowed_within_userinfo
+ static {
+ allowed_within_userinfo.or(within_userinfo);
+ allowed_within_userinfo.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed for the IPv6reference component. The
+ * characters '[', ']' in IPv6reference should be excluded.
+ */
+ public static final BitSet allowed_IPv6reference = new BitSet(256);
+ // Static initializer for allowed_IPv6reference
+ static {
+ allowed_IPv6reference.or(IPv6reference);
+ // allowed_IPv6reference.andNot(unwise);
+ allowed_IPv6reference.clear('[');
+ allowed_IPv6reference.clear(']');
+ }
+
+ /**
+ * Those characters that are allowed for the host component. The characters '[',
+ * ']' in IPv6reference should be excluded.
+ */
+ public static final BitSet allowed_host = new BitSet(256);
+ // Static initializer for allowed_host
+ static {
+ allowed_host.or(hostname);
+ allowed_host.or(allowed_IPv6reference);
+ }
+
+ /**
+ * Those characters that are allowed for the authority component.
+ */
+ public static final BitSet allowed_within_authority = new BitSet(256);
+ // Static initializer for allowed_within_authority
+ static {
+ allowed_within_authority.or(server);
+ allowed_within_authority.or(reg_name);
+ allowed_within_authority.clear(';');
+ allowed_within_authority.clear(':');
+ allowed_within_authority.clear('@');
+ allowed_within_authority.clear('?');
+ allowed_within_authority.clear('/');
+ }
+
+ /**
+ * Those characters that are allowed for the abs_path.
+ */
+ public static final BitSet allowed_abs_path = new BitSet(256);
+ // Static initializer for allowed_abs_path
+ static {
+ allowed_abs_path.or(abs_path);
+ // allowed_abs_path.set('/'); // aleady included
+ allowed_abs_path.andNot(percent);
+ }
+
+ /**
+ * Those characters that are allowed for the rel_path.
+ */
+ public static final BitSet allowed_rel_path = new BitSet(256);
+ // Static initializer for allowed_rel_path
+ static {
+ allowed_rel_path.or(rel_path);
+ allowed_rel_path.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed within the path.
+ */
+ public static final BitSet allowed_within_path = new BitSet(256);
+ // Static initializer for allowed_within_path
+ static {
+ allowed_within_path.or(abs_path);
+ allowed_within_path.clear('/');
+ allowed_within_path.clear(';');
+ allowed_within_path.clear('=');
+ allowed_within_path.clear('?');
+ }
+
+ /**
+ * Those characters that are allowed for the query component.
+ */
+ public static final BitSet allowed_query = new BitSet(256);
+ // Static initializer for allowed_query
+ static {
+ allowed_query.or(uric);
+ allowed_query.clear('%');
+ }
+
+ /**
+ * Those characters that are allowed within the query component.
+ */
+ public static final BitSet allowed_within_query = new BitSet(256);
+ // Static initializer for allowed_within_query
+ static {
+ allowed_within_query.or(allowed_query);
+ allowed_within_query.andNot(reserved); // excluded 'reserved'
+ allowed_within_query.clear('#'); // avoid confict with the fragment
+ }
+
+ /**
+ * Those characters that are allowed for the fragment component.
+ */
+ public static final BitSet allowed_fragment = new BitSet(256);
+ // Static initializer for allowed_fragment
+ static {
+ allowed_fragment.or(uric);
+ allowed_fragment.clear('%');
+ }
+
+ // ------------------------------------------- Flags for this URI-reference
+
+ // URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ // absoluteURI = scheme ":" ( hier_part | opaque_part )
+ protected boolean _is_hier_part;
+ protected boolean _is_opaque_part;
+ // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ // hier_part = ( net_path | abs_path ) [ "?" query ]
+ protected boolean _is_net_path;
+ protected boolean _is_abs_path;
+ protected boolean _is_rel_path;
+ // net_path = "//" authority [ abs_path ]
+ // authority = server | reg_name
+ protected boolean _is_reg_name;
+ protected boolean _is_server; // = _has_server
+ // server = [ [ userinfo "@" ] hostport ]
+ // host = hostname | IPv4address | IPv6reference
+ protected boolean _is_hostname;
+ protected boolean _is_IPv4address;
+ protected boolean _is_IPv6reference;
+
+ // ------------------------------------------ Character and escape encoding
+
+ /**
+ * Encode with the default protocol charset.
+ *
+ * @param original the original character sequence
+ * @param allowed those characters that are allowed within a component
+ * @return URI character sequence
+ * @exception IOException null component or unsupported character encoding
+ */
+ protected static char[] encode(String original, BitSet allowed) throws IOException {
+
+ return encode(original, allowed, _protocolCharset);
+ }
+
+ /**
+ * Encodes URI string.
+ *
+ * This is a two mapping, one from original characters to octets, and
+ * subsequently a second from octets to URI characters:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * original character sequence->octet sequence->URI character sequence
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * An escaped octet is encoded as a character triplet, consisting of the percent
+ * character "%" followed by the two hexadecimal digits representing the octet
+ * code. For example, "%20" is the escaped encoding for the US-ASCII space
+ * character.
+ * <p>
+ * Conversion from the local filesystem character set to UTF-8 will normally
+ * involve a two step process. First convert the local character set to the UCS;
+ * then convert the UCS to UTF-8. The first step in the process can be performed
+ * by maintaining a mapping table that includes the local character set code and
+ * the corresponding UCS code. The next step is to convert the UCS character
+ * code to the UTF-8 encoding.
+ * <p>
+ * Mapping between vendor codepages can be done in a very similar manner as
+ * described above.
+ * <p>
+ * The only time escape encodings can allowedly be made is when a URI is being
+ * created from its component parts. The escape and validate methods are
+ * internally performed within this method.
+ *
+ * @param original the original character sequence
+ * @param allowed those characters that are allowed within a component
+ * @param charset the protocol charset
+ * @return URI character sequence
+ * @exception IOException null component or unsupported character encoding
+ */
+ protected static char[] encode(String original, BitSet allowed, String charset) throws IOException {
+
+ // encode original to uri characters.
+ if (original == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: null");
+ }
+ // escape octet to uri characters.
+ if (allowed == null) {
+ throw new IOException(/* IOException.PARSING, */
+ "URI: null allowed characters");
+ }
+ byte[] octets;
+ try {
+ octets = original.getBytes(charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */ "Unsupported Encoding: " + charset);
+ }
+ StringBuffer buf = new StringBuffer(octets.length);
+ for (int i = 0; i < octets.length; i++) {
+ char c = (char) octets[i];
+ if (allowed.get(c)) {
+ buf.append(c);
+ } else {
+ buf.append('%');
+ byte b = octets[i]; // use the original byte value
+ char hexadecimal = Character.forDigit((b >> 4) & 0xF, 16);
+ buf.append(Character.toUpperCase(hexadecimal)); // high
+ hexadecimal = Character.forDigit(b & 0xF, 16);
+ buf.append(Character.toUpperCase(hexadecimal)); // low
+ }
+ }
+
+ return buf.toString().toCharArray();
+ }
+
+ /**
+ * Decode with the default protocol charset.
+ *
+ * @param component the URI character sequence
+ * @return original character sequence
+ * @exception IOException incomplete trailing escape pattern or unsupported
+ * character encoding
+ */
+ protected static String decode(char[] component) throws IOException {
+ return decode(component, _protocolCharset);
+ }
+
+ /**
+ * Decodes URI encoded string.
+ *
+ * This is a two mapping, one from URI characters to octets, and subsequently a
+ * second from octets to original characters:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * URI character sequence->octet sequence->original character sequence
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * A URI must be separated into its components before the escaped characters
+ * within those components can be allowedly decoded.
+ * <p>
+ * Notice that there is a chance that URI characters that are non UTF-8 may be
+ * parsed as valid UTF-8. A recent non-scientific analysis found that EUC
+ * encoded Japanese words had a 2.7% false reading; SJIS had a 0.0005% false
+ * reading; other encoding such as ASCII or KOI-8 have a 0% false reading.
+ * <p>
+ * The percent "%" character always has the reserved purpose of being the escape
+ * indicator, it must be escaped as "%25" in order to be used as data within a
+ * URI.
+ * <p>
+ * The unescape method is internally performed within this method.
+ *
+ * @param component the URI character sequence
+ * @param charset the protocol charset
+ * @return original character sequence
+ * @exception IOException incomplete trailing escape pattern or unsupported
+ * character encoding
+ */
+ protected static String decode(char[] component, String charset) throws IOException {
+
+ // unescape uri characters to octets
+ if (component == null)
+ return null;
+
+ byte[] octets;
+ try {
+ octets = new String(component).getBytes(charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
+ "URI: not supported " + charset + " encoding");
+ }
+ int length = octets.length;
+ int oi = 0; // output index
+ for (int ii = 0; ii < length; oi++) {
+ byte aByte = (byte) octets[ii++];
+ if (aByte == '%' && ii + 2 <= length) {
+ byte high = (byte) Character.digit((char) octets[ii++], 16);
+ byte low = (byte) Character.digit((char) octets[ii++], 16);
+ if (high == -1 || low == -1) {
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: incomplete trailing escape pattern");
+
+ }
+ aByte = (byte) ((high << 4) + low);
+ }
+ octets[oi] = (byte) aByte;
+ }
+
+ String result;
+ try {
+ result = new String(octets, 0, oi, charset);
+ } catch (UnsupportedEncodingException error) {
+ throw new IOException(/* IOException.UNSUPPORTED_ENCODING, */
+ "URI: not supported " + charset + " encoding");
+ }
+
+ return result;
+ }
+
+ /**
+ * Pre-validate the unescaped URI string within a specific component.
+ *
+ * @param component the component string within the component
+ * @param disallowed those characters disallowed within the component
+ * @return if true, it doesn't have the disallowed characters if false, the
+ * component is undefined or an incorrect one
+ */
+ protected boolean prevalidate(String component, BitSet disallowed) {
+ // prevalidate the given component by disallowed characters
+ if (component == null) {
+ return false; // undefined
+ }
+ char[] target = component.toCharArray();
+ for (int i = 0; i < target.length; i++) {
+ if (disallowed.get(target[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Validate the URI characters within a specific component. The component must
+ * be performed after escape encoding. Or it doesn't include escaped characters.
+ *
+ * @param component the characters sequence within the component
+ * @param generous those characters that are allowed within a component
+ * @return if true, it's the correct URI character sequence
+ */
+ protected boolean validate(char[] component, BitSet generous) {
+ // validate each component by generous characters
+ return validate(component, 0, -1, generous);
+ }
+
+ /**
+ * Validate the URI characters within a specific component. The component must
+ * be performed after escape encoding. Or it doesn't include escaped characters.
+ * <p>
+ * It's not that much strict, generous. The strict validation might be performed
+ * before being called this method.
+ *
+ * @param component the characters sequence within the component
+ * @param soffset the starting offset of the given component
+ * @param eoffset the ending offset of the given component if -1, it means the
+ * length of the component
+ * @param generous those characters that are allowed within a component
+ * @return if true, it's the correct URI character sequence
+ * @throws NullPointerException null component
+ */
+ protected boolean validate(char[] component, int soffset, int eoffset, BitSet generous) {
+ // validate each component by generous characters
+ if (eoffset == -1) {
+ eoffset = component.length - 1;
+ }
+ for (int i = soffset; i <= eoffset; i++) {
+ if (!generous.get(component[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * In order to avoid any possilbity of conflict with non-ASCII characters, Parse
+ * a URI reference as a <code>String</code> with the character encoding of the
+ * local system or the document.
+ * <p>
+ * The following line is the regular expression for breaking-down a URI
+ * reference into its components.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * 12 3 4 5 6 7 8 9
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * For example, matching the above expression to
+ * http://jakarta.apache.org/ietf/uri/#Related results in the following
+ * subexpression matches:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * $1 = http:
+ * scheme = $2 = http
+ * $3 = //jakarta.apache.org
+ * authority = $4 = jakarta.apache.org
+ * path = $5 = /ietf/uri/
+ * $6 = <undefined>
+ * query = $7 = <undefined>
+ * $8 = #Related
+ * fragment = $9 = Related
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @param original the original character sequence
+ * @param escaped <code>true</code> if <code>original</code> is escaped
+ * @return the original character sequence
+ * @exception IOException
+ */
+ protected void parseUriReference(String original, boolean escaped) throws IOException {
+
+ // validate and contruct the URI character sequence
+ if (original == null || original.length() == 0) {
+ throw new IOException("URI-Reference required");
+ }
+
+ /**
+ * @ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ */
+ String tmp = original.trim();
+
+ /**
+ * The length of the string sequence of characters. It may not be equal to the
+ * length of the byte array.
+ */
+ int length = tmp.length();
+
+ /**
+ * Remove the delimiters like angle brackets around an URI.
+ */
+ char[] firstDelimiter = { tmp.charAt(0) };
+ if (validate(firstDelimiter, delims)) {
+ if (length >= 2) {
+ char[] lastDelimiter = { tmp.charAt(length - 1) };
+ if (validate(lastDelimiter, delims)) {
+ tmp = tmp.substring(1, length - 1);
+ length = length - 2;
+ }
+ }
+ }
+
+ /**
+ * The starting index
+ */
+ int from = 0;
+
+ /**
+ * The test flag whether the URI is started from the path component.
+ */
+ boolean isStartedFromPath = false;
+ int atColon = tmp.indexOf(':');
+ int atSlash = tmp.indexOf('/');
+ if (atColon < 0 || (atSlash >= 0 && atSlash < atColon)) {
+ isStartedFromPath = true;
+ }
+
+ /**
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * &#64;@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ int at = indexFirstOf(tmp, isStartedFromPath ? "/?#" : ":/?#", from);
+ if (at == -1)
+ at = 0;
+
+ /**
+ * Parse the scheme.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * scheme = $2 = http
+ * &#64;
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (at < length && tmp.charAt(at) == ':') {
+ char[] target = tmp.substring(0, at).toLowerCase().toCharArray();
+ if (validate(target, scheme)) {
+ _scheme = target;
+ } else {
+ throw new IOException("incorrect scheme");
+ }
+ from = ++at;
+ }
+
+ /**
+ * Parse the authority component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = $4 = jakarta.apache.org
+ * &#64;@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ // Reset flags
+ _is_net_path = _is_abs_path = _is_rel_path = _is_hier_part = false;
+ if (0 <= at && at < length && tmp.charAt(at) == '/') {
+ // Set flag
+ _is_hier_part = true;
+ if (at + 2 < length && tmp.charAt(at + 1) == '/') {
+ // the temporary index to start the search from
+ int next = indexFirstOf(tmp, "/?#", at + 2);
+ if (next == -1) {
+ next = (tmp.substring(at + 2).length() == 0) ? at + 2 : tmp.length();
+ }
+ parseAuthority(tmp.substring(at + 2, next), escaped);
+ from = at = next;
+ // Set flag
+ _is_net_path = true;
+ }
+ if (from == at) {
+ // Set flag
+ _is_abs_path = true;
+ }
+ }
+
+ /**
+ * Parse the path component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = $5 = /ietf/uri/
+ * &#64;@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (from < length) {
+ // rel_path = rel_segment [ abs_path ]
+ int next = indexFirstOf(tmp, "?#", from);
+ if (next == -1) {
+ next = tmp.length();
+ }
+ if (!_is_abs_path) {
+ if (!escaped && prevalidate(tmp.substring(from, next), disallowed_rel_path)
+ || escaped && validate(tmp.substring(from, next).toCharArray(), rel_path)) {
+ // Set flag
+ _is_rel_path = true;
+ } else if (!escaped && prevalidate(tmp.substring(from, next), disallowed_opaque_part)
+ || escaped && validate(tmp.substring(from, next).toCharArray(), opaque_part)) {
+ // Set flag
+ _is_opaque_part = true;
+ } else {
+ // the path component may be empty
+ _path = null;
+ }
+ }
+ setPath(tmp.substring(from, next));
+ at = next;
+ }
+
+ /**
+ * Parse the query component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * query = $7 = <undefined>
+ * &#64;@@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (0 <= at && at + 1 < length && tmp.charAt(at) == '?') {
+ int next = tmp.indexOf('#', at + 1);
+ if (next == -1) {
+ next = tmp.length();
+ }
+ _query = (escaped) ? tmp.substring(at + 1, next).toCharArray()
+ : encode(tmp.substring(at + 1, next), allowed_query);
+ at = next;
+ }
+
+ /**
+ * Parse the fragment component.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * fragment = $9 = Related
+ * &#64;@@@@@@@
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ */
+ if (0 <= at && at + 1 < length && tmp.charAt(at) == '#') {
+ _fragment = (escaped) ? tmp.substring(at + 1).toCharArray()
+ : encode(tmp.substring(at + 1), allowed_fragment);
+ }
+
+ // set this URI.
+ setUriReference();
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given string.
+ *
+ * @param s the string to be indexed
+ * @param delims the delimiters used to index
+ * @return the earlier index if there are delimiters
+ */
+ protected int indexFirstOf(String s, String delims) {
+ return indexFirstOf(s, delims, -1);
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given string.
+ *
+ * @param s the string to be indexed
+ * @param delims the delimiters used to index
+ * @param offset the from index
+ * @return the earlier index if there are delimiters
+ */
+ protected int indexFirstOf(String s, String delims, int offset) {
+ if (s == null || s.length() == 0) {
+ return -1;
+ }
+ if (delims == null || delims.length() == 0) {
+ return -1;
+ }
+ // check boundaries
+ if (offset < 0) {
+ offset = 0;
+ } else if (offset > s.length()) {
+ return -1;
+ }
+ // s is never null
+ int min = s.length();
+ char[] delim = delims.toCharArray();
+ for (int i = 0; i < delim.length; i++) {
+ int at = s.indexOf(delim[i], offset);
+ if (at >= 0 && at < min) {
+ min = at;
+ }
+ }
+ return (min == s.length()) ? -1 : min;
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given array.
+ *
+ * @param s the character array to be indexed
+ * @param delim the delimiter used to index
+ * @return the ealier index if there are a delimiter
+ */
+ protected int indexFirstOf(char[] s, char delim) {
+ return indexFirstOf(s, delim, 0);
+ }
+
+ /**
+ * Get the earlier index that to be searched for the first occurrance in one of
+ * any of the given array.
+ *
+ * @param s the character array to be indexed
+ * @param delim the delimiter used to index
+ * @return the ealier index if there is a delimiter
+ */
+ protected int indexFirstOf(char[] s, char delim, int offset) {
+ if (s == null || s.length == 0) {
+ return -1;
+ }
+ // check boundaries
+ if (offset < 0) {
+ offset = 0;
+ } else if (offset > s.length) {
+ return -1;
+ }
+ for (int i = offset; i < s.length; i++) {
+ if (s[i] == delim) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Parse the authority component.
+ *
+ * @param original the original character sequence of authority component
+ * @param escaped <code>true</code> if <code>original</code> is escaped
+ * @exception IOException
+ */
+ protected void parseAuthority(String original, boolean escaped) throws IOException {
+
+ // Reset flags
+ _is_reg_name = _is_server = _is_hostname = _is_IPv4address = _is_IPv6reference = false;
+
+ boolean has_port = true;
+ int from = 0;
+ int next = original.indexOf('@');
+ if (next != -1) { // neither -1 and 0
+ // each protocol extented from URI supports the specific userinfo
+ _userinfo = (escaped) ? original.substring(0, next).toCharArray()
+ : encode(original.substring(0, next), allowed_userinfo);
+ from = next + 1;
+ }
+ next = original.indexOf('[', from);
+ if (next >= from) {
+ next = original.indexOf(']', from);
+ if (next == -1) {
+ throw new IOException(/* IOException.PARSING, */ "URI: IPv6reference");
+ } else {
+ next++;
+ }
+ // In IPv6reference, '[', ']' should be excluded
+ _host = (escaped) ? original.substring(from, next).toCharArray()
+ : encode(original.substring(from, next), allowed_IPv6reference);
+ // Set flag
+ _is_IPv6reference = true;
+ } else { // only for !_is_IPv6reference
+ next = original.indexOf(':', from);
+ if (next == -1) {
+ next = original.length();
+ has_port = false;
+ }
+ // REMINDME: it doesn't need the pre-validation
+ _host = original.substring(from, next).toCharArray();
+ if (validate(_host, IPv4address)) {
+ // Set flag
+ _is_IPv4address = true;
+ } else if (validate(_host, hostname)) {
+ // Set flag
+ _is_hostname = true;
+ } else {
+ // Set flag
+ _is_reg_name = true;
+ }
+ }
+ if (_is_reg_name) {
+ // Reset flags for a server-based naming authority
+ _is_server = _is_hostname = _is_IPv4address = _is_IPv6reference = false;
+ // set a registry-based naming authority
+ _authority = (escaped) ? original.toString().toCharArray() : encode(original.toString(), allowed_reg_name);
+ } else {
+ if (original.length() - 1 > next && has_port && original.charAt(next) == ':') { // not empty
+ from = next + 1;
+ try {
+ _port = Integer.parseInt(original.substring(from));
+ } catch (NumberFormatException error) {
+ throw new IOException(/* IOException.PARSING, */
+ "URI: invalid port number");
+ }
+ }
+ // set a server-based naming authority
+ StringBuffer buf = new StringBuffer();
+ if (_userinfo != null) { // has_userinfo
+ buf.append(_userinfo);
+ buf.append('@');
+ }
+ if (_host != null) {
+ buf.append(_host);
+ if (_port != -1) {
+ buf.append(':');
+ buf.append(_port);
+ }
+ }
+ _authority = buf.toString().toCharArray();
+ // Set flag
+ _is_server = true;
+ }
+ }
+
+ /**
+ * Once it's parsed successfully, set this URI.
+ *
+ * @see #getRawURI
+ */
+ protected void setUriReference() {
+ // set _uri
+ StringBuffer buf = new StringBuffer();
+ // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ if (_scheme != null) {
+ buf.append(_scheme);
+ buf.append(':');
+ }
+ if (_is_net_path) {
+ buf.append("//");
+ if (_authority != null) { // has_authority
+ if (_userinfo != null) { // by default, remove userinfo part
+ if (_host != null) {
+ buf.append(_host);
+ if (_port != -1) {
+ buf.append(':');
+ buf.append(_port);
+ }
+ }
+ } else {
+ buf.append(_authority);
+ }
+ }
+ }
+ if (_opaque != null && _is_opaque_part) {
+ buf.append(_opaque);
+ } else if (_path != null) {
+ // _is_hier_part or _is_relativeURI
+ if (_path.length != 0) {
+ buf.append(_path);
+ }
+ }
+ if (_query != null) { // has_query
+ buf.append('?');
+ buf.append(_query);
+ }
+ if (_fragment != null) { // has_fragment
+ buf.append('#');
+ buf.append(_fragment);
+ }
+
+ _uri = buf.toString().toCharArray();
+ }
+
+ // ----------------------------------------------------------- Test methods
+
+ /**
+ * Tell whether or not this URI is absolute.
+ *
+ * @return true iif this URI is absoluteURI
+ */
+ public boolean isAbsoluteURI() {
+ return (_scheme != null);
+ }
+
+ /**
+ * Tell whether or not this URI is relative.
+ *
+ * @return true iif this URI is relativeURI
+ */
+ public boolean isRelativeURI() {
+ return (_scheme == null);
+ }
+
+ /**
+ * Tell whether or not the absoluteURI of this URI is hier_part.
+ *
+ * @return true iif the absoluteURI is hier_part
+ */
+ public boolean isHierPart() {
+ return _is_hier_part;
+ }
+
+ /**
+ * Tell whether or not the absoluteURI of this URI is opaque_part.
+ *
+ * @return true iif the absoluteURI is opaque_part
+ */
+ public boolean isOpaquePart() {
+ return _is_opaque_part;
+ }
+
+ /**
+ * Tell whether or not the relativeURI or heir_part of this URI is net_path.
+ * It's the same function as the has_authority() method.
+ *
+ * @return true iif the relativeURI or heir_part is net_path
+ * @see #hasAuthority
+ */
+ public boolean isNetPath() {
+ return _is_net_path || (_authority != null);
+ }
+
+ /**
+ * Tell whether or not the relativeURI or hier_part of this URI is abs_path.
+ *
+ * @return true iif the relativeURI or hier_part is abs_path
+ */
+ public boolean isAbsPath() {
+ return _is_abs_path;
+ }
+
+ /**
+ * Tell whether or not the relativeURI of this URI is rel_path.
+ *
+ * @return true iif the relativeURI is rel_path
+ */
+ public boolean isRelPath() {
+ return _is_rel_path;
+ }
+
+ /**
+ * Tell whether or not this URI has authority. It's the same function as the
+ * is_net_path() method.
+ *
+ * @return true iif this URI has authority
+ * @see #isNetPath
+ */
+ public boolean hasAuthority() {
+ return (_authority != null) || _is_net_path;
+ }
+
+ /**
+ * Tell whether or not the authority component of this URI is reg_name.
+ *
+ * @return true iif the authority component is reg_name
+ */
+ public boolean isRegName() {
+ return _is_reg_name;
+ }
+
+ /**
+ * Tell whether or not the authority component of this URI is server.
+ *
+ * @return true iif the authority component is server
+ */
+ public boolean isServer() {
+ return _is_server;
+ }
+
+ /**
+ * Tell whether or not this URI has userinfo.
+ *
+ * @return true iif this URI has userinfo
+ */
+ public boolean hasUserinfo() {
+ return (_userinfo != null);
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is hostname.
+ *
+ * @return true iif the host part is hostname
+ */
+ public boolean isHostname() {
+ return _is_hostname;
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is IPv4address.
+ *
+ * @return true iif the host part is IPv4address
+ */
+ public boolean isIPv4address() {
+ return _is_IPv4address;
+ }
+
+ /**
+ * Tell whether or not the host part of this URI is IPv6reference.
+ *
+ * @return true iif the host part is IPv6reference
+ */
+ public boolean isIPv6reference() {
+ return _is_IPv6reference;
+ }
+
+ /**
+ * Tell whether or not this URI has query.
+ *
+ * @return true iif this URI has query
+ */
+ public boolean hasQuery() {
+ return (_query != null);
+ }
+
+ /**
+ * Tell whether or not this URI has fragment.
+ *
+ * @return true iif this URI has fragment
+ */
+ public boolean hasFragment() {
+ return (_fragment != null);
+ }
+
+ // ---------------------------------------------------------------- Charset
+
+ /**
+ * Set the default charset of the protocol.
+ * <p>
+ * The character set used to store files SHALL remain a local decision and MAY
+ * depend on the capability of local operating systems. Prior to the exchange of
+ * URIs they SHOULD be converted into a ISO/IEC 10646 format and UTF-8 encoded.
+ * This approach, while allowing international exchange of URIs, will still
+ * allow backward compatibility with older systems because the code set
+ * positions for ASCII characters are identical to the one byte sequence in
+ * UTF-8.
+ * <p>
+ * An individual URI scheme may require a single charset, define a default
+ * charset, or provide a way to indicate the charset used.
+ *
+ * @param charset the default charset for each protocol
+ */
+ public static void setProtocolCharset(String charset) {
+ _protocolCharset = charset;
+ }
+
+ /**
+ * Get the default charset of the protocol.
+ * <p>
+ * An individual URI scheme may require a single charset, define a default
+ * charset, or provide a way to indicate the charset used.
+ * <p>
+ * To work globally either requires support of a number of character sets and to
+ * be able to convert between them, or the use of a single preferred character
+ * set. For support of global compatibility it is STRONGLY RECOMMENDED that
+ * clients and servers use UTF-8 encoding when exchanging URIs.
+ *
+ * @return the charset string
+ */
+ public static String getProtocolCharset() {
+ return _protocolCharset;
+ }
+
+ /**
+ * Set the default charset of the document.
+ * <p>
+ * Notice that it will be possible to contain mixed characters (e.g.
+ * ftp://host/KoreanNamespace/ChineseResource). To handle the Bi-directional
+ * display of these character sets, the protocol charset could be simply used
+ * again. Because it's not yet implemented that the insertion of BIDI control
+ * characters at different points during composition is extracted.
+ *
+ * @param charset the default charset for the document
+ */
+ public static void setDocumentCharset(String charset) {
+ _documentCharset = charset;
+ }
+
+ /**
+ * Get the default charset of the document.
+ *
+ * @return the charset string
+ */
+ public static String getDocumentCharset() {
+ return _documentCharset;
+ }
+
+ // ------------------------------------------------------------- The scheme
+
+ /**
+ * Get the scheme.
+ *
+ * @return the scheme
+ */
+ public char[] getRawScheme() {
+ return _scheme;
+ }
+
+ /**
+ * Get the scheme.
+ *
+ * @return the scheme null if undefined scheme
+ */
+ public String getScheme() {
+ return (_scheme == null) ? null : new String(_scheme);
+ }
+
+ // ---------------------------------------------------------- The authority
+
+ /**
+ * Set the authority. It can be one type of server, hostport, hostname,
+ * IPv4address, IPv6reference and reg_name.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * authority = server | reg_name
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @param escapedAuthority the raw escaped authority
+ * @exception IOException
+ * @throws NullPointerException null authority
+ */
+ public void setRawAuthority(char[] escapedAuthority) throws IOException {
+ parseAuthority(new String(escapedAuthority), true);
+ setUriReference();
+ }
+
+ /**
+ * Set the authority. It can be one type of server, hostport, hostname,
+ * IPv4address, IPv6reference and reg_name. Note that there is no setAuthority
+ * method by the escape encoding reason.
+ *
+ * @param escapedAuthority the escaped authority string
+ * @exception IOException
+ */
+ public void setEscapedAuthority(String escapedAuthority) throws IOException {
+
+ parseAuthority(escapedAuthority, true);
+ setUriReference();
+ }
+
+ /**
+ * Get the raw-escaped authority.
+ *
+ * @return the raw-escaped authority
+ */
+ public char[] getRawAuthority() {
+ return _authority;
+ }
+
+ /**
+ * Get the escaped authority.
+ *
+ * @return the escaped authority
+ */
+ public String getEscapedAuthority() {
+ return (_authority == null) ? null : new String(_authority);
+ }
+
+ /**
+ * Get the authority.
+ *
+ * @return the authority
+ * @exception IOException
+ * @see #decode
+ */
+ public String getAuthority() throws IOException {
+ return (_authority == null) ? null : decode(_authority);
+ }
+
+ // ----------------------------------------------------------- The userinfo
+
+ /**
+ * Get the raw-escaped userinfo.
+ *
+ * @return the raw-escaped userinfo
+ * @see #getAuthority
+ */
+ public char[] getRawUserinfo() {
+ return _userinfo;
+ }
+
+ /**
+ * Get the escaped userinfo.
+ *
+ * @return the escaped userinfo
+ * @see #getAuthority
+ */
+ public String getEscapedUserinfo() {
+ return (_userinfo == null) ? null : new String(_userinfo);
+ }
+
+ /**
+ * Get the userinfo.
+ *
+ * @return the userinfo
+ * @exception IOException
+ * @see #decode
+ * @see #getAuthority
+ */
+ public String getUserinfo() throws IOException {
+ return (_userinfo == null) ? null : decode(_userinfo);
+ }
+
+ // --------------------------------------------------------------- The host
+
+ /**
+ * Get the host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the host
+ * @see #getAuthority
+ */
+ public char[] getRawHost() {
+ return _host;
+ }
+
+ /**
+ * Get the host.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * host = hostname | IPv4address | IPv6reference
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the host
+ * @exception IOException
+ * @see #decode
+ * @see #getAuthority
+ */
+ public String getHost() throws IOException {
+ return decode(_host);
+ }
+
+ // --------------------------------------------------------------- The port
+
+ /**
+ * Get the port. In order to get the specfic default port, the specific
+ * protocol-supported class extended from the URI class should be used. It has
+ * the server-based naming authority.
+ *
+ * @return the port if -1, it has the default port for the scheme or the
+ * server-based naming authority is not supported in the specific URI.
+ */
+ public int getPort() {
+ return _port;
+ }
+
+ // --------------------------------------------------------------- The path
+
+ /**
+ * Set the path. The method couldn't be used by API programmers.
+ *
+ * @param path the path string
+ * @exception IOException set incorrectly or fragment only
+ * @see #encode
+ */
+ protected void setPath(String path) throws IOException {
+
+ // set path
+ if (_is_net_path || _is_abs_path) {
+ _path = encode(path, allowed_abs_path);
+ } else if (_is_rel_path) {
+ StringBuffer buff = new StringBuffer(path.length());
+ int at = path.indexOf('/');
+ if (at > 0) { // never 0
+ buff.append(encode(path.substring(0, at), allowed_rel_path));
+ buff.append(encode(path.substring(at), allowed_abs_path));
+ } else {
+ buff.append(encode(path, allowed_rel_path));
+ }
+ _path = buff.toString().toCharArray();
+ } else if (_is_opaque_part) {
+ _opaque = encode(path, allowed_opaque_part);
+ } else {
+ throw new IOException(/* IOException.PARSING, */"URI: incorrect path");
+ }
+ }
+
+ /**
+ * Resolve the base and relative path.
+ *
+ * @param base_path a character array of the base_path
+ * @param rel_path a character array of the rel_path
+ * @return the resolved path
+ */
+ protected char[] resolvePath(char[] base_path, char[] rel_path) {
+
+ // REMINDME: paths are never null
+ String base = (base_path == null) ? "" : new String(base_path);
+ int at = base.lastIndexOf('/');
+ if (at != -1) {
+ base_path = base.substring(0, at + 1).toCharArray();
+ }
+ // _path could be empty
+ if (rel_path == null || rel_path.length == 0) {
+ return normalize(base_path);
+ } else if (rel_path[0] == '/') {
+ return rel_path;
+ } else {
+ StringBuffer buff = new StringBuffer(base.length() + rel_path.length);
+ if (at != -1) {
+ buff.append(base.substring(0, at + 1));
+ buff.append(rel_path);
+ }
+ return normalize(buff.toString().toCharArray());
+ }
+ }
+
+ /**
+ * Get the raw-escaped current hierarchy level in the given path. If the last
+ * namespace is a collection, the slash mark ('/') should be ended with at the
+ * last character of the path string.
+ *
+ * @param path the path
+ * @return the current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ protected char[] getRawCurrentHierPath(char[] path) throws IOException {
+
+ if (_is_opaque_part) {
+ throw new IOException(/* IOException.PARSING, */ "URI: no hierarchy level");
+ }
+ if (path == null) {
+ throw new IOException(/* IOException.PARSING, */ "URI: emtpy path");
+ }
+ String buff = new String(path);
+ int first = buff.indexOf('/');
+ int last = buff.lastIndexOf('/');
+ if (last == 0) {
+ return rootPath;
+ } else if (first != last && last != -1) {
+ return buff.substring(0, last).toCharArray();
+ }
+ // FIXME: it could be a document on the server side
+ return path;
+ }
+
+ /**
+ * Get the raw-escaped current hierarchy level.
+ *
+ * @return the raw-escaped current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ public char[] getRawCurrentHierPath() throws IOException {
+ return (_path == null) ? null : getRawCurrentHierPath(_path);
+ }
+
+ /**
+ * Get the escaped current hierarchy level.
+ *
+ * @return the escaped current hierarchy level
+ * @exception IOException no hierarchy level
+ */
+ public String getEscapedCurrentHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the current hierarchy level.
+ *
+ * @return the current hierarchy level
+ * @exception IOException
+ * @see #decode
+ */
+ public String getCurrentHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the raw above hierarchy level
+ * @exception IOException
+ */
+ public char[] getRawAboveHierPath() throws IOException {
+ char[] path = getRawCurrentHierPath();
+ return (path == null) ? null : getRawCurrentHierPath(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the raw above hierarchy level
+ * @exception IOException
+ */
+ public String getEscapedAboveHierPath() throws IOException {
+ char[] path = getRawAboveHierPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the level above the this hierarchy level.
+ *
+ * @return the above hierarchy level
+ * @exception IOException
+ * @see #decode
+ */
+ public String getAboveHierPath() throws IOException {
+ char[] path = getRawAboveHierPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the raw-escaped path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the raw-escaped path
+ */
+ public char[] getRawPath() {
+ return _is_opaque_part ? _opaque : _path;
+ }
+
+ /**
+ * Get the escaped path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * abs_path = "/" path_segments
+ * opaque_part = uric_no_slash *uric
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the escaped path string
+ */
+ public String getEscapedPath() {
+ char[] path = getRawPath();
+ return (path == null) ? null : new String(path);
+ }
+
+ /**
+ * Get the path.
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * path = [ abs_path | opaque_part ]
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ *
+ * @return the path string
+ * @exception IOException
+ * @see #decode
+ */
+ public String getPath() throws IOException {
+ char[] path = getRawPath();
+ return (path == null) ? null : decode(path);
+ }
+
+ /**
+ * Get the raw-escaped basename of the path.
+ *
+ * @return the raw-escaped basename
+ */
+ public char[] getRawName() {
+ if (_path == null)
+ return null;
+
+ int at = 0;
+ for (int i = _path.length - 1; i >= 0; i--) {
+ if (_path[i] == '/') {
+ at = i + 1;
+ break;
+ }
+ }
+ int len = _path.length - at;
+ char[] basename = new char[len];
+ System.arraycopy(_path, at, basename, 0, len);
+ return basename;
+ }
+
+ /**
+ * Get the escaped basename of the path.
+ *
+ * @return the escaped basename string
+ */
+ public String getEscapedName() {
+ char[] basename = getRawName();
+ return (basename == null) ? null : new String(basename);
+ }
+
+ /**
+ * Get the basename of the path.
+ *
+ * @return the basename string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getName() throws IOException {
+ char[] basename = getRawName();
+ return (basename == null) ? null : decode(getRawName());
+ }
+
+ // ----------------------------------------------------- The path and query
+
+ /**
+ * Get the raw-escaped path and query.
+ *
+ * @return the raw-escaped path and query
+ */
+ public char[] getRawPathQuery() {
+
+ if (_path == null && _query == null) {
+ return null;
+ }
+ StringBuffer buff = new StringBuffer();
+ if (_path != null) {
+ buff.append(_path);
+ }
+ if (_query != null) {
+ buff.append('?');
+ buff.append(_query);
+ }
+ return buff.toString().toCharArray();
+ }
+
+ /**
+ * Get the escaped query.
+ *
+ * @return the escaped path and query string
+ */
+ public String getEscapedPathQuery() {
+ char[] rawPathQuery = getRawPathQuery();
+ return (rawPathQuery == null) ? null : new String(rawPathQuery);
+ }
+
+ /**
+ * Get the path and query.
+ *
+ * @return the path and query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getPathQuery() throws IOException {
+ char[] rawPathQuery = getRawPathQuery();
+ return (rawPathQuery == null) ? null : decode(rawPathQuery);
+ }
+
+ // -------------------------------------------------------------- The query
+
+ /**
+ * Set the raw-escaped query.
+ *
+ * @param escapedQuery the raw-escaped query
+ * @exception IOException escaped query not valid
+ * @throws NullPointerException null query
+ */
+ public void setRawQuery(char[] escapedQuery) throws IOException {
+ if (!validate(escapedQuery, query))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped query not valid");
+ _query = escapedQuery;
+ setUriReference();
+ }
+
+ /**
+ * Set the escaped query string.
+ *
+ * @param escapedQuery the escaped query string
+ * @exception IOException escaped query not valid
+ * @throws NullPointerException null query
+ */
+ public void setEscapedQuery(String escapedQuery) throws IOException {
+ setRawQuery(escapedQuery.toCharArray());
+ }
+
+ /**
+ * Set the query. When a query string is not misunderstood the reserved special
+ * characters ("&amp;", "=", "+", ",", and "$") within a query component, it is
+ * recommended to use in encoding the whole query with this method.
+ *
+ * @param query the query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @throws NullPointerException null query
+ * @see #encode
+ */
+ public void setQuery(String query) throws IOException {
+ setRawQuery(encode(query, allowed_query));
+ }
+
+ /**
+ * Get the raw-escaped query.
+ *
+ * @return the raw-escaped query
+ */
+ public char[] getRawQuery() {
+ return _query;
+ }
+
+ /**
+ * Get the escaped query.
+ *
+ * @return the escaped query string
+ */
+ public String getEscapedQuery() {
+ return (_query == null) ? null : new String(_query);
+ }
+
+ /**
+ * Get the query.
+ *
+ * @return the query string.
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getQuery() throws IOException {
+ return (_query == null) ? null : decode(_query);
+ }
+
+ // ----------------------------------------------------------- The fragment
+
+ /**
+ * Set the raw-escaped fragment.
+ *
+ * @param escapedFragment the raw-escaped fragment
+ * @exception IOException escaped fragment not valid
+ * @throws NullPointerException null fragment
+ */
+ public void setRawFragment(char[] escapedFragment) throws IOException {
+ if (!validate(escapedFragment, fragment))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped fragment not valid");
+ _fragment = escapedFragment;
+ setUriReference();
+ }
+
+ /**
+ * Set the escaped fragment string.
+ *
+ * @param escapedFragment the escaped fragment string
+ * @exception IOException escaped fragment not valid
+ * @throws NullPointerException null fragment
+ */
+ public void setEscapedFragment(String escapedFragment) throws IOException {
+ char[] fragmentSequence = escapedFragment.toCharArray();
+ if (!validate(fragmentSequence, fragment))
+ throw new IOException(/* IOException.ESCAPING, */
+ "URI: escaped fragment not valid");
+ _fragment = fragmentSequence;
+ setUriReference();
+ }
+
+ /**
+ * Set the fragment.
+ *
+ * @param the fragment string.
+ * @exception IOException Or unsupported character encoding
+ * @throws NullPointerException null fragment
+ */
+ public void setFragment(String fragment) throws IOException {
+ _fragment = encode(fragment, allowed_fragment);
+ setUriReference();
+ }
+
+ /**
+ * Get the raw-escaped fragment.
+ * <p>
+ * The optional fragment identifier is not part of a URI, but is often used in
+ * conjunction with a URI.
+ * <p>
+ * The format and interpretation of fragment identifiers is dependent on the
+ * media type [RFC2046] of the retrieval result.
+ * <p>
+ * A fragment identifier is only meaningful when a URI reference is intended for
+ * retrieval and the result of that retrieval is a document for which the
+ * identified fragment is consistently defined.
+ *
+ * @return the raw-escaped fragment
+ */
+ public char[] getRawFragment() {
+ return _fragment;
+ }
+
+ /**
+ * Get the escaped fragment.
+ *
+ * @return the escaped fragment string
+ */
+ public String getEscapedFragment() {
+ return (_fragment == null) ? null : new String(_fragment);
+ }
+
+ /**
+ * Get the fragment.
+ *
+ * @return the fragment string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getFragment() throws IOException {
+ return (_fragment == null) ? null : decode(_fragment);
+ }
+
+ // ------------------------------------------------------------- Utilities
+
+ /**
+ * Normalize the given hier path part.
+ *
+ * @param path the path to normalize
+ * @return the normalized path
+ */
+ protected char[] normalize(char[] path) {
+
+ if (path == null)
+ return null;
+
+ String normalized = new String(path);
+ boolean endsWithSlash = true;
+ // precondition
+ if (!normalized.endsWith("/")) {
+ normalized += '/';
+ endsWithSlash = false;
+ }
+ if (normalized.endsWith("/./") || normalized.endsWith("/../")) {
+ endsWithSlash = true;
+ }
+ // Resolve occurrences of "/./" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("/./");
+ if (at == -1) {
+ break;
+ }
+ normalized = normalized.substring(0, at) + normalized.substring(at + 2);
+ }
+ // Resolve occurrences of "/../" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("/../");
+ if (at == -1) {
+ break;
+ }
+ if (at == 0) {
+ normalized = "/";
+ break;
+ }
+ int backward = normalized.lastIndexOf('/', at - 1);
+ if (backward == -1) {
+ // consider the rel_path
+ normalized = normalized.substring(at + 4);
+ } else {
+ normalized = normalized.substring(0, backward) + normalized.substring(at + 3);
+ }
+ }
+ // Resolve occurrences of "//" in the normalized path
+ while (true) {
+ int at = normalized.indexOf("//");
+ if (at == -1) {
+ break;
+ }
+ normalized = normalized.substring(0, at) + normalized.substring(at + 1);
+ }
+ if (!endsWithSlash && normalized.endsWith("/")) {
+ normalized = normalized.substring(0, normalized.length() - 1);
+ } else if (endsWithSlash && !normalized.endsWith("/")) {
+ normalized = normalized + "/";
+ }
+ // Set the normalized path that we have completed
+ return normalized.toCharArray();
+ }
+
+ /**
+ * Normalize the path part of this URI.
+ */
+ public void normalize() {
+ _path = normalize(_path);
+ }
+
+ /**
+ * Test if the first array is equal to the second array.
+ *
+ * @param first the first character array
+ * @param second the second character array
+ * @return true if they're equal
+ */
+ protected boolean equals(char[] first, char[] second) {
+
+ if (first == null && second == null) {
+ return true;
+ }
+ if (first == null || second == null) {
+ return false;
+ }
+ if (first.length != second.length) {
+ return false;
+ }
+ for (int i = 0; i < first.length; i++) {
+ if (first[i] != second[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test an object if this URI is equal to another.
+ *
+ * @param obj an object to compare
+ * @return true if two URI objects are equal
+ */
+ public boolean equals(Object obj) {
+
+ // normalize and test each components
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof URI)) {
+ return false;
+ }
+ URI another = (URI) obj;
+ // scheme
+ if (!equals(_scheme, another._scheme)) {
+ return false;
+ }
+ // is_opaque_part or is_hier_part? and opaque
+ if (!equals(_opaque, another._opaque)) {
+ return false;
+ }
+ // is_hier_part
+ // has_authority
+ if (!equals(_authority, another._authority)) {
+ return false;
+ }
+ // path
+ if (!equals(_path, another._path)) {
+ return false;
+ }
+ // has_query
+ if (!equals(_query, another._query)) {
+ return false;
+ }
+ // has_fragment? should be careful of the only fragment case.
+ if (!equals(_fragment, another._fragment)) {
+ return false;
+ }
+ return true;
+ }
+
+ // ---------------------------------------------------------- Serialization
+
+ /**
+ * Write the content of this URI.
+ *
+ * @param oos the object-output stream
+ */
+ protected void writeObject(java.io.ObjectOutputStream oos) throws IOException {
+
+ oos.defaultWriteObject();
+ }
+
+ /**
+ * Read a URI.
+ *
+ * @param ois the object-input stream
+ */
+ protected void readObject(java.io.ObjectInputStream ois) throws ClassNotFoundException, IOException {
+
+ ois.defaultReadObject();
+ }
+
+ // ------------------------------------------------------------- Comparison
+
+ /**
+ * Compare this URI to another object.
+ *
+ * @param obj the object to be compared.
+ * @return 0, if it's same, -1, if failed, first being compared with in the
+ * authority component
+ * @exception ClassCastException not URI argument
+ * @throws NullPointerException null object
+ */
+ public int compareTo(Object obj) {
+
+ URI another = (URI) obj;
+ if (!equals(_authority, another.getRawAuthority()))
+ return -1;
+ return toString().compareTo(another.toString());
+ }
+
+ // ------------------------------------------------------------------ Clone
+
+ /**
+ * Create and return a copy of this object, the URI-reference containing the
+ * userinfo component. Notice that the whole URI-reference including the
+ * userinfo component counld not be gotten as a <code>String</code>.
+ * <p>
+ * To copy the identical <code>URI</code> object including the userinfo
+ * component, it should be used.
+ *
+ * @return a clone of this instance
+ */
+ public synchronized Object clone() {
+
+ URI instance = new URI();
+
+ instance._uri = _uri;
+ instance._scheme = _scheme;
+ instance._opaque = _opaque;
+ instance._authority = _authority;
+ instance._userinfo = _userinfo;
+ instance._host = _host;
+ instance._port = _port;
+ instance._path = _path;
+ instance._query = _query;
+ instance._fragment = _fragment;
+ // flags
+ instance._is_hier_part = _is_hier_part;
+ instance._is_opaque_part = _is_opaque_part;
+ instance._is_net_path = _is_net_path;
+ instance._is_abs_path = _is_abs_path;
+ instance._is_rel_path = _is_rel_path;
+ instance._is_reg_name = _is_reg_name;
+ instance._is_server = _is_server;
+ instance._is_hostname = _is_hostname;
+ instance._is_IPv4address = _is_IPv4address;
+ instance._is_IPv6reference = _is_IPv6reference;
+
+ return instance;
+ }
+
+ // ------------------------------------------------------------ Get the URI
+
+ /**
+ * It can be gotten the URI character sequence. It's raw-escaped. For the
+ * purpose of the protocol to be transported, it will be useful.
+ * <p>
+ * It is clearly unwise to use a URL that contains a password which is intended
+ * to be secret. In particular, the use of a password within the 'userinfo'
+ * component of a URL is strongly disrecommended except in those rare cases
+ * where the 'password' parameter is intended to be public.
+ * <p>
+ * When you want to get each part of the userinfo, you need to use the specific
+ * methods in the specific URL. It depends on the specific URL.
+ *
+ * @return URI character sequence
+ */
+ public char[] getRawURI() {
+ return _uri;
+ }
+
+ /**
+ * It can be gotten the URI character sequence. It's escaped. For the purpose of
+ * the protocol to be transported, it will be useful.
+ *
+ * @return the URI string
+ */
+ public String getEscapedURI() {
+ return (_uri == null) ? null : new String(_uri);
+ }
+
+ /**
+ * It can be gotten the URI character sequence.
+ *
+ * @return the URI string
+ * @exception IOException incomplete trailing escape pattern Or unsupported
+ * character encoding
+ * @see #decode
+ */
+ public String getURI() throws IOException {
+ return (_uri == null) ? null : decode(_uri);
+ }
+
+ /**
+ * Get the escaped URI string.
+ * <p>
+ * On the document, the URI-reference form is only used without the userinfo
+ * component like http://jakarta.apache.org/ by the security reason. But the
+ * URI-reference form with the userinfo component could be parsed.
+ * <p>
+ * In other words, this URI and any its subclasses must not expose the
+ * URI-reference expression with the userinfo component like
+ * http://user:password@hostport/restricted_zone.<br>
+ * It means that the API client programmer should extract each user and password
+ * to access manually. Probably it will be supported in the each subclass,
+ * however, not a whole URI-reference expression.
+ *
+ * @return the URI string
+ * @see #clone()
+ */
+ public String toString() {
+ return getEscapedURI();
+ }
+
+ // ------------------------------------------------------------ Inner class
+
+ /**
+ * A mapping to determine the (somewhat arbitrarily) preferred charset for a
+ * given locale. Supports all locales recognized in JDK 1.1.
+ * <p>
+ * The distribution of this class is Servlets.com. It was originally written by
+ * Jason Hunter [jhunter at acm.org] and used by with permission.
+ */
+ public static class LocaleToCharsetMap {
+
+ private static Hashtable map;
+ static {
+ map = new Hashtable();
+ map.put("ar", "ISO-8859-6");
+ map.put("be", "ISO-8859-5");
+ map.put("bg", "ISO-8859-5");
+ map.put("ca", "ISO-8859-1");
+ map.put("cs", "ISO-8859-2");
+ map.put("da", "ISO-8859-1");
+ map.put("de", "ISO-8859-1");
+ map.put("el", "ISO-8859-7");
+ map.put("en", "ISO-8859-1");
+ map.put("es", "ISO-8859-1");
+ map.put("et", "ISO-8859-1");
+ map.put("fi", "ISO-8859-1");
+ map.put("fr", "ISO-8859-1");
+ map.put("hr", "ISO-8859-2");
+ map.put("hu", "ISO-8859-2");
+ map.put("is", "ISO-8859-1");
+ map.put("it", "ISO-8859-1");
+ map.put("iw", "ISO-8859-8");
+ map.put("ja", "Shift_JIS");
+ map.put("ko", "EUC-KR");
+ map.put("lt", "ISO-8859-2");
+ map.put("lv", "ISO-8859-2");
+ map.put("mk", "ISO-8859-5");
+ map.put("nl", "ISO-8859-1");
+ map.put("no", "ISO-8859-1");
+ map.put("pl", "ISO-8859-2");
+ map.put("pt", "ISO-8859-1");
+ map.put("ro", "ISO-8859-2");
+ map.put("ru", "ISO-8859-5");
+ map.put("sh", "ISO-8859-5");
+ map.put("sk", "ISO-8859-2");
+ map.put("sl", "ISO-8859-2");
+ map.put("sq", "ISO-8859-2");
+ map.put("sr", "ISO-8859-5");
+ map.put("sv", "ISO-8859-1");
+ map.put("tr", "ISO-8859-9");
+ map.put("uk", "ISO-8859-5");
+ map.put("zh", "GB2312");
+ map.put("zh_TW", "Big5");
+ }
+
+ /**
+ * Get the preferred charset for the given locale.
+ *
+ * @param locale the locale
+ * @return the preferred charset or null if the locale is not recognized
+ */
+ public static String getCharset(Locale locale) {
+ // try for an full name match (may include country)
+ String charset = (String) map.get(locale.toString());
+ if (charset != null)
+ return charset;
+
+ // if a full name didn't match, try just the language
+ charset = (String) map.get(locale.getLanguage());
+ return charset; // may be null
+ }
+
+ }
}
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
index 377345c..cc95697 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionResults.java
@@ -19,33 +19,27 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* An interface defining the results of a DirectAction.
-* Implemented by both WOResponse and WOComponent so both
-* can be returned from a DirectAction.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public interface WOActionResults
-{
-/**
-* Returns a response object as appropriate for the target.
-*/
- WOResponse generateResponse ();
+ * An interface defining the results of a DirectAction. Implemented by both
+ * WOResponse and WOComponent so both can be returned from a DirectAction.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public interface WOActionResults {
+ /**
+ * Returns a response object as appropriate for the target.
+ */
+ WOResponse generateResponse();
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
index 78191b6..86e7807 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActionURL.java
@@ -21,20 +21,23 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * This dynamic element renders only the URL of a hyperlink.
- * Bindings are:
+ * This dynamic element renders only the URL of a hyperlink. Bindings are:
* <ul>
* <li>href: The URL that the hyperlink should point to.</li>
- * <li>pageName: The name of the WOComponent that the hyperlink should point to.</li>
- * <li>directActionName: The name of the direct action to call when the link is activated.</li>
- * <li>actionClass: The name of the WODirectAction subclass where the direct action resides.</li>
- * <li>action: A pointer to a method on the component that contains this element. If the link is activated,
- * the method will be called.
+ * <li>pageName: The name of the WOComponent that the hyperlink should point
+ * to.</li>
+ * <li>directActionName: The name of the direct action to call when the link is
+ * activated.</li>
+ * <li>actionClass: The name of the WODirectAction subclass where the direct
+ * action resides.</li>
+ * <li>action: A pointer to a method on the component that contains this
+ * element. If the link is activated, the method will be called.
* <li>ref: The name of the anchor to go to inside the resulting page.</li>
* </ul>
*
- * The href, pageName and directActionName/actionClass and name properties are mutually exclusive and you should
- * only use at most one of them simultaneously.
+ * The href, pageName and directActionName/actionClass and name properties are
+ * mutually exclusive and you should only use at most one of them
+ * simultaneously.
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -42,16 +45,16 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOActionURL extends WOHyperlink {
- public WOActionURL() {
- super();
- }
+ public WOActionURL() {
+ super();
+ }
- public WOActionURL(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOActionURL(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString(actionURL(c));
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString(actionURL(c));
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
index cad6f64..bf80b3e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOActiveImage.java
@@ -7,8 +7,9 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
- * WOActiveImage renders a dynamically generated IMG tag, enclosed in a hyperlink.
- * Internally, it uses a WOImage and a WOHyperlink to do the actual work.
+ * WOActiveImage renders a dynamically generated IMG tag, enclosed in a
+ * hyperlink. Internally, it uses a WOImage and a WOHyperlink to do the actual
+ * work.
*
* The bindings are those of WOImage and WOHyperlink combined.
*
@@ -18,64 +19,64 @@ import net.wotonomy.foundation.NSMutableDictionary;
*/
public class WOActiveImage extends WODynamicElement {
- protected WOActiveImage() {
- super();
- }
+ protected WOActiveImage() {
+ super();
+ }
- public WOActiveImage(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
+ public WOActiveImage(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- NSMutableDictionary atribs = new NSMutableDictionary(5);
- if (associations.objectForKey("mimeType") != null)
- atribs.setObjectForKey(associations.objectForKey("mimeType"), "mimeType");
- if (associations.objectForKey("data") != null)
- atribs.setObjectForKey(associations.objectForKey("data"), "data");
- if (associations.objectForKey("src") != null)
- atribs.setObjectForKey(associations.objectForKey("src"), "src");
- if (associations.objectForKey("framework") != null)
- atribs.setObjectForKey(associations.objectForKey("framework"), "framework");
- if (associations.objectForKey("filename") != null)
- atribs.setObjectForKey(associations.objectForKey("filename"), "filename");
- if (associations.objectForKey("alt") != null)
- atribs.setObjectForKey(associations.objectForKey("alt"), "alt");
- if (associations.objectForKey("border") != null)
- atribs.setObjectForKey(associations.objectForKey("border"), "border");
- if (associations.objectForKey("width") != null)
- atribs.setObjectForKey(associations.objectForKey("width"), "width");
- if (associations.objectForKey("height") != null)
- atribs.setObjectForKey(associations.objectForKey("height"), "height");
- WODynamicElement img = new WOImage("WOImage_" + name, atribs, null);
- NSMutableDictionary uf = new NSMutableDictionary();
- Enumeration enumeration = associations.keyEnumerator();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (key.startsWith("?"))
- uf.setObjectForKey(associations.objectForKey(key), key);
- }
- createLink(img).appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ NSMutableDictionary atribs = new NSMutableDictionary(5);
+ if (associations.objectForKey("mimeType") != null)
+ atribs.setObjectForKey(associations.objectForKey("mimeType"), "mimeType");
+ if (associations.objectForKey("data") != null)
+ atribs.setObjectForKey(associations.objectForKey("data"), "data");
+ if (associations.objectForKey("src") != null)
+ atribs.setObjectForKey(associations.objectForKey("src"), "src");
+ if (associations.objectForKey("framework") != null)
+ atribs.setObjectForKey(associations.objectForKey("framework"), "framework");
+ if (associations.objectForKey("filename") != null)
+ atribs.setObjectForKey(associations.objectForKey("filename"), "filename");
+ if (associations.objectForKey("alt") != null)
+ atribs.setObjectForKey(associations.objectForKey("alt"), "alt");
+ if (associations.objectForKey("border") != null)
+ atribs.setObjectForKey(associations.objectForKey("border"), "border");
+ if (associations.objectForKey("width") != null)
+ atribs.setObjectForKey(associations.objectForKey("width"), "width");
+ if (associations.objectForKey("height") != null)
+ atribs.setObjectForKey(associations.objectForKey("height"), "height");
+ WODynamicElement img = new WOImage("WOImage_" + name, atribs, null);
+ NSMutableDictionary uf = new NSMutableDictionary();
+ Enumeration enumeration = associations.keyEnumerator();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (key.startsWith("?"))
+ uf.setObjectForKey(associations.objectForKey(key), key);
+ }
+ createLink(img).appendToResponse(r, c);
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- return createLink(null).invokeAction(r, c);
- }
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ return createLink(null).invokeAction(r, c);
+ }
- protected WOHyperlink createLink(WOElement e) {
- NSMutableDictionary atribs = new NSMutableDictionary(5);
- if (associations.objectForKey("href") != null)
- atribs.setObjectForKey(associations.objectForKey("href"), "href");
- if (associations.objectForKey("pageName") != null)
- atribs.setObjectForKey(associations.objectForKey("pageName"), "pageName");
- if (associations.objectForKey("action") != null)
- atribs.setObjectForKey(associations.objectForKey("action"), "action");
- if (associations.objectForKey("directActionName") != null)
- atribs.setObjectForKey(associations.objectForKey("directActionName"), "directActionName");
- if (associations.objectForKey("actionClass") != null)
- atribs.setObjectForKey(associations.objectForKey("actionClass"), "actionClass");
- if (associations.objectForKey("target") != null)
- atribs.setObjectForKey(associations.objectForKey("target"), "target");
- return new WOHyperlink(name, atribs, e);
- }
+ protected WOHyperlink createLink(WOElement e) {
+ NSMutableDictionary atribs = new NSMutableDictionary(5);
+ if (associations.objectForKey("href") != null)
+ atribs.setObjectForKey(associations.objectForKey("href"), "href");
+ if (associations.objectForKey("pageName") != null)
+ atribs.setObjectForKey(associations.objectForKey("pageName"), "pageName");
+ if (associations.objectForKey("action") != null)
+ atribs.setObjectForKey(associations.objectForKey("action"), "action");
+ if (associations.objectForKey("directActionName") != null)
+ atribs.setObjectForKey(associations.objectForKey("directActionName"), "directActionName");
+ if (associations.objectForKey("actionClass") != null)
+ atribs.setObjectForKey(associations.objectForKey("actionClass"), "actionClass");
+ if (associations.objectForKey("target") != null)
+ atribs.setObjectForKey(associations.objectForKey("target"), "target");
+ return new WOHyperlink(name, atribs, e);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
index 90e40c6..46b598c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOApplication.java
@@ -37,1157 +37,982 @@ import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.util.InetAddrPort;
/**
-* A pure java implementation of WOApplication. <br><br>
-*
-* The application is responsible for creating and managing sessions
-* and dispatching requests to the appropriate handlers. <br><br>
-*
-* This implementation extends HttpServlet, so the application itself
-* is a servlet and can be configured and managed as such by the servlet
-* container.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOApplication
- extends HttpServlet
-{
- /**
- * A tricky way to allow multiple WOApplications
- * in the same servlet container.
- */
- static private ThreadLocal threadLocal;
- //static private WOApplication application;
-
- /**
- * Determines application-wide page caching.
- * Pages may individually prevent caching.
- */
- static private boolean cachingEnabled = false;
- private static boolean autoOpenInBrowser = true;
-
- private String name;
+ * A pure java implementation of WOApplication. <br>
+ * <br>
+ *
+ * The application is responsible for creating and managing sessions and
+ * dispatching requests to the appropriate handlers. <br>
+ * <br>
+ *
+ * This implementation extends HttpServlet, so the application itself is a
+ * servlet and can be configured and managed as such by the servlet container.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOApplication extends HttpServlet {
+ /**
+ * A tricky way to allow multiple WOApplications in the same servlet container.
+ */
+ static private ThreadLocal threadLocal;
+ // static private WOApplication application;
+
+ /**
+ * Determines application-wide page caching. Pages may individually prevent
+ * caching.
+ */
+ static private boolean cachingEnabled = false;
+ private static boolean autoOpenInBrowser = true;
+
+ private String name;
private WORequestHandler defaultRequestHandler;
- private NSMutableDictionary requestHandlers;
- private WOSessionStore sessionStore;
- private WOResourceManager resourceManager;
- private boolean pageRefreshOnBacktrack;
- private int pageCacheSize;
- private int permanentPageCacheSize;
-
- public static final String WOApplicationWillFinishLaunchingNotification
- = "WOApplicationWillFinishLaunchingNotification";
- public static final String WOApplicationDidFinishLaunchingNotification
- = "WOApplicationDidFinishLaunchingNotification";
- public static final String WOGarbageCollectionPeriodKey
- = "WOGarbageCollectionPeriodKey";
-
- static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey";
- static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey";
- static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey";
- static String WOPort = "WOPort";
- static String WOSMTPHost = "WOSMTPHost";
- static final String ELEMENT_CLASS = "elementClass";
-
- public WOApplication ()
- {
- if ( threadLocal == null )
- {
- threadLocal = new ThreadLocal();
- }
- threadLocal.set( this );
-
- //application = this;
- resourceManager = createResourceManager();
- requestHandlers = new NSMutableDictionary();
- defaultRequestHandler = new WODirectActionRequestHandler();
- registerRequestHandler( defaultRequestHandler, directActionRequestHandlerKey() );
- registerRequestHandler( new WOComponentRequestHandler(), componentRequestHandlerKey() );
- registerRequestHandler( new WOResourceRequestHandler(), resourceRequestHandlerKey() );
- sessionStore = WOSessionStore.serverSessionStore();
-
- pageRefreshOnBacktrack = true;
- pageCacheSize = 30;
- permanentPageCacheSize = 30;
-
- threadLocal.set( null );
- }
-
+ private NSMutableDictionary requestHandlers;
+ private WOSessionStore sessionStore;
+ private WOResourceManager resourceManager;
+ private boolean pageRefreshOnBacktrack;
+ private int pageCacheSize;
+ private int permanentPageCacheSize;
+
+ public static final String WOApplicationWillFinishLaunchingNotification = "WOApplicationWillFinishLaunchingNotification";
+ public static final String WOApplicationDidFinishLaunchingNotification = "WOApplicationDidFinishLaunchingNotification";
+ public static final String WOGarbageCollectionPeriodKey = "WOGarbageCollectionPeriodKey";
+
+ static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey";
+ static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey";
+ static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey";
+ static String WOPort = "WOPort";
+ static String WOSMTPHost = "WOSMTPHost";
+ static final String ELEMENT_CLASS = "elementClass";
+
+ public WOApplication() {
+ if (threadLocal == null) {
+ threadLocal = new ThreadLocal();
+ }
+ threadLocal.set(this);
+
+ // application = this;
+ resourceManager = createResourceManager();
+ requestHandlers = new NSMutableDictionary();
+ defaultRequestHandler = new WODirectActionRequestHandler();
+ registerRequestHandler(defaultRequestHandler, directActionRequestHandlerKey());
+ registerRequestHandler(new WOComponentRequestHandler(), componentRequestHandlerKey());
+ registerRequestHandler(new WOResourceRequestHandler(), resourceRequestHandlerKey());
+ sessionStore = WOSessionStore.serverSessionStore();
+
+ pageRefreshOnBacktrack = true;
+ pageCacheSize = 30;
+ permanentPageCacheSize = 30;
+
+ threadLocal.set(null);
+ }
+
/**
- * Dispatches the request and updates the specified response
- * as appropriate. This implementation creates a new WORequest
- * and WOContext from the request, sends the response to the
- * appropriate WORequestHandler, and then updates the servlet
- * response from the resulting WOResponse.
- */
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- threadLocal.set( this );
-
- WORequest request = new WORequest( req, this );
- WOResponse response = dispatchRequest( request );
- response.generateServletResponse( resp );
- }
+ * Dispatches the request and updates the specified response as appropriate.
+ * This implementation creates a new WORequest and WOContext from the request,
+ * sends the response to the appropriate WORequestHandler, and then updates the
+ * servlet response from the resulting WOResponse.
+ */
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, java.io.IOException {
+ threadLocal.set(this);
+
+ WORequest request = new WORequest(req, this);
+ WOResponse response = dispatchRequest(request);
+ response.generateServletResponse(resp);
+ }
/**
- * Handles post requests by calling doGet(), since the framework
- * handles both gets and posts similarly. Override to handle
- * post requests in a different manner.
- */
- protected void doPost(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- doGet( req, resp );
+ * Handles post requests by calling doGet(), since the framework handles both
+ * gets and posts similarly. Override to handle post requests in a different
+ * manner.
+ */
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, java.io.IOException {
+ doGet(req, resp);
}
-
+
// obtaining attributes
-
+
+ /**
+ * Returns the singleton instance of this application.
+ */
+ public static WOApplication application() {
+ return (WOApplication) threadLocal.get();
+ // return application;
+ }
+
+ /**
+ * Returns the name of the application. This implementation returns the name the
+ * jar file or directory from which the class was loaded, with no extensions.
+ */
+ public String name() {
+ if (name == null) {
+ name = path();
+ int i;
+ if (name.endsWith("/")) { // path
+ name = name.substring(0, name.length() - 1);
+ } else { // jar file
+ i = name.lastIndexOf('.');
+ if (i != -1)
+ name = name.substring(0, i);
+ }
+ i = name.lastIndexOf('/');
+ if (i != -1)
+ name = name.substring(i + 1);
+ }
+ return name;
+ }
+
/**
- * Returns the singleton instance of this application.
- */
- public static WOApplication application()
- {
- return (WOApplication) threadLocal.get();
- //return application;
- }
-
+ * Returns the absolute path to the application on the local file system. Note
+ * that the application might be embedded inside of a jar file.
+ */
+ public String path() {
+ return getClass().getProtectionDomain().getCodeSource().getLocation().toString();
+ }
+
/**
- * Returns the name of the application. This implementation returns
- * the name the jar file or directory from which the class was loaded,
- * with no extensions.
- */
- public String name()
- {
- if ( name == null )
- {
- name = path();
- int i;
- if ( name.endsWith( "/" ) )
- { // path
- name = name.substring( 0, name.length() - 1 );
- }
- else
- { // jar file
- i = name.lastIndexOf( '.' );
- if ( i != -1 ) name = name.substring( 0, i );
- }
- i = name.lastIndexOf( '/' );
- if ( i != -1 ) name = name.substring( i+1 );
- }
- return name;
- }
-
- /**
- * Returns the absolute path to the application on the local file system.
- * Note that the application might be embedded inside of a jar file.
- */
- public String path ()
- {
- return getClass().getProtectionDomain().getCodeSource().getLocation().toString();
- }
-
- /**
- * Returns the path to the application on the local file system
- * relative to the server's document root.
- */
- public String baseURL ()
- {
- String root = getServletContext().getRealPath( "/" );
- String result = path();
- if ( result.endsWith("/") )
- { // path
- if ( result.startsWith( root ) )
- { // relative to root
- result = result.substring( root.length() );
- }
- // else leave as absolute reference
- }
- // jar or war file: leave as absolute reference
- return result;
- }
-
- // concurrent request handling
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- * Subclasses may override to return false to force
- * single-threaded request handling, although this
- * is not implemented.
- */
- public boolean allowsConcurrentRequestHandling ()
- {
- return true;
- }
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- */
- public boolean adaptorsDispatchRequestsConcurrently ()
- {
- return true;
- }
-
- /**
- * Returns whether this application allows request
- * to be handled concurrently.
- * This implementation returns true.
- */
- public boolean isConcurrentRequestHandlingEnabled ()
- {
- return true;
- }
-
- // handling requests
+ * Returns the path to the application on the local file system relative to the
+ * server's document root.
+ */
+ public String baseURL() {
+ String root = getServletContext().getRealPath("/");
+ String result = path();
+ if (result.endsWith("/")) { // path
+ if (result.startsWith(root)) { // relative to root
+ result = result.substring(root.length());
+ }
+ // else leave as absolute reference
+ }
+ // jar or war file: leave as absolute reference
+ return result;
+ }
+
+ // concurrent request handling
/**
- * Invoked first in the request-response cycle.
- * Override to perform any kind of initialization at the
- * start of a request. This implementation does nothing.
- */
- public void awake ()
- {
-
- }
-
- /**
- * Invoked to start the first phase of the request-response cycle,
- * after all calls to awake() have been completed.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- aContext.session().takeValuesFromRequest( aRequest, aContext );
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true. Subclasses may override to return false to
+ * force single-threaded request handling, although this is not implemented.
+ */
+ public boolean allowsConcurrentRequestHandling() {
+ return true;
}
- /**
- * Invoked to start the second phase of the request-response cycle,
- * after all calls to takeValuesFromRequest have finished.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return aContext.session().invokeAction( aRequest, aContext );
- }
-
- /**
- * Invoked to start the third phase of the request-response cycle,
- * after invokeAction() has completed and returned a WOResponse.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- aContext.session().appendToResponse( aResponse, aContext );
- }
-
- /**
- * Invoked last in the request-response cycle.
- * Override to perform any kind of clean-up at the
- * end of a request. This implementation does nothing.
- */
- public void sleep ()
- {
-
- }
-
- /**
- * Dispatches the request to the appropriate handler.
- */
- public WOResponse dispatchRequest (WORequest aRequest)
- {
- return handlerForRequest( aRequest ).handleRequest( aRequest );
- }
-
- // request handling
-
- /**
- * Returns the default request handler used if the requested
- * handler isn't specified or cannot be found. (This defaults
- * to the WODirectActionRequestHandler.)
- */
- public WORequestHandler defaultRequestHandler ()
- {
- return defaultRequestHandler;
- }
-
- /**
- * Sets the default request handler used if the requested
- * handler isn't specified or cannot be found.
- */
- public void setDefaultRequestHandler (WORequestHandler aRequestHandler)
- {
- defaultRequestHandler = aRequestHandler;
- }
-
- /**
- * Registers the specified request handler for the specified key.
- */
- public void registerRequestHandler (WORequestHandler aRequestHandler, String aKey)
- {
- requestHandlers.setObjectForKey( aRequestHandler, aKey );
- }
-
- /**
- * Unregisters any existing request handler for the specified key
- * returning the existing request handler, if any.
- */
- public WORequestHandler removeRequestHandlerForKey (String aKey)
- {
- WORequestHandler result = requestHandlerForKey( aKey );
- requestHandlers.removeObjectForKey( aKey );
- return result;
- }
-
- /**
- * Returns the keys under which request handlers are registered.
- */
- public NSArray registeredRequestHandlerKeys ()
- {
- return requestHandlers.allKeys();
- }
-
- /**
- * Returns the request handler registered for the specified key,
- * or null if no request handler is registered for that key.
- */
- public WORequestHandler requestHandlerForKey (String aKey)
- {
- return (WORequestHandler) requestHandlers.objectForKey( aKey );
- }
-
- /**
- * Returns the request handler that would best service the specified request.
- */
- public WORequestHandler handlerForRequest (WORequest aRequest)
- {
- WORequestHandler result = requestHandlerForKey( aRequest.requestHandlerKey() );
- if ( aRequest == null ) result = defaultRequestHandler();
- return result;
- }
-
- // handling errors
-
- public WOResponse handleSessionCreationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to create session: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handleSessionRestorationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to restore session: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handlePageRestorationErrorInContext( WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- //TODO: add more useful information to the response
- System.err.println( "Failed to restore page: " + aContext );
-new RuntimeException().printStackTrace(); // remove me
- return response;
- }
-
- public WOResponse handleException( Throwable aThrowable, WOContext aContext )
- {
- WOResponse response = new WOResponse();
- response.setStatus( 500 ); // internal server error
- System.err.println( "Exception occurred: " + aContext );
- if ( aThrowable.getMessage() != null )
- {
- response.appendContentString( aThrowable.getMessage() );
- aThrowable.printStackTrace();
- }
- else
- {
- response.appendContentString( aThrowable.toString() );
- aThrowable.printStackTrace();
- }
- aThrowable.printStackTrace();
- return response;
- }
-
- // managing pages
-
- /**
- * Sets the number of pages that will be retained
- * in the user's session. Set to zero to disable page caching.
- */
- public void setPageCacheSize (int aPositiveInt)
- {
- pageCacheSize = aPositiveInt;
- }
-
- /**
- * Returns the number of pages that will be retained
- * in the user's session. The default page cache size is 30.
- */
- public int pageCacheSize ()
- {
- return pageCacheSize;
- }
-
- /**
- * Returns the number of pages that will be retained in the
- * longer-term "permanent" page cache in the user's session,
- * which is typically used for navigation bars in frames, etc.
- * The default permanent page cache size is 30.
- */
- public int permanentPageCacheSize ()
- {
- return permanentPageCacheSize;
- }
-
- /**
- * Returns the number of pages that will be retained in the
- * longer-term "permanent" page cache in the user's session,
- * which is typically used for navigation bars in frames, etc.
- * Set to zero to disable permanent page caching.
- */
- public void setPermanentPageCacheSize (int aPositiveInt)
- {
- permanentPageCacheSize = aPositiveInt;
- }
-
- /**
- * Returns whether a "backtrack" for an existing page should
- * simply call generateResponse() on the existing page instance.
- * If false, a new page is created instead. The default is true.
- */
- public void setPageRefreshOnBacktrackEnabled (boolean enabled)
- {
- pageRefreshOnBacktrack = enabled;
- }
-
- /**
- * Returns whether a "backtrack" for an existing page should
- * simply call generateResponse() on the existing page instance.
- * If false, a new page is created instead. The default is true.
- */
- public boolean isPageRefreshOnBacktrackEnabled ()
- {
- return pageRefreshOnBacktrack;
- }
-
- // managing sessions
-
- /**
- * Sets the session store used by this application to persist
- * sessions between request-response transactions.
- */
- public void setSessionStore(WOSessionStore aSessionStore)
- {
- sessionStore = aSessionStore;
- }
-
- /**
- * Returns the session store used by this application to persist
- * sessions between request-response transactions.
- */
- public WOSessionStore sessionStore()
- {
- return sessionStore;
- }
-
- /**
- * Called at the end of the request-response cycle
- * to persist the current session until the user's next request.
- */
- public void saveSessionForContext(WOContext aContext)
- {
- sessionStore.saveSessionForContext( aContext );
- }
-
- /**
- * Called at the beginning of the request-response cycle
- * to obtain the current session from the user's last request.
- * Returns null if no such session has been created.
- * This method sets the context of the session to the specified context.
- */
- public WOSession restoreSessionWithID(String aSessionID, WOContext aContext)
- {
- WORequest request = aContext.request();
- WOSession session = sessionStore.restoreSessionWithID( aSessionID, request );
- if ( session != null )
- {
- session.setContext( aContext );
- session.setServletSession( request.servletRequest().getSession() );
- }
- return session;
- }
-
- /**
- * Called to create a session for a new request. This implementation
- * looks for a class in the same package as the application class
- * called "Session" and failing that returns a WOSession.
- */
- public WOSession createSessionForRequest(WORequest aRequest)
- {
- WOSession result = null;
- try
- {
+ /**
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true.
+ */
+ public boolean adaptorsDispatchRequestsConcurrently() {
+ return true;
+ }
+
+ /**
+ * Returns whether this application allows request to be handled concurrently.
+ * This implementation returns true.
+ */
+ public boolean isConcurrentRequestHandlingEnabled() {
+ return true;
+ }
+
+ // handling requests
+
+ /**
+ * Invoked first in the request-response cycle. Override to perform any kind of
+ * initialization at the start of a request. This implementation does nothing.
+ */
+ public void awake() {
+
+ }
+
+ /**
+ * Invoked to start the first phase of the request-response cycle, after all
+ * calls to awake() have been completed.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ aContext.session().takeValuesFromRequest(aRequest, aContext);
+ }
+
+ /**
+ * Invoked to start the second phase of the request-response cycle, after all
+ * calls to takeValuesFromRequest have finished.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return aContext.session().invokeAction(aRequest, aContext);
+ }
+
+ /**
+ * Invoked to start the third phase of the request-response cycle, after
+ * invokeAction() has completed and returned a WOResponse.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ aContext.session().appendToResponse(aResponse, aContext);
+ }
+
+ /**
+ * Invoked last in the request-response cycle. Override to perform any kind of
+ * clean-up at the end of a request. This implementation does nothing.
+ */
+ public void sleep() {
+
+ }
+
+ /**
+ * Dispatches the request to the appropriate handler.
+ */
+ public WOResponse dispatchRequest(WORequest aRequest) {
+ return handlerForRequest(aRequest).handleRequest(aRequest);
+ }
+
+ // request handling
+
+ /**
+ * Returns the default request handler used if the requested handler isn't
+ * specified or cannot be found. (This defaults to the
+ * WODirectActionRequestHandler.)
+ */
+ public WORequestHandler defaultRequestHandler() {
+ return defaultRequestHandler;
+ }
+
+ /**
+ * Sets the default request handler used if the requested handler isn't
+ * specified or cannot be found.
+ */
+ public void setDefaultRequestHandler(WORequestHandler aRequestHandler) {
+ defaultRequestHandler = aRequestHandler;
+ }
+
+ /**
+ * Registers the specified request handler for the specified key.
+ */
+ public void registerRequestHandler(WORequestHandler aRequestHandler, String aKey) {
+ requestHandlers.setObjectForKey(aRequestHandler, aKey);
+ }
+
+ /**
+ * Unregisters any existing request handler for the specified key returning the
+ * existing request handler, if any.
+ */
+ public WORequestHandler removeRequestHandlerForKey(String aKey) {
+ WORequestHandler result = requestHandlerForKey(aKey);
+ requestHandlers.removeObjectForKey(aKey);
+ return result;
+ }
+
+ /**
+ * Returns the keys under which request handlers are registered.
+ */
+ public NSArray registeredRequestHandlerKeys() {
+ return requestHandlers.allKeys();
+ }
+
+ /**
+ * Returns the request handler registered for the specified key, or null if no
+ * request handler is registered for that key.
+ */
+ public WORequestHandler requestHandlerForKey(String aKey) {
+ return (WORequestHandler) requestHandlers.objectForKey(aKey);
+ }
+
+ /**
+ * Returns the request handler that would best service the specified request.
+ */
+ public WORequestHandler handlerForRequest(WORequest aRequest) {
+ WORequestHandler result = requestHandlerForKey(aRequest.requestHandlerKey());
+ if (aRequest == null)
+ result = defaultRequestHandler();
+ return result;
+ }
+
+ // handling errors
+
+ public WOResponse handleSessionCreationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to create session: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handleSessionRestorationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to restore session: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handlePageRestorationErrorInContext(WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ // TODO: add more useful information to the response
+ System.err.println("Failed to restore page: " + aContext);
+ new RuntimeException().printStackTrace(); // remove me
+ return response;
+ }
+
+ public WOResponse handleException(Throwable aThrowable, WOContext aContext) {
+ WOResponse response = new WOResponse();
+ response.setStatus(500); // internal server error
+ System.err.println("Exception occurred: " + aContext);
+ if (aThrowable.getMessage() != null) {
+ response.appendContentString(aThrowable.getMessage());
+ aThrowable.printStackTrace();
+ } else {
+ response.appendContentString(aThrowable.toString());
+ aThrowable.printStackTrace();
+ }
+ aThrowable.printStackTrace();
+ return response;
+ }
+
+ // managing pages
+
+ /**
+ * Sets the number of pages that will be retained in the user's session. Set to
+ * zero to disable page caching.
+ */
+ public void setPageCacheSize(int aPositiveInt) {
+ pageCacheSize = aPositiveInt;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the user's session. The
+ * default page cache size is 30.
+ */
+ public int pageCacheSize() {
+ return pageCacheSize;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the longer-term
+ * "permanent" page cache in the user's session, which is typically used for
+ * navigation bars in frames, etc. The default permanent page cache size is 30.
+ */
+ public int permanentPageCacheSize() {
+ return permanentPageCacheSize;
+ }
+
+ /**
+ * Returns the number of pages that will be retained in the longer-term
+ * "permanent" page cache in the user's session, which is typically used for
+ * navigation bars in frames, etc. Set to zero to disable permanent page
+ * caching.
+ */
+ public void setPermanentPageCacheSize(int aPositiveInt) {
+ permanentPageCacheSize = aPositiveInt;
+ }
+
+ /**
+ * Returns whether a "backtrack" for an existing page should simply call
+ * generateResponse() on the existing page instance. If false, a new page is
+ * created instead. The default is true.
+ */
+ public void setPageRefreshOnBacktrackEnabled(boolean enabled) {
+ pageRefreshOnBacktrack = enabled;
+ }
+
+ /**
+ * Returns whether a "backtrack" for an existing page should simply call
+ * generateResponse() on the existing page instance. If false, a new page is
+ * created instead. The default is true.
+ */
+ public boolean isPageRefreshOnBacktrackEnabled() {
+ return pageRefreshOnBacktrack;
+ }
+
+ // managing sessions
+
+ /**
+ * Sets the session store used by this application to persist sessions between
+ * request-response transactions.
+ */
+ public void setSessionStore(WOSessionStore aSessionStore) {
+ sessionStore = aSessionStore;
+ }
+
+ /**
+ * Returns the session store used by this application to persist sessions
+ * between request-response transactions.
+ */
+ public WOSessionStore sessionStore() {
+ return sessionStore;
+ }
+
+ /**
+ * Called at the end of the request-response cycle to persist the current
+ * session until the user's next request.
+ */
+ public void saveSessionForContext(WOContext aContext) {
+ sessionStore.saveSessionForContext(aContext);
+ }
+
+ /**
+ * Called at the beginning of the request-response cycle to obtain the current
+ * session from the user's last request. Returns null if no such session has
+ * been created. This method sets the context of the session to the specified
+ * context.
+ */
+ public WOSession restoreSessionWithID(String aSessionID, WOContext aContext) {
+ WORequest request = aContext.request();
+ WOSession session = sessionStore.restoreSessionWithID(aSessionID, request);
+ if (session != null) {
+ session.setContext(aContext);
+ session.setServletSession(request.servletRequest().getSession());
+ }
+ return session;
+ }
+
+ /**
+ * Called to create a session for a new request. This implementation looks for a
+ * class in the same package as the application class called "Session" and
+ * failing that returns a WOSession.
+ */
+ public WOSession createSessionForRequest(WORequest aRequest) {
+ WOSession result = null;
+ try {
// using our class loader, which is hopefully dynamic.
- result = (WOSession) getLocalClass( "Session" ).newInstance();
- }
- catch ( Throwable t )
- {
- // ignore: fall back to WOSession
- //t.printStackTrace();
- }
-
- if ( result == null )
- {
- result = new WOSession();
- }
-
- result.setServletSession( aRequest.servletRequest().getSession( true ) );
- return result;
- }
-
+ result = (WOSession) getLocalClass("Session").newInstance();
+ } catch (Throwable t) {
+ // ignore: fall back to WOSession
+ // t.printStackTrace();
+ }
+
+ if (result == null) {
+ result = new WOSession();
+ }
+
+ result.setServletSession(aRequest.servletRequest().getSession(true));
+ return result;
+ }
+
+ /**
+ * Returns the page component with the specified name. A context is created with
+ * the specified request, along with a session if necessary.
+ */
+ public WOComponent pageWithName(String aName, WORequest aRequest) {
+ return pageWithName(aName, WOContext.contextWithRequest(aRequest));
+ }
+
/**
- * Returns the page component with the specified name.
- * A context is created with the specified request,
- * along with a session if necessary.
- */
- public WOComponent pageWithName (String aName, WORequest aRequest)
- {
- return pageWithName( aName, WOContext.contextWithRequest( aRequest ) );
- }
-
- /**
- * Called to retrieve a component for the specified context.
- */
- public WOComponent pageWithName (String aName, WOContext aContext)
- {
- if ( aName == null )
- {
- throw new IllegalArgumentException(
- "WOApplication.pageWithName: name is null" );
- }
-
- WOComponent result = null;
- try
- {
+ * Called to retrieve a component for the specified context.
+ */
+ public WOComponent pageWithName(String aName, WOContext aContext) {
+ if (aName == null) {
+ throw new IllegalArgumentException("WOApplication.pageWithName: name is null");
+ }
+
+ WOComponent result = null;
+ try {
// using our class loader, which is hopefully dynamic.
- Class c = getLocalClass( aName );
-
- if ( c != null )
- {
- // get constructor
- Constructor ctor;
- try
- {
- ctor = c.getConstructor( new Class[] { WOContext.class } );
- }
- catch ( NoSuchMethodException nsme )
- {
- ctor = null;
- }
-
- // create instance of class
- if ( ctor != null )
- {
- result = (WOComponent) ctor.newInstance( new Object[] { aContext } );
- }
- else // call back on default constructor (deprecated)
- {
- result = (WOComponent) c.newInstance();
- }
- }
- }
- catch ( Throwable t )
- {
- // ignore for now
- //TODO: Throw appropriate exception here
- //System.err.println( "Not found: pageWithName: " + aName );
- t.printStackTrace();
- }
-
- if ( result != null && aContext != null )
- {
- // this is where components get their context
- result.ensureAwakeInContext( aContext );
- }
- else
- if ( result == null )
- {
- System.err.println( "Not found: pageWithName: " + aName );
- }
-
- return result;
- }
-
- /**
- * Returns a class in the same package as the Application class,
- * or, failing that, from the WOApplication package, or finally
- * from the root of the class path. Returns null if not found.
- */
- Class getLocalClass( String aName )
- {
- Class result = null;
- if ( getClass() != WOApplication.class )
- {
- result = loadLocalClass( getClass(), aName );
- }
- if ( result == null )
- {
- result = loadLocalClass( WOApplication.class, aName );
- }
- if ( result == null )
- {
- result = loadLocalClass( null, aName );
- }
- return result;
- }
-
- private static final Class loadLocalClass( Class aClass, String aName )
- {
- ClassLoader loader;
- String packageName = "";
- if ( aClass != null )
- {
- loader = aClass.getClassLoader();
- packageName = aClass.getName();
- int index = packageName.lastIndexOf( "." );
- if ( index > -1 )
- {
- packageName = packageName.substring( 0, index+1 );
- }
- else
- {
- packageName = "";
- }
- }
- else
- {
- loader = WOApplication.class.getClassLoader();
- }
-
- try
- {
- return loader.loadClass( packageName + aName );
- }
- catch ( ClassNotFoundException e )
- {
- return null;
- }
- }
-
- // creating elements
-
- /**
- * Returns either a dynamic element or a component
- * for the specified name.
- */
- public WOElement dynamicElementWithName(
- String anElementName, NSDictionary anAssociationMap,
- WOElement aBodyElement, List aLanguageList)
- {
- WOElement element = null;
- Class c = null;
- try
- {
- c = getLocalClass( anElementName );
- if ( c == null )
- {
- System.out.println( "Not found: dynamicElementWithName: " +
- "could not find WODynamicElement subclass: " + anElementName );
- c = WODynamicElement.class;
- }
-
- // get constructor
- Class[] params = new Class[]
- { String.class, NSDictionary.class, WOElement.class };
- Constructor ctor = c.getConstructor( params );
-
- // create instance of class
- if ( ctor != null )
- {
- element = (WODynamicElement) ctor.newInstance(
- new Object[] { anElementName, anAssociationMap, aBodyElement } );
- }
- }
- catch ( Throwable t )
- {
- // ignore: not a dynamic element
- //System.out.println( "Not a dynamic element: dynamicElementWithName: " + t );
- //exc.printStackTrace();
- }
-
- // no dynamic element found: look for a component
- if ( element == null )
- {
- WOComponent component = (WOComponent) pageWithName( anElementName, (WOContext) null );
-
- // this seems hackish:
- // I don't see another way of setting the bindings.
- component.associations = anAssociationMap;
- component.rootElement = aBodyElement;
-
- element = component;
- }
-
- return element;
- }
-
- // resource handling
-
- /**
- * Called to create the application's resource manager.
- * Override to create a custom resource manager.
- */
- public WOResourceManager createResourceManager()
- {
- return new WOResourceManager();
- }
-
- /**
- * Returns the application's current resource manager.
- */
- public WOResourceManager resourceManager()
- {
- return resourceManager;
- }
-
- /**
- * Installs a custom resource manager into the current application.
- * @deprecated Override createResourceManager() instead.
- */
- public void setResourceManager(WOResourceManager aResourceManager)
- {
- resourceManager = aResourceManager;
- }
+ Class c = getLocalClass(aName);
+
+ if (c != null) {
+ // get constructor
+ Constructor ctor;
+ try {
+ ctor = c.getConstructor(new Class[] { WOContext.class });
+ } catch (NoSuchMethodException nsme) {
+ ctor = null;
+ }
+
+ // create instance of class
+ if (ctor != null) {
+ result = (WOComponent) ctor.newInstance(new Object[] { aContext });
+ } else // call back on default constructor (deprecated)
+ {
+ result = (WOComponent) c.newInstance();
+ }
+ }
+ } catch (Throwable t) {
+ // ignore for now
+ // TODO: Throw appropriate exception here
+ // System.err.println( "Not found: pageWithName: " + aName );
+ t.printStackTrace();
+ }
+
+ if (result != null && aContext != null) {
+ // this is where components get their context
+ result.ensureAwakeInContext(aContext);
+ } else if (result == null) {
+ System.err.println("Not found: pageWithName: " + aName);
+ }
+
+ return result;
+ }
-/*
- // request handling undocumented
-
- public WOComponent pageWithName (String);
- public void savePage (WOComponent);
- public WOComponent restorePageForContextID (String);
- public WOContext context ();
- public WOSession session ();
- public WOSession createSession ();
- public WOSession restoreSession ();
- public void saveSession (WOSession);
-
- public WOResponse handleRequest (WORequest aRequest)
- {
- }
-
- // error handling undocumented
-
- WOResponse handleSessionCreationError ();
- WOResponse handleSessionRestorationError ();
- WOResponse handlePageRestorationError ();
- WOResponse handleException (Throwable);
-
- // running
-
- public NSRunLoop runLoop ();
- public void run ();
- public void setTimeOut (double);
- public double timeOut ();
- public void terminate ();
- public boolean isTerminating ();
-
- // script debugging
-
- public void traceScriptedMessages (boolean);
- public void traceAssignments (boolean);
- public void traceStatements (boolean);
- public void traceObjectiveCMessages (boolean);
- public void trace (boolean);
- public void logTakeValueForDeclarationNamed (String, String, String, String, Object);
- public void logSetValueForDeclarationNamed (String, String, String, String, Object);
-
- // script handling
-
- public String scriptedClassNameWithPath (String);
- public String scriptedClassNameWithPathEncoding (String, int);
-
- // statistics report
-
- public void setStatisticsStore (WOStatisticsStore);
- public WOStatisticsStore statisticsStore ();
- public NSDictionary statistics ();
-
- // managing adaptors
-
- public WOAdaptor adaptorWithName (String, NSDictionary);
- public NSArray adaptors ();
-
- // monitor support
-
- public boolean monitoringEnabled ();
- public int activeSessionsCount ();
- public void refuseNewSessions (boolean);
- public boolean isRefusingNewSessions ();
- public void setMinimumActiveSessionsCount (int);
- public int minimumActiveSessionsCount ();
- public void terminateAfterTimeInterval (double);
-
- // garbage collection undocumented
-
- int garbageCollectionPeriod ();
- void setGarbageCollectionPeriod (int);
-
- // backwards compatibility
-
- public boolean requiresWOF35RequestHandling ();
- public boolean requiresWOF35TemplateParser ();
-
- public void setPrintsHTMLParserDiagnostics (boolean);
- public boolean printsHTMLParserDiagnostics ();
-
- // configuration and defaults
-
- public static NSArray loadFrameworks ();
- public static void setLoadFrameworks (NSArray);
-*/
- static boolean debuggingEnabled = false;
- /**
- * Returns whether the application is in "debug mode".
- */
- public static boolean isDebuggingEnabled()
- {
- return debuggingEnabled;
- }
-
- /**
- * Sets whether the application is in "debug mode".
- */
- public static void setDebuggingEnabled( boolean enabled )
- {
- debuggingEnabled = enabled;
- }
-
- /**
- * Sets whether templates are cached. If true, templates will
- * only be read once per application lifetime. Otherwise, templates
- * will be read each time this class is instantiated. Defaults to false.
- */
- public static void setCachingEnabled (boolean enabled)
- {
+ /**
+ * Returns a class in the same package as the Application class, or, failing
+ * that, from the WOApplication package, or finally from the root of the class
+ * path. Returns null if not found.
+ */
+ Class getLocalClass(String aName) {
+ Class result = null;
+ if (getClass() != WOApplication.class) {
+ result = loadLocalClass(getClass(), aName);
+ }
+ if (result == null) {
+ result = loadLocalClass(WOApplication.class, aName);
+ }
+ if (result == null) {
+ result = loadLocalClass(null, aName);
+ }
+ return result;
+ }
+
+ private static final Class loadLocalClass(Class aClass, String aName) {
+ ClassLoader loader;
+ String packageName = "";
+ if (aClass != null) {
+ loader = aClass.getClassLoader();
+ packageName = aClass.getName();
+ int index = packageName.lastIndexOf(".");
+ if (index > -1) {
+ packageName = packageName.substring(0, index + 1);
+ } else {
+ packageName = "";
+ }
+ } else {
+ loader = WOApplication.class.getClassLoader();
+ }
+
+ try {
+ return loader.loadClass(packageName + aName);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ // creating elements
+
+ /**
+ * Returns either a dynamic element or a component for the specified name.
+ */
+ public WOElement dynamicElementWithName(String anElementName, NSDictionary anAssociationMap, WOElement aBodyElement,
+ List aLanguageList) {
+ WOElement element = null;
+ Class c = null;
+ try {
+ c = getLocalClass(anElementName);
+ if (c == null) {
+ System.out.println("Not found: dynamicElementWithName: " + "could not find WODynamicElement subclass: "
+ + anElementName);
+ c = WODynamicElement.class;
+ }
+
+ // get constructor
+ Class[] params = new Class[] { String.class, NSDictionary.class, WOElement.class };
+ Constructor ctor = c.getConstructor(params);
+
+ // create instance of class
+ if (ctor != null) {
+ element = (WODynamicElement) ctor
+ .newInstance(new Object[] { anElementName, anAssociationMap, aBodyElement });
+ }
+ } catch (Throwable t) {
+ // ignore: not a dynamic element
+ // System.out.println( "Not a dynamic element: dynamicElementWithName: " + t );
+ // exc.printStackTrace();
+ }
+
+ // no dynamic element found: look for a component
+ if (element == null) {
+ WOComponent component = (WOComponent) pageWithName(anElementName, (WOContext) null);
+
+ // this seems hackish:
+ // I don't see another way of setting the bindings.
+ component.associations = anAssociationMap;
+ component.rootElement = aBodyElement;
+
+ element = component;
+ }
+
+ return element;
+ }
+
+ // resource handling
+
+ /**
+ * Called to create the application's resource manager. Override to create a
+ * custom resource manager.
+ */
+ public WOResourceManager createResourceManager() {
+ return new WOResourceManager();
+ }
+
+ /**
+ * Returns the application's current resource manager.
+ */
+ public WOResourceManager resourceManager() {
+ return resourceManager;
+ }
+
+ /**
+ * Installs a custom resource manager into the current application.
+ *
+ * @deprecated Override createResourceManager() instead.
+ */
+ public void setResourceManager(WOResourceManager aResourceManager) {
+ resourceManager = aResourceManager;
+ }
+
+ /*
+ * // request handling undocumented
+ *
+ * public WOComponent pageWithName (String); public void savePage (WOComponent);
+ * public WOComponent restorePageForContextID (String); public WOContext context
+ * (); public WOSession session (); public WOSession createSession (); public
+ * WOSession restoreSession (); public void saveSession (WOSession);
+ *
+ * public WOResponse handleRequest (WORequest aRequest) { }
+ *
+ * // error handling undocumented
+ *
+ * WOResponse handleSessionCreationError (); WOResponse
+ * handleSessionRestorationError (); WOResponse handlePageRestorationError ();
+ * WOResponse handleException (Throwable);
+ *
+ * // running
+ *
+ * public NSRunLoop runLoop (); public void run (); public void setTimeOut
+ * (double); public double timeOut (); public void terminate (); public boolean
+ * isTerminating ();
+ *
+ * // script debugging
+ *
+ * public void traceScriptedMessages (boolean); public void traceAssignments
+ * (boolean); public void traceStatements (boolean); public void
+ * traceObjectiveCMessages (boolean); public void trace (boolean); public void
+ * logTakeValueForDeclarationNamed (String, String, String, String, Object);
+ * public void logSetValueForDeclarationNamed (String, String, String, String,
+ * Object);
+ *
+ * // script handling
+ *
+ * public String scriptedClassNameWithPath (String); public String
+ * scriptedClassNameWithPathEncoding (String, int);
+ *
+ * // statistics report
+ *
+ * public void setStatisticsStore (WOStatisticsStore); public WOStatisticsStore
+ * statisticsStore (); public NSDictionary statistics ();
+ *
+ * // managing adaptors
+ *
+ * public WOAdaptor adaptorWithName (String, NSDictionary); public NSArray
+ * adaptors ();
+ *
+ * // monitor support
+ *
+ * public boolean monitoringEnabled (); public int activeSessionsCount ();
+ * public void refuseNewSessions (boolean); public boolean isRefusingNewSessions
+ * (); public void setMinimumActiveSessionsCount (int); public int
+ * minimumActiveSessionsCount (); public void terminateAfterTimeInterval
+ * (double);
+ *
+ * // garbage collection undocumented
+ *
+ * int garbageCollectionPeriod (); void setGarbageCollectionPeriod (int);
+ *
+ * // backwards compatibility
+ *
+ * public boolean requiresWOF35RequestHandling (); public boolean
+ * requiresWOF35TemplateParser ();
+ *
+ * public void setPrintsHTMLParserDiagnostics (boolean); public boolean
+ * printsHTMLParserDiagnostics ();
+ *
+ * // configuration and defaults
+ *
+ * public static NSArray loadFrameworks (); public static void setLoadFrameworks
+ * (NSArray);
+ */
+ static boolean debuggingEnabled = false;
+
+ /**
+ * Returns whether the application is in "debug mode".
+ */
+ public static boolean isDebuggingEnabled() {
+ return debuggingEnabled;
+ }
+
+ /**
+ * Sets whether the application is in "debug mode".
+ */
+ public static void setDebuggingEnabled(boolean enabled) {
+ debuggingEnabled = enabled;
+ }
+
+ /**
+ * Sets whether templates are cached. If true, templates will only be read once
+ * per application lifetime. Otherwise, templates will be read each time this
+ * class is instantiated. Defaults to false.
+ */
+ public static void setCachingEnabled(boolean enabled) {
cachingEnabled = enabled;
}
- /**
- * Returns whether templates are cached. If true, templates are
- * read once per application lifetime. Otherwise, templates are
- * read each time this class is instantiated.
- */
- public static boolean isCachingEnabled ()
- {
- return cachingEnabled;
- }
-
- // configuration
-
- /**
- * Returns the component request handler key,
- * which is defined by the system property _ComponentRequestHandlerKey.
- * The default is "wo".
- */
- public static String componentRequestHandlerKey()
- {
- return System.getProperty( _ComponentRequestHandlerKey, "wo" );
- }
-
- /**
- * Sets the component request handler key.
- * @deprecated Set the system property _ComponentRequestHandlerKey.
- */
- public static void setComponentRequestHandlerKey(String aKey)
- {
- System.setProperty( _ComponentRequestHandlerKey, aKey );
- }
-
- /**
- * Returns the direct action request handler key,
- * which is defined by the system property _DirectActionRequestHandlerKey.
- * The default is "wa".
- */
- public static String directActionRequestHandlerKey()
- {
- return System.getProperty( _DirectActionRequestHandlerKey, "wa" );
- }
-
- /**
- * Sets the direct action request handler key.
- * @deprecated Set the system property _DirectActionRequestHandlerKey.
- */
- public static void setDirectActionRequestHandlerKey(String aKey)
- {
- System.setProperty( _DirectActionRequestHandlerKey, aKey );
- }
-
- /**
- * Returns the resource request handler key,
- * which is defined by the system property _ResourceRequestHandlerKey.
- * The default is "wr".
- */
- public static String resourceRequestHandlerKey()
- {
- return System.getProperty( _ResourceRequestHandlerKey, "wr" );
- }
-
- /**
- * Sets the resource request handler key.
- * @deprecated Set the system property _ResourceRequestHandlerKey.
- */
- public static void setResourceRequestHandlerKey(String aKey)
- {
- System.setProperty( _ResourceRequestHandlerKey, aKey );
- }
-
- /**
- * Returns whether this application should attempt to open
- * a web browser on the host machine when launched standalone.
- * The default is true.
- */
- public static boolean autoOpenInBrowser()
- {
- return autoOpenInBrowser;
- }
-
- /**
- * Sets whether this application should attempt to open
- * a web browser on the host machine when launched standalone.
- */
- public static void setAutoOpenInBrowser(boolean autoOpen)
- {
- autoOpenInBrowser = autoOpen;
- }
-
- /**
- * Gets the port used when run as a standalone server.
- * Returns the value of the system property WOPort.
- * By default, this is zero, which causes the application
- * to automatically select an available port.
- */
- public static Number port ()
- {
- return Integer.getInteger( WOPort, 0 );
- }
-
- /**
- * Gets the smtp server that will be used to send email.
- * Returns the system property WOSMTPHost.
- */
- public static String SMTPHost()
- {
- return System.getProperty( WOSMTPHost );
- }
-
- /**
- * Sets the smtp server that will be used to send email.
- * @deprecated Set the system property WOSMTPHost.
- */
- public static void setSMTPHost( String aHost )
- {
- System.setProperty( WOSMTPHost, aHost );
- }
-/*
- public static boolean isDirectConnectEnabled ();
- public static void setDirectConnectEnabled (boolean);
- public static String cgiAdaptorURL ();
- public static void setCGIAdaptorURL (String);
- public static String applicationBaseURL ();
- public static void setApplicationBaseURL (String);
- public static String frameworksBaseURL ();
- public static void setFrameworksBaseURL (String);
- public static String recordingPath ();
- public static void setRecordingPath (String);
- public static NSArray projectSearchPath ();
- public static void setProjectSearchPath (NSArray);
- public static boolean isMonitorEnabled ();
- public static void setMonitorEnabled (boolean);
- public static String monitorHost ();
- public static String adaptor ();
- public String number (); // deprecated
- public static Number listenQueueSize ();
- public static void setListenQueueSize (Number);
- public static NSArray additionalAdaptors ();
- public static void setAdditionalAdaptors (NSArray);
- public static boolean includeCommentsInResponses ();
- public static void setIncludeCommentsInResponses (boolean);
- public static void setSessionTimeOut (Number);
- public static Number sessionTimeOut ();
- public static void logString (String);
- public static void debugString (String);
- public static void logToMonitorString (String);
-*/
+ /**
+ * Returns whether templates are cached. If true, templates are read once per
+ * application lifetime. Otherwise, templates are read each time this class is
+ * instantiated.
+ */
+ public static boolean isCachingEnabled() {
+ return cachingEnabled;
+ }
+
+ // configuration
+
+ /**
+ * Returns the component request handler key, which is defined by the system
+ * property _ComponentRequestHandlerKey. The default is "wo".
+ */
+ public static String componentRequestHandlerKey() {
+ return System.getProperty(_ComponentRequestHandlerKey, "wo");
+ }
+
+ /**
+ * Sets the component request handler key.
+ *
+ * @deprecated Set the system property _ComponentRequestHandlerKey.
+ */
+ public static void setComponentRequestHandlerKey(String aKey) {
+ System.setProperty(_ComponentRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns the direct action request handler key, which is defined by the system
+ * property _DirectActionRequestHandlerKey. The default is "wa".
+ */
+ public static String directActionRequestHandlerKey() {
+ return System.getProperty(_DirectActionRequestHandlerKey, "wa");
+ }
+
+ /**
+ * Sets the direct action request handler key.
+ *
+ * @deprecated Set the system property _DirectActionRequestHandlerKey.
+ */
+ public static void setDirectActionRequestHandlerKey(String aKey) {
+ System.setProperty(_DirectActionRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns the resource request handler key, which is defined by the system
+ * property _ResourceRequestHandlerKey. The default is "wr".
+ */
+ public static String resourceRequestHandlerKey() {
+ return System.getProperty(_ResourceRequestHandlerKey, "wr");
+ }
- /**
- * Main entry point for applications that do not subclass WOApplication.
- */
- public static void main( String[] argv )
- {
- main( argv, WOApplication.class );
- }
-
- /**
- * Subclasses may call this method to start a self-hosted
- * web server to serve themselves directly (for testing).
- */
- public static void main( String[] argv, Class subclass )
- {
- try
- {
- int port = 0;
- boolean open = false;
- try
- {
- port = ((Number)subclass.getMethod( "port",
- new Class[0]).invoke(subclass,new Object[0])).intValue();
- open = ((Boolean)subclass.getMethod( "autoOpenInBrowser",
- new Class[0]).invoke(subclass,new Object[0])).booleanValue();
- }
- catch ( Throwable t )
- {
- System.err.print("Error reading configuration:" );
- t.printStackTrace();
- }
-
- HttpServer server = new HttpServer();
- HttpListener listener = server.addListener(new InetAddrPort(port));
- org.mortbay.http.HttpContext context = server.getContext("/");
- ServletHandler handler = new ServletHandler();
- handler.addServlet("/",subclass.getName());
- context.addHandler(handler);
- server.start();
- port = listener.getPort();
- System.out.println("Waiting for requests: http://127.0.0.1:" + port);
- if ( open )
- {
- BrowserLauncher.openURL( "http://127.0.0.1:" + port );
- }
- }
- catch ( Throwable t )
- {
- t.printStackTrace();
- }
- }
+ /**
+ * Sets the resource request handler key.
+ *
+ * @deprecated Set the system property _ResourceRequestHandlerKey.
+ */
+ public static void setResourceRequestHandlerKey(String aKey) {
+ System.setProperty(_ResourceRequestHandlerKey, aKey);
+ }
+
+ /**
+ * Returns whether this application should attempt to open a web browser on the
+ * host machine when launched standalone. The default is true.
+ */
+ public static boolean autoOpenInBrowser() {
+ return autoOpenInBrowser;
+ }
+
+ /**
+ * Sets whether this application should attempt to open a web browser on the
+ * host machine when launched standalone.
+ */
+ public static void setAutoOpenInBrowser(boolean autoOpen) {
+ autoOpenInBrowser = autoOpen;
+ }
+
+ /**
+ * Gets the port used when run as a standalone server. Returns the value of the
+ * system property WOPort. By default, this is zero, which causes the
+ * application to automatically select an available port.
+ */
+ public static Number port() {
+ return Integer.getInteger(WOPort, 0);
+ }
+
+ /**
+ * Gets the smtp server that will be used to send email. Returns the system
+ * property WOSMTPHost.
+ */
+ public static String SMTPHost() {
+ return System.getProperty(WOSMTPHost);
+ }
+
+ /**
+ * Sets the smtp server that will be used to send email.
+ *
+ * @deprecated Set the system property WOSMTPHost.
+ */
+ public static void setSMTPHost(String aHost) {
+ System.setProperty(WOSMTPHost, aHost);
+ }
+ /*
+ * public static boolean isDirectConnectEnabled (); public static void
+ * setDirectConnectEnabled (boolean); public static String cgiAdaptorURL ();
+ * public static void setCGIAdaptorURL (String); public static String
+ * applicationBaseURL (); public static void setApplicationBaseURL (String);
+ * public static String frameworksBaseURL (); public static void
+ * setFrameworksBaseURL (String); public static String recordingPath (); public
+ * static void setRecordingPath (String); public static NSArray
+ * projectSearchPath (); public static void setProjectSearchPath (NSArray);
+ * public static boolean isMonitorEnabled (); public static void
+ * setMonitorEnabled (boolean); public static String monitorHost (); public
+ * static String adaptor (); public String number (); // deprecated public
+ * static Number listenQueueSize (); public static void setListenQueueSize
+ * (Number); public static NSArray additionalAdaptors (); public static void
+ * setAdditionalAdaptors (NSArray); public static boolean
+ * includeCommentsInResponses (); public static void
+ * setIncludeCommentsInResponses (boolean); public static void setSessionTimeOut
+ * (Number); public static Number sessionTimeOut (); public static void
+ * logString (String); public static void debugString (String); public static
+ * void logToMonitorString (String);
+ */
+
+ /**
+ * Main entry point for applications that do not subclass WOApplication.
+ */
+ public static void main(String[] argv) {
+ main(argv, WOApplication.class);
+ }
+
+ /**
+ * Subclasses may call this method to start a self-hosted web server to serve
+ * themselves directly (for testing).
+ */
+ public static void main(String[] argv, Class subclass) {
+ try {
+ int port = 0;
+ boolean open = false;
+ try {
+ port = ((Number) subclass.getMethod("port", new Class[0]).invoke(subclass, new Object[0])).intValue();
+ open = ((Boolean) subclass.getMethod("autoOpenInBrowser", new Class[0]).invoke(subclass, new Object[0]))
+ .booleanValue();
+ } catch (Throwable t) {
+ System.err.print("Error reading configuration:");
+ t.printStackTrace();
+ }
+
+ HttpServer server = new HttpServer();
+ HttpListener listener = server.addListener(new InetAddrPort(port));
+ org.mortbay.http.HttpContext context = server.getContext("/");
+ ServletHandler handler = new ServletHandler();
+ handler.addServlet("/", subclass.getName());
+ context.addHandler(handler);
+ server.start();
+ port = listener.getPort();
+ System.out.println("Waiting for requests: http://127.0.0.1:" + port);
+ if (open) {
+ BrowserLauncher.openURL("http://127.0.0.1:" + port);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.30 2003/03/28 18:01:19 mpowers
- * Now defaulting port to zero.
+ * Revision 1.30 2003/03/28 18:01:19 mpowers Now defaulting port to zero.
*
- * Revision 1.29 2003/03/28 17:31:58 mpowers
- * Implemented support for autoselection of free port. (thanks gmuth!)
+ * Revision 1.29 2003/03/28 17:31:58 mpowers Implemented support for
+ * autoselection of free port. (thanks gmuth!)
*
- * Revision 1.28 2003/03/28 17:26:17 mpowers
- * Implemented package support: Applications can now live in packages.
- * Better support for locating package local classes.
+ * Revision 1.28 2003/03/28 17:26:17 mpowers Implemented package support:
+ * Applications can now live in packages. Better support for locating package
+ * local classes.
*
- * Revision 1.27 2003/02/21 16:40:22 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.27 2003/02/21 16:40:22 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.26 2003/02/14 22:33:18 mpowers
- * Better handling for standalone mode.
+ * Revision 1.26 2003/02/14 22:33:18 mpowers Better handling for standalone
+ * mode.
*
- * Revision 1.25 2003/02/14 15:18:27 mpowers
- * Now launching standalone app as a servlet, not a webapp.
- * Disabled jetty's event logging.
+ * Revision 1.25 2003/02/14 15:18:27 mpowers Now launching standalone app as a
+ * servlet, not a webapp. Disabled jetty's event logging.
*
- * Revision 1.24 2003/02/13 22:41:04 mpowers
- * WOApplications can now be self-serving. Added configuration params too.
+ * Revision 1.24 2003/02/13 22:41:04 mpowers WOApplications can now be
+ * self-serving. Added configuration params too.
*
- * Revision 1.23 2003/01/28 19:33:51 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.23 2003/01/28 19:33:51 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.22 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.22 2003/01/27 15:08:00 mpowers Implemented WOResourceManager,
+ * using java resources for now.
*
- * Revision 1.21 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.21 2003/01/24 20:13:22 mpowers Now accepting immutable
+ * NSDictionary in constructor, not Map.
*
- * Revision 1.20 2003/01/20 17:50:11 mpowers
- * Caught a loop condition when same declaration was used twice.
+ * Revision 1.20 2003/01/20 17:50:11 mpowers Caught a loop condition when same
+ * declaration was used twice.
*
- * Revision 1.19 2003/01/19 22:33:25 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.19 2003/01/19 22:33:25 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.18 2003/01/18 23:54:50 mpowers
- * Implemented debugging enabled.
+ * Revision 1.18 2003/01/18 23:54:50 mpowers Implemented debugging enabled.
*
- * Revision 1.17 2003/01/17 20:58:18 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.17 2003/01/17 20:58:18 mpowers Fixed up WOHyperlink.
*
- * Revision 1.16 2003/01/17 20:34:17 mpowers
- * Rudimentary support for resource requests.
+ * Revision 1.16 2003/01/17 20:34:17 mpowers Rudimentary support for resource
+ * requests.
*
- * Revision 1.15 2003/01/17 15:31:56 mpowers
- * Removed spurious error message.
+ * Revision 1.15 2003/01/17 15:31:56 mpowers Removed spurious error message.
*
- * Revision 1.14 2003/01/17 14:39:00 mpowers
- * Now calling preferred constructor: WOComponent(WOContext)
+ * Revision 1.14 2003/01/17 14:39:00 mpowers Now calling preferred constructor:
+ * WOComponent(WOContext)
*
- * Revision 1.13 2003/01/16 20:10:46 mpowers
- * - components now synchronize bindings
- * - support for WOComponentContent
- * - implemented performParentAction
+ * Revision 1.13 2003/01/16 20:10:46 mpowers - components now synchronize
+ * bindings - support for WOComponentContent - implemented performParentAction
*
- * Revision 1.12 2003/01/16 15:50:43 mpowers
- * More robust declaration parsing.
- * Subcomponents are now supported.
- * dynamicElementWithName can now return subcomponents.
+ * Revision 1.12 2003/01/16 15:50:43 mpowers More robust declaration parsing.
+ * Subcomponents are now supported. dynamicElementWithName can now return
+ * subcomponents.
*
- * Revision 1.11 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.11 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.10 2003/01/13 22:24:18 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.10 2003/01/13 22:24:18 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.9 2003/01/10 20:17:41 mpowers
- * Component action urls are now working.
+ * Revision 1.9 2003/01/10 20:17:41 mpowers Component action urls are now
+ * working.
*
- * Revision 1.8 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.8 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.4 2002/12/19 17:58:52 mpowers
- * Rewrote the template parsing - no longer confused about "root element".
+ * Revision 1.4 2002/12/19 17:58:52 mpowers Rewrote the template parsing - no
+ * longer confused about "root element".
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/12/17 14:57:41 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:41 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
index 608f9fa..89623a6 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOAssociation.java
@@ -19,150 +19,138 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* A pure java implementation of WOAssociation. <br><br>
-*
-* A WOAssociation represents the mapping of a property on a
-* WOComponent to a property on a WOAssociation. For example: <br><br>
-*
-* MyAssociation: WOString { value = currentCustomer.location.city }; <br><br>
-*
-* This example represents a WOAssociation between the value field
-* on a WOString element and the city property of the location property
-* of the currentCustomer property of a WOComponent. <br><br>
-*
-* To resolve values, a property accessor method will be used in
-* preference to a public field, if both exist. Any null value
-* in the path will produce null. <br><br>
-*
-* A mapping represented in quotation marks: { value = "This is a test." }
-* is considered a constant value.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public class WOAssociation implements java.io.Serializable
-{
+ * A pure java implementation of WOAssociation. <br>
+ * <br>
+ *
+ * A WOAssociation represents the mapping of a property on a WOComponent to a
+ * property on a WOAssociation. For example: <br>
+ * <br>
+ *
+ * MyAssociation: WOString { value = currentCustomer.location.city }; <br>
+ * <br>
+ *
+ * This example represents a WOAssociation between the value field on a WOString
+ * element and the city property of the location property of the currentCustomer
+ * property of a WOComponent. <br>
+ * <br>
+ *
+ * To resolve values, a property accessor method will be used in preference to a
+ * public field, if both exist. Any null value in the path will produce null.
+ * <br>
+ * <br>
+ *
+ * A mapping represented in quotation marks: { value = "This is a test." } is
+ * considered a constant value.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public class WOAssociation implements java.io.Serializable {
protected Object value;
protected String path;
-
+
+ /**
+ * The default constructor. The static factory methods should be used to create
+ * instances of WOAssociation.
+ */
+ protected WOAssociation() {
+ value = null;
+ path = null;
+ }
+
/**
- * The default constructor. The static factory methods should
- * be used to create instances of WOAssociation.
- */
- protected WOAssociation ()
- {
- value = null;
- path = null;
- }
+ * Creates a WOAssociation that maps to a constant value.
+ */
+ public static WOAssociation associationWithValue(Object anObject) {
+ WOAssociation result = new WOAssociation();
+ result.value = anObject;
+ return result;
+ }
/**
- * Creates a WOAssociation that maps to a constant value.
- */
- public static WOAssociation associationWithValue (Object anObject)
- {
- WOAssociation result = new WOAssociation();
- result.value = anObject;
- return result;
- }
-
- /**
- * Creates a WOAssociation that maps to the specified key path.
- * If the path is null, the association will map to null.
- * Throws an exception if the property cannot be resolved.
- */
- public static WOAssociation associationWithKeyPath (String aString)
- {
- WOAssociation result = new WOAssociation();
- result.path = aString;
- return result;
- }
+ * Creates a WOAssociation that maps to the specified key path. If the path is
+ * null, the association will map to null. Throws an exception if the property
+ * cannot be resolved.
+ */
+ public static WOAssociation associationWithKeyPath(String aString) {
+ WOAssociation result = new WOAssociation();
+ result.path = aString;
+ return result;
+ }
/**
- * Returns the value for this association's key path in the
- * specified component, or null if any value in the path is
- * null or if the key path is null.
- */
- public Object valueInComponent (WOComponent aComponent)
- {
- if ( aComponent == null ) return null;
- if ( value != null ) return value;
- if ( path != null ) return aComponent.valueForKey( path );
- throw new RuntimeException(
- "WOAssociation: neither value nor path specified!" );
- }
-
- /**
- * Sets the property in the specified component to the specified value.
- * Throws an exception if the property cannot be resolved.
- */
- public void setValue (Object aValue, WOComponent aComponent)
- {
- if ( path != null )
- {
- aComponent.takeValueForKey( aValue, path );
+ * Returns the value for this association's key path in the specified component,
+ * or null if any value in the path is null or if the key path is null.
+ */
+ public Object valueInComponent(WOComponent aComponent) {
+ if (aComponent == null)
+ return null;
+ if (value != null)
+ return value;
+ if (path != null)
+ return aComponent.valueForKey(path);
+ throw new RuntimeException("WOAssociation: neither value nor path specified!");
+ }
+
+ /**
+ * Sets the property in the specified component to the specified value. Throws
+ * an exception if the property cannot be resolved.
+ */
+ public void setValue(Object aValue, WOComponent aComponent) {
+ if (path != null) {
+ aComponent.takeValueForKey(aValue, path);
return;
}
- throw new RuntimeException(
- "WOAssociation: tried to set value but no path was specified!" );
+ throw new RuntimeException("WOAssociation: tried to set value but no path was specified!");
+ }
+
+ /**
+ * Returns true if this association is writable; that is, returns true if this
+ * association is not constant.
+ */
+ public boolean isValueSettable() {
+ return (path != null);
}
/**
- * Returns true if this association is writable; that is,
- * returns true if this association is not constant.
- */
- public boolean isValueSettable ()
- {
- return ( path != null );
- }
-
- /**
- * Returns true if this association is constant
- * and therefore read-only.
- */
- public boolean isValueConstant ()
- {
- return ( path == null );
- }
-
- /**
- * For debugging purposes.
- */
- public String toString()
- {
- if ( path != null )
- {
- return "[WOAssociation:" + path + "]";
- }
- return "[WOAssociation:\"" + value + "\"]";
- }
-}
+ * Returns true if this association is constant and therefore read-only.
+ */
+ public boolean isValueConstant() {
+ return (path == null);
+ }
+
+ /**
+ * For debugging purposes.
+ */
+ public String toString() {
+ if (path != null) {
+ return "[WOAssociation:" + path + "]";
+ }
+ return "[WOAssociation:\"" + value + "\"]";
+ }
+}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.6 2003/01/24 20:13:22 mpowers Now accepting immutable NSDictionary
+ * in constructor, not Map.
*
- * Revision 1.5 2003/01/17 22:55:08 mpowers
- * Straighted out the parent binding issue (I think).
- * Fixes for woextensions compatibility.
+ * Revision 1.5 2003/01/17 22:55:08 mpowers Straighted out the parent binding
+ * issue (I think). Fixes for woextensions compatibility.
*
- * Revision 1.3 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.3 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.2 2003/01/14 15:51:48 mpowers
- * Removed value() method from WOAssociaton.
+ * Revision 1.2 2003/01/14 15:51:48 mpowers Removed value() method from
+ * WOAssociaton.
*
- * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
index 9f0707d..131d223 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOBody.java
@@ -23,99 +23,91 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOBody represents a page's "body" tag and is used to dynamically
-* set the background image for a page, and therefore works much like WOImage.
-*
-* Bindings are:
-* <UL>
-* <li>src: A static URL for the image source.</li>
-* <li>data: A NSData object with the image content. Must be used with mimeType.</li>
-* <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
-* <li>filename: The path to a file containing an image.</li>
-* <li>framework: The optional framework from whence the image should be retrieved (used in conjunction with filename).</li>
-* <li>key: A key under which this resource will be cached for repeated access.</li>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * WOBody represents a page's "body" tag and is used to dynamically set the
+ * background image for a page, and therefore works much like WOImage.
+ *
+ * Bindings are:
+ * <UL>
+ * <li>src: A static URL for the image source.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
+ * <li>filename: The path to a file containing an image.</li>
+ * <li>framework: The optional framework from whence the image should be
+ * retrieved (used in conjunction with filename).</li>
+ * <li>key: A key under which this resource will be cached for repeated
+ * access.</li>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOBody extends WOImage {
- protected String src;
- protected String filename;
- protected String framework;
- protected NSData data;
- protected String mimeType;
+ protected String src;
+ protected String filename;
+ protected String framework;
+ protected NSData data;
+ protected String mimeType;
- protected WOBody() {
- super();
- }
+ protected WOBody() {
+ super();
+ }
- public WOBody(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
+ public WOBody(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.ensureAwakeInContext( aContext );
- }
- }
+ void ensureAwakeInContext(WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.ensureAwakeInContext(aContext);
+ }
+ }
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- return rootElement.invokeAction( aRequest, aContext );
- }
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c)
- {
- r.appendContentString("<body background=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- if ( rootElement != null )
- {
- rootElement.appendToResponse( r, c );
- }
- r.appendContentString("</body>");
- }
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ return rootElement.invokeAction(aRequest, aContext);
+ }
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<body background=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ if (rootElement != null) {
+ rootElement.appendToResponse(r, c);
+ }
+ r.appendContentString("</body>");
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.4 2003/08/07 00:15:14 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.4 2003/08/07 00:15:14 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.3 2003/01/27 15:57:28 mpowers
- * Now participates in all parts of request/response cycle.
+ * Revision 1.3 2003/01/27 15:57:28 mpowers Now participates in all parts of
+ * request/response cycle.
*
- * Revision 1.2 2003/01/27 15:08:23 mpowers
- * Now appending to response.
+ * Revision 1.2 2003/01/27 15:08:23 mpowers Now appending to response.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
index 5d22d36..8e706c1 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCheckBox.java
@@ -7,75 +7,75 @@ import net.wotonomy.foundation.NSMutableArray;
public class WOCheckBox extends WOInput {
- protected boolean checked = false;
+ protected boolean checked = false;
- public WOCheckBox() {
- super();
- }
+ public WOCheckBox() {
+ super();
+ }
- public WOCheckBox(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOCheckBox(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "CHECKBOX";
- }
+ protected String inputType() {
+ return "CHECKBOX";
+ }
- protected Object value(WOContext c) {
- Object val = null;
- boolean checked = false;
- if (associations.objectForKey("value") != null) {
- val = valueForProperty("value", c.component());
- Object sel = valueForProperty("selection", c.component());
- if (sel != null && val != null && sel.equals(val))
- checked = true;
- }
- if (val == null) {
- val = c.elementID();
- }
- return val;
- }
+ protected Object value(WOContext c) {
+ Object val = null;
+ boolean checked = false;
+ if (associations.objectForKey("value") != null) {
+ val = valueForProperty("value", c.component());
+ Object sel = valueForProperty("selection", c.component());
+ if (sel != null && val != null && sel.equals(val))
+ checked = true;
+ }
+ if (val == null) {
+ val = c.elementID();
+ }
+ return val;
+ }
- protected void appendExtras(WOResponse r, WOContext c) {
- checked |= booleanForProperty("checked", c.component());
- if (checked)
- r.appendContentString(" CHECKED");
- }
+ protected void appendExtras(WOResponse r, WOContext c) {
+ checked |= booleanForProperty("checked", c.component());
+ if (checked)
+ r.appendContentString(" CHECKED");
+ }
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.addObject("checked");
- a.addObject("selection");
- return a;
- }
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.addObject("checked");
+ a.addObject("selection");
+ return a;
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- checked = false;
- super.appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ checked = false;
+ super.appendToResponse(r, c);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if (disabled(c))
- return;
- NSArray values = r.formValuesForKey(inputName(c));
- Object val = valueForProperty("value", c.component());
- if (val == null)
- val = c.elementID();
- java.util.Enumeration enumerator = values.objectEnumerator();
- checked = false;
- while (enumerator.hasMoreElements()) {
- Object nextval = enumerator.nextElement();
- if (nextval.equals(val))
- checked = true;
- }
- if (associations.objectForKey("value") != null && associations.objectForKey("selection") != null) {
- if (checked)
- setValueForProperty("selection", val, c.component());
- else if (valueForProperty("selection", c.component()) != null)
- setValueForProperty("selection", null, c.component());
- }
- if (associations.objectForKey("checked") != null)
- setValueForProperty("checked", checked ? Boolean.TRUE : Boolean.FALSE, c.component());
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (disabled(c))
+ return;
+ NSArray values = r.formValuesForKey(inputName(c));
+ Object val = valueForProperty("value", c.component());
+ if (val == null)
+ val = c.elementID();
+ java.util.Enumeration enumerator = values.objectEnumerator();
+ checked = false;
+ while (enumerator.hasMoreElements()) {
+ Object nextval = enumerator.nextElement();
+ if (nextval.equals(val))
+ checked = true;
+ }
+ if (associations.objectForKey("value") != null && associations.objectForKey("selection") != null) {
+ if (checked)
+ setValueForProperty("selection", val, c.component());
+ else if (valueForProperty("selection", c.component()) != null)
+ setValueForProperty("selection", null, c.component());
+ }
+ if (associations.objectForKey("checked") != null)
+ setValueForProperty("checked", checked ? Boolean.TRUE : Boolean.FALSE, c.component());
+ }
} \ No newline at end of file
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
index 20d8b0a..c99768c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponent.java
@@ -42,1271 +42,1037 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.NSSelector;
/**
-* Pure java implementation of WOComponent.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOComponent
- extends WOElement
- implements WOActionResults,
- net.wotonomy.control.EOKeyValueCodingAdditions,
- net.wotonomy.control.EOKeyValueCoding
-{
+ * Pure java implementation of WOComponent.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOComponent extends WOElement implements WOActionResults, net.wotonomy.control.EOKeyValueCodingAdditions,
+ net.wotonomy.control.EOKeyValueCoding {
WOElement rootElement;
-
- private static final String DIRECTORY_SUFFIX = ".wo";
- private static final String TEMPLATE_SUFFIX = ".html";
- private static final String DECLARATION_SUFFIX = ".wod";
-
- private static final String OPEN_TAG = "webobject";
- private static final String CLOSE_TAG = "/webobject";
- private static final String NAME_KEY = "name";
-
- protected transient WOContext context; // don't persist
- protected boolean cachingEnabled;
- protected WOElement template;
- protected WOComponent parent;
+
+ private static final String DIRECTORY_SUFFIX = ".wo";
+ private static final String TEMPLATE_SUFFIX = ".html";
+ private static final String DECLARATION_SUFFIX = ".wod";
+
+ private static final String OPEN_TAG = "webobject";
+ private static final String CLOSE_TAG = "/webobject";
+ private static final String NAME_KEY = "name";
+
+ protected transient WOContext context; // don't persist
+ protected boolean cachingEnabled;
+ protected WOElement template;
+ protected WOComponent parent;
+
+ /**
+ * Default constructor. Deprecated in latest spec.
+ */
+ public WOComponent() {
+ parent = null;
+ cachingEnabled = true;
+ template = null;
+ }
+
+ /**
+ * Constructor specifying a context.
+ */
+ public WOComponent(WOContext aContext) {
+ this();
+ context = aContext;
+ }
+
+ /**
+ * Returns the name of the component, which is usually just the class name.
+ */
+ public String name() {
+ return justTheClassName();
+ }
/**
- * Default constructor. Deprecated in latest spec.
- */
- public WOComponent ()
- {
- parent = null;
- cachingEnabled = true;
- template = null;
- }
-
- /**
- * Constructor specifying a context.
- */
- public WOComponent( WOContext aContext )
- {
- this();
- context = aContext;
- }
-
+ * Returns the system-dependent file path to the current component directory,
+ * including the ".wo" extension.
+ */
+ public String path() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
/**
- * Returns the name of the component, which is usually just the class name.
- */
- public String name ()
- {
- return justTheClassName();
- }
-
- /**
- * Returns the system-dependent file path to the current component
- * directory, including the ".wo" extension.
- */
- public String path ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Returns the URL for this component, relative to the server's document root on
+ * the server's file system. This is not an http url.
+ */
+ public String baseURL() {
+ throw new RuntimeException("Not implemented yet.");
+ }
/**
- * Returns the URL for this component, relative to the server's
- * document root on the server's file system.
- * This is not an http url.
- */
- public String baseURL ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Returns the name of the framework that contains this component, or null if
+ * the component does not belong to a framework. This currently returns the
+ * package path of the class, or null if it does not belong to a package.
+ */
+ public String frameworkName() {
+ return justTheResourcePath();
+ }
/**
- * Returns the name of the framework that contains this component,
- * or null if the component does not belong to a framework.
- * This currently returns the package path of the class, or
- * null if it does not belong to a package.
- */
- public String frameworkName ()
- {
- return justTheResourcePath();
- }
-
- /**
- * Sets whether templates are cached. If true, templates will
- * only be read once per application lifetime. Otherwise, templates
- * will be read each time this class is instantiated. Defaults to false.
- */
- public void setCachingEnabled (boolean enabled)
- {
+ * Sets whether templates are cached. If true, templates will only be read once
+ * per application lifetime. Otherwise, templates will be read each time this
+ * class is instantiated. Defaults to false.
+ */
+ public void setCachingEnabled(boolean enabled) {
cachingEnabled = enabled;
}
- /**
- * Returns whether templates are cached. If true, templates are
- * read once per application lifetime. Otherwise, templates are
- * read each time this class is instantiated.
- */
- public boolean isCachingEnabled ()
- {
- return cachingEnabled && WOApplication.application().isCachingEnabled();
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for this component.
- */
- public WOElement template()
- {
- return template;
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for the named component.
- * @deprecated Use template() instead.
- */
- public WOElement templateWithName(String aComponentName)
- {
- return templateWithName( aComponentName, null );
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the templates in the component directory for the named component.
- */
- WOElement templateWithName(String aComponentName, String aFramework)
- {
- NSArray languages = null;
- WOContext context = context();
- if ( context != null )
- {
- languages = context.request().browserLanguages();
- }
- WOElement result = templateWithHTMLString(
- readTemplateResource( aComponentName, aFramework, TEMPLATE_SUFFIX, languages ),
- readTemplateResource( aComponentName, aFramework, DECLARATION_SUFFIX, languages ),
- languages );
- if ( result == null )
- {
- System.out.println( "WOComponent.templateWithName: failed for " + aComponentName );
- }
- return result;
- }
-
- /**
- * Returns the root of the tree of elements produced by parsing
- * the specfified HTML string and bindings declaration string.
- * Note: language list is currently ignored.
- */
- public static WOElement templateWithHTMLString (
- String anHTMLString, String aDeclaration, List aLanguageList)
- {
- if ( anHTMLString == null ) return null;
- WOElement result = null;
- try
- {
- NSDictionary bindings = processDeclaration( aDeclaration );
- List elements = new LinkedList();
- int index = processTemplate( elements, anHTMLString, 0, bindings, aLanguageList );
- if ( index == -1 )
- {
- if ( elements.size() == 1 )
- {
- result = (WOElement) elements.get(0);
- }
- else
- {
- result = new WOParentElement( elements );
- }
- }
- else // entire template did not process
- {
- throw new RuntimeException( "No closing tag: " + anHTMLString.substring( index ) );
- }
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- }
+ /**
+ * Returns whether templates are cached. If true, templates are read once per
+ * application lifetime. Otherwise, templates are read each time this class is
+ * instantiated.
+ */
+ public boolean isCachingEnabled() {
+ return cachingEnabled && WOApplication.application().isCachingEnabled();
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for this component.
+ */
+ public WOElement template() {
+ return template;
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for the named component.
+ *
+ * @deprecated Use template() instead.
+ */
+ public WOElement templateWithName(String aComponentName) {
+ return templateWithName(aComponentName, null);
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the templates in
+ * the component directory for the named component.
+ */
+ WOElement templateWithName(String aComponentName, String aFramework) {
+ NSArray languages = null;
+ WOContext context = context();
+ if (context != null) {
+ languages = context.request().browserLanguages();
+ }
+ WOElement result = templateWithHTMLString(
+ readTemplateResource(aComponentName, aFramework, TEMPLATE_SUFFIX, languages),
+ readTemplateResource(aComponentName, aFramework, DECLARATION_SUFFIX, languages), languages);
+ if (result == null) {
+ System.out.println("WOComponent.templateWithName: failed for " + aComponentName);
+ }
return result;
- }
-
- /**
- * Called at the beginning of a request-response cycle.
- * Override to perform any necessary initialization.
- * This implementation does nothing.
- */
- public void awake ()
- {
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
+ }
+
+ /**
+ * Returns the root of the tree of elements produced by parsing the specfified
+ * HTML string and bindings declaration string. Note: language list is currently
+ * ignored.
+ */
+ public static WOElement templateWithHTMLString(String anHTMLString, String aDeclaration, List aLanguageList) {
+ if (anHTMLString == null)
+ return null;
+ WOElement result = null;
+ try {
+ NSDictionary bindings = processDeclaration(aDeclaration);
+ List elements = new LinkedList();
+ int index = processTemplate(elements, anHTMLString, 0, bindings, aLanguageList);
+ if (index == -1) {
+ if (elements.size() == 1) {
+ result = (WOElement) elements.get(0);
+ } else {
+ result = new WOParentElement(elements);
+ }
+ } else // entire template did not process
+ {
+ throw new RuntimeException("No closing tag: " + anHTMLString.substring(index));
+ }
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * Called at the beginning of a request-response cycle. Override to perform any
+ * necessary initialization. This implementation does nothing.
+ */
+ public void awake() {
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
context = aContext;
parent = aContext.parent();
- if ( template == null )
- {
- template = templateWithName( name(), frameworkName() );
- }
- if ( template != null )
- {
- template.ensureAwakeInContext( aContext );
- }
- awake();
- }
-
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- template.takeValuesFromRequest( aRequest, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- template.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- WOActionResults result = null;
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- result = template.invokeAction( aRequest, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- result = template.invokeAction( aRequest, aContext );
- }
+ if (template == null) {
+ template = templateWithName(name(), frameworkName());
+ }
+ if (template != null) {
+ template.ensureAwakeInContext(aContext);
+ }
+ awake();
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ template.takeValuesFromRequest(aRequest, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ template.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ WOActionResults result = null;
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ result = template.invokeAction(aRequest, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ result = template.invokeAction(aRequest, aContext);
+ }
return result;
- }
-
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- if ( template != null )
- {
- template.appendToResponse( aResponse, aContext );
- }
- pushValuesToParent();
- }
- else
- if ( template != null )
- {
- template.appendToResponse( aResponse, aContext );
- }
- context = null;
- }
-
- /**
- * Called at the end of a request-response cycle.
- * Override to perform any necessary clean-up.
- * This implementation does nothing.
- */
- public void sleep ()
- {
- }
-
- /**
- * Generates a WOResponse and calls appendToResponse() on it.
- */
- public WOResponse generateResponse ()
- {
- WOResponse response = new WOResponse();
- WOContext context = context();
- appendToResponse( response, context ); // nulls out context
- context.session().savePage( this ); //?is this the right place for this?
- return response;
- }
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
+ if (template != null) {
+ template.appendToResponse(aResponse, aContext);
+ }
+ pushValuesToParent();
+ } else if (template != null) {
+ template.appendToResponse(aResponse, aContext);
+ }
+ context = null;
+ }
+
+ /**
+ * Called at the end of a request-response cycle. Override to perform any
+ * necessary clean-up. This implementation does nothing.
+ */
+ public void sleep() {
+ }
/**
- * Returns this component's parent component, or null if none.
- */
- public WOComponent parent()
- {
- return parent;
- }
-
- /**
- * Invokes the specified action on this component's parent.
- * Variables will be synchronized when this method returns.
- */
- public WOActionResults performParentAction(String anAction)
- {
- WOActionResults result = parent().performAction( anAction );
- if ( synchronizesVariablesWithBindings() )
- {
- pullValuesFromParent();
- }
- return result;
- }
-
- /**
- * Invokes the specified action on this component.
- */
- WOActionResults performAction( String anAction )
- {
- try
- {
- return (WOActionResults) NSSelector.invoke( anAction, this );
+ * Generates a WOResponse and calls appendToResponse() on it.
+ */
+ public WOResponse generateResponse() {
+ WOResponse response = new WOResponse();
+ WOContext context = context();
+ appendToResponse(response, context); // nulls out context
+ context.session().savePage(this); // ?is this the right place for this?
+ return response;
+ }
+
+ /**
+ * Returns this component's parent component, or null if none.
+ */
+ public WOComponent parent() {
+ return parent;
+ }
+
+ /**
+ * Invokes the specified action on this component's parent. Variables will be
+ * synchronized when this method returns.
+ */
+ public WOActionResults performParentAction(String anAction) {
+ WOActionResults result = parent().performAction(anAction);
+ if (synchronizesVariablesWithBindings()) {
+ pullValuesFromParent();
}
- catch ( NoSuchMethodException exc )
- {
+ return result;
+ }
+
+ /**
+ * Invokes the specified action on this component.
+ */
+ WOActionResults performAction(String anAction) {
+ try {
+ return (WOActionResults) NSSelector.invoke(anAction, this);
+ } catch (NoSuchMethodException exc) {
// returns below
- }
- catch ( InvocationTargetException exc )
- {
+ } catch (InvocationTargetException exc) {
Throwable t = exc.getTargetException();
- exc.printStackTrace();
- throw new RuntimeException( t.toString() );
+ exc.printStackTrace();
+ throw new RuntimeException(t.toString());
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ throw new RuntimeException(exc.toString());
}
- catch ( Exception exc )
- {
- exc.printStackTrace();
- throw new RuntimeException( exc.toString() );
+ return null;
+ }
+
+ /**
+ * Called before each phase of the request-response cycle, if
+ * synchronizesVariablesWithBindings is true and the component is not stateless.
+ */
+ public void pullValuesFromParent() {
+ if (associations == null)
+ return;
+ String key;
+ Enumeration e = associations.keyEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ takeValueForKey(valueForBinding(key), key);
+ }
+ }
+
+ /**
+ * Called after each phase of the request-response cycle, if
+ * synchronizesVariablesWithBindings is true and the component is not stateless.
+ */
+ public void pushValuesToParent() {
+ if (associations == null)
+ return;
+ String key;
+ Enumeration e = associations.keyEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ setValueForBinding(valueForKey(key), key);
}
- return null;
- }
-
- /**
- * Called before each phase of the request-response cycle,
- * if synchronizesVariablesWithBindings is true and the
- * component is not stateless.
- */
- public void pullValuesFromParent()
- {
- if ( associations == null ) return;
- String key;
- Enumeration e = associations.keyEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- takeValueForKey( valueForBinding( key ), key );
- }
- }
-
- /**
- * Called after each phase of the request-response cycle,
- * if synchronizesVariablesWithBindings is true and the
- * component is not stateless.
- */
- public void pushValuesToParent()
- {
- if ( associations == null ) return;
- String key;
- Enumeration e = associations.keyEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- setValueForBinding( valueForKey( key ), key );
- }
- }
-
- /**
- * Returns whether this component should be considered stateless.
- * Stateless components are shared between sessions to conserve memory.
- * This implementation returns false; override to return true.
- */
- public boolean isStateless()
- {
- return false;
- }
-
- /**
- * Called only on stateless components to tell themselves to reset
- * themselves for another invocation using a different context.
- * This implementation does nothing.
- */
- public void reset()
- {
- // does nothing
- }
-
- /**
- * Returns the application containing this instance of the class.
- */
- public WOApplication application ()
- {
- return context.application();
- }
-
- /**
- * Returns whether a session has been created for this user.
- */
- public boolean hasSession ()
- {
- return context.hasSession();
- }
-
- /**
- * Returns the current session object, creating it if it doesn't exist.
- */
- public WOSession session ()
- {
- return context.session();
- }
+ }
+
+ /**
+ * Returns whether this component should be considered stateless. Stateless
+ * components are shared between sessions to conserve memory. This
+ * implementation returns false; override to return true.
+ */
+ public boolean isStateless() {
+ return false;
+ }
+
+ /**
+ * Called only on stateless components to tell themselves to reset themselves
+ * for another invocation using a different context. This implementation does
+ * nothing.
+ */
+ public void reset() {
+ // does nothing
+ }
/**
- * Returns the current context for this component.
- */
- public WOContext context ()
- {
- return context;
- }
+ * Returns the application containing this instance of the class.
+ */
+ public WOApplication application() {
+ return context.application();
+ }
/**
- * Returns a new WOComponent with the specified name.
- * If null, returns the component named "Main".
- * If the named component doesn't exist, returns null.
- */
- public WOComponent pageWithName (String aName)
- {
- return application().pageWithName( aName, context() );
- }
+ * Returns whether a session has been created for this user.
+ */
+ public boolean hasSession() {
+ return context.hasSession();
+ }
/**
- * Called when exceptions are raised by assigning values
- * to this object. This implementation does nothing, but
- * subclasses may override to do something useful.
- */
- public void validationFailedWithException (
- Throwable anException, Object aValue, String aPath)
- {
- // does nothing
- }
+ * Returns the current session object, creating it if it doesn't exist.
+ */
+ public WOSession session() {
+ return context.session();
+ }
/**
- * Called on the component that represents the requested page.
- * Override to return logging information specific to your
- * component. This implementation returns the component's name.
- */
- public String descriptionForResponse (
- WOResponse aResponse, WOContext aContext)
- {
- return name();
- }
+ * Returns the current context for this component.
+ */
+ public WOContext context() {
+ return context;
+ }
/**
- * Returns true if this component should get and set values
- * in its parent. This implementation returns true.
- * Override to create a component that does not automatically
- * synchronize bindings with its parent, useful if you wish
- * to handle synchronization manually.
- */
- public boolean synchronizesVariablesWithBindings ()
- {
- return true;
- }
-
- /**
- * Returns whether this component has a readable value that maps
- * to the specified binding. This implementation calls
- * hasBinding(aBinding).
- */
- public boolean canGetValueForBinding(String aBinding)
- {
- return hasBinding( aBinding );
- }
-
- /**
- * Returns whether this component has a writable value that maps
- * to the specified binding.
- */
- public boolean canSetValueForBinding(String aBinding)
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null)
- {
- if ( assoc.isValueSettable() ) return true;
- }
- return false;
- }
-
- /**
- * Returns whether this component has the specified binding.
- */
- public boolean hasBinding (String aBinding)
- {
- if ( associations == null ) return false;
- return associations.containsKey( aBinding );
- }
+ * Returns a new WOComponent with the specified name. If null, returns the
+ * component named "Main". If the named component doesn't exist, returns null.
+ */
+ public WOComponent pageWithName(String aName) {
+ return application().pageWithName(aName, context());
+ }
+
+ /**
+ * Called when exceptions are raised by assigning values to this object. This
+ * implementation does nothing, but subclasses may override to do something
+ * useful.
+ */
+ public void validationFailedWithException(Throwable anException, Object aValue, String aPath) {
+ // does nothing
+ }
+
+ /**
+ * Called on the component that represents the requested page. Override to
+ * return logging information specific to your component. This implementation
+ * returns the component's name.
+ */
+ public String descriptionForResponse(WOResponse aResponse, WOContext aContext) {
+ return name();
+ }
/**
- * Returns the value for the specified binding for this component.
- * The parent component is expected to have set the binding for
- * this component. If no such binding exists, the binding is
- * treated as a property is and obtained using valueForKey.
- * If the property is not found, this method returns null.
- */
- public Object valueForBinding (String aBinding)
- {
- WOComponent parent = parent();
- if ( associations != null )
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null && parent != null)
- {
- return assoc.valueInComponent( parent );
- }
- }
- if ( parent != null )
- {
- return parent.valueForKey( aBinding );
- }
- return null;
- }
+ * Returns true if this component should get and set values in its parent. This
+ * implementation returns true. Override to create a component that does not
+ * automatically synchronize bindings with its parent, useful if you wish to
+ * handle synchronization manually.
+ */
+ public boolean synchronizesVariablesWithBindings() {
+ return true;
+ }
+
+ /**
+ * Returns whether this component has a readable value that maps to the
+ * specified binding. This implementation calls hasBinding(aBinding).
+ */
+ public boolean canGetValueForBinding(String aBinding) {
+ return hasBinding(aBinding);
+ }
+
+ /**
+ * Returns whether this component has a writable value that maps to the
+ * specified binding.
+ */
+ public boolean canSetValueForBinding(String aBinding) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null) {
+ if (assoc.isValueSettable())
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this component has the specified binding.
+ */
+ public boolean hasBinding(String aBinding) {
+ if (associations == null)
+ return false;
+ return associations.containsKey(aBinding);
+ }
+
+ /**
+ * Returns the value for the specified binding for this component. The parent
+ * component is expected to have set the binding for this component. If no such
+ * binding exists, the binding is treated as a property is and obtained using
+ * valueForKey. If the property is not found, this method returns null.
+ */
+ public Object valueForBinding(String aBinding) {
+ WOComponent parent = parent();
+ if (associations != null) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null && parent != null) {
+ return assoc.valueInComponent(parent);
+ }
+ }
+ if (parent != null) {
+ return parent.valueForKey(aBinding);
+ }
+ return null;
+ }
/**
- * Sets the value for the specified binding for this component.
- * The parent component is expected to have set the binding
- * for this component. If no such binding exists, the binding
- * is treated as a property and is set using takeValueForKey.
- * If the property is not found, this method fails silently.
- */
- public void setValueForBinding (Object aValue, String aBinding)
- {
- if ( associations == null ) return;
-
- WOComponent parent = parent();
-
- if ( associations != null )
- {
- WOAssociation assoc =
- (WOAssociation)associations.objectForKey(aBinding);
- if (assoc != null && parent != null)
- {
- if ( assoc.isValueSettable() )
- {
- assoc.setValue( aValue, parent );
- return;
- }
- }
- }
- if ( parent != null )
- {
- parent.takeValueForKey( aValue, aBinding );
- }
- }
-
- public static void logString (String aString)
- {
- System.out.println( aString );
- }
-
- public static void debugString (String aString)
- {
- System.err.println( aString );
- }
-
- public Object valueForKeyPath (String aPath)
- {
- // currently key value coding support also handles keypaths
- return valueForKey( aPath );
- }
-
- public void takeValueForKeyPath (Object aValue, String aPath)
- {
- // currently key value coding support also handles keypaths
- takeValueForKey( aValue, aPath );
- }
-
- public NSDictionary valuesForKeys (List aKeyList)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public void takeValuesFromDictionary (Map aValueMap)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public Object valueForKey (String aKey)
- { // System.out.println( "valueForKey: " + aKey + "->" + this );
- // handle "^" property keys
- if ( aKey.startsWith( "^" ) )
- {
- return valueForBinding( aKey.substring(1) );
- }
- return EOKeyValueCodingSupport.valueForKey( this, aKey );
- }
-
- public void takeValueForKey (Object aValue, String aKey)
- { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this );
- // handle "^" property keys
- if ( aKey.startsWith( "^" ) )
- {
- setValueForBinding( aValue, aKey.substring(1) );
- return;
- }
- EOKeyValueCodingSupport.takeValueForKey( this, aValue, aKey );
- }
-
- public Object storedValueForKey (String aKey)
- {
- return EOKeyValueCodingSupport.storedValueForKey( this, aKey );
- }
-
- public void takeStoredValueForKey (Object aValue, String aKey)
- {
- EOKeyValueCodingSupport.takeStoredValueForKey( this, aValue, aKey );
- }
-
- public Object handleQueryWithUnboundKey (String aKey)
- {
- return EOKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- public void handleTakeValueForUnboundKey (Object aValue, String aKey)
- {
- EOKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- public void unableToSetNullForKey (String aKey)
- {
- EOKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- public Object validateTakeValueForKeyPath (Object aValue, String aKey)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
+ * Sets the value for the specified binding for this component. The parent
+ * component is expected to have set the binding for this component. If no such
+ * binding exists, the binding is treated as a property and is set using
+ * takeValueForKey. If the property is not found, this method fails silently.
+ */
+ public void setValueForBinding(Object aValue, String aBinding) {
+ if (associations == null)
+ return;
+
+ WOComponent parent = parent();
+
+ if (associations != null) {
+ WOAssociation assoc = (WOAssociation) associations.objectForKey(aBinding);
+ if (assoc != null && parent != null) {
+ if (assoc.isValueSettable()) {
+ assoc.setValue(aValue, parent);
+ return;
+ }
+ }
+ }
+ if (parent != null) {
+ parent.takeValueForKey(aValue, aBinding);
+ }
+ }
+
+ public static void logString(String aString) {
+ System.out.println(aString);
+ }
+
+ public static void debugString(String aString) {
+ System.err.println(aString);
+ }
+
+ public Object valueForKeyPath(String aPath) {
+ // currently key value coding support also handles keypaths
+ return valueForKey(aPath);
+ }
+
+ public void takeValueForKeyPath(Object aValue, String aPath) {
+ // currently key value coding support also handles keypaths
+ takeValueForKey(aValue, aPath);
+ }
+
+ public NSDictionary valuesForKeys(List aKeyList) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public void takeValuesFromDictionary(Map aValueMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+ public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this );
+ // handle "^" property keys
+ if (aKey.startsWith("^")) {
+ return valueForBinding(aKey.substring(1));
+ }
+ return EOKeyValueCodingSupport.valueForKey(this, aKey);
+ }
+
+ public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : "
+ // + aValue + "->" + this );
+ // handle "^" property keys
+ if (aKey.startsWith("^")) {
+ setValueForBinding(aValue, aKey.substring(1));
+ return;
+ }
+ EOKeyValueCodingSupport.takeValueForKey(this, aValue, aKey);
+ }
+
+ public Object storedValueForKey(String aKey) {
+ return EOKeyValueCodingSupport.storedValueForKey(this, aKey);
+ }
+
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.takeStoredValueForKey(this, aValue, aKey);
+ }
+
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return EOKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ EOKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ public void unableToSetNullForKey(String aKey) {
+ EOKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ public Object validateTakeValueForKeyPath(Object aValue, String aKey) {
+ throw new RuntimeException("Not implemented yet.");
+ }
// Template Processing
- /**
- * Takes a template string and a location to begin parsing,
- * looking only for interesting tags, and calling itself recursively
- * as necessary. Returns the index to resume parsing, or -1 if done.
- */
- static private int processTemplate(
- List elements, String template, int index,
- Map bindings, List aLanguageList )
- throws java.io.IOException
- { //System.out.println( "processTemplate: " + index );
- if ( template == null ) return -1;
-
- int start = index;
-
- while ( true )
- {
- // search for start of next tag
- start = template.indexOf( '<', start );
-
- if ( start == -1 )
- {
- // if no tags, send output and return
- elements.add( new WOStaticElement( template.substring( index ) ) );
- return -1;
- }
-
- // search for end of opening tag
- int end = template.indexOf( ">", start + 1 );
- if ( end == -1 )
- {
- // if no end to tag
- throw new RuntimeException( "No end to tag: "
- + template.substring( start ) );
- }
-
- boolean hasBody = true;
- if ( template.charAt( end - 1 ) == '/' )
- {
- // tag is standalone - no body
- end = end - 1;
- hasBody = false;
- }
-
- // search for name of tag
- int endName = start + 1;
- while ( endName < end )
- {
- if ( Character.isWhitespace(
- template.charAt(endName) ) ) break;
- endName++;
- }
-
- String name = template.substring( start + 1, endName );
-
- if ( name.toLowerCase().startsWith( OPEN_TAG ) )
- {
- // add the contents before the tag
- //System.out.println( index + " : " + start + " : " + hasBody );
- elements.add( new WOStaticElement( template.substring( index, start ) ) );
-
- // interesting tag; parse parameters
- Map params = new HashMap( 5 ); // arbitrary init length
- if ( endName < end )
- {
- // delimit by whitespace
- StringTokenizer tokens = new StringTokenizer(
- template.substring( endName+1, end ) );
- int equals;
- String token;
- String value;
- while ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
- equals = token.indexOf( '=' );
- if ( equals != -1 )
- {
- value = token.substring( equals+1 );
-
- if ( value.startsWith( "\"" ) )
- {
- // handle spaces within parameter names
- while ( ! value.endsWith( "\"" ) )
- {
- value = value + " " + tokens.nextToken();
- }
-
- // strip quotation marks
- if ( value.endsWith( "\"" ) )
- {
- value = value.substring( 1, value.length()-1 );
- }
- }
-
- // register key with specified value
- params.put(
- token.substring( 0, equals ).toLowerCase(), value );
-
- }
- else
- {
- // no value found, register the key name
- params.put( token.toLowerCase(), "" );
- }
- }
- }
-
- index = end + (hasBody?1:2);
-
- WOElement body = null;
- if ( hasBody )
- {
- List childElements = new LinkedList();
-
- index = processTemplate(
- childElements, template, index,
- bindings, aLanguageList );
- start = index;
-
- if ( index == -1 )
- {
- throw new RuntimeException(
- "No closing tag found: " + template.substring( end ) );
- }
-
- if ( childElements.size() == 1 )
- {
- body = (WOElement) childElements.get(0);
- }
- else
- {
- body = new WOParentElement( childElements );
- }
- }
-
- WOElement element = null;
- String nameProperty = (String) params.get( NAME_KEY );
- NSDictionary original = (NSDictionary) bindings.get( nameProperty );
- //System.out.println( nameProperty + " : " + associations );
- if ( original == null )
- {
- original = NSDictionary.EmptyDictionary;
- System.err.println( "No associations for: " + nameProperty );
- System.err.println( bindings );
- }
-
- NSDictionary associations = new NSMutableDictionary( original );
- String elementClass = (String) associations.remove( WOApplication.ELEMENT_CLASS );
-
- WOApplication application = WOApplication.application();
- element = application.dynamicElementWithName(
- elementClass, associations, body, aLanguageList );
- if ( element == null )
- {
- // unable to create element: show assocs in static element
- element = new WOStaticElement( associations.toString() );
- }
-
- //System.out.println( element );
- elements.add( element );
-
- if ( !hasBody )
- {
- start = end + 2;
- }
- }
- else
- if ( name.toLowerCase().startsWith( CLOSE_TAG ) )
- {
- // add any contents before the tag
- elements.add( new WOStaticElement( template.substring( index, start ) ) );
-
+ /**
+ * Takes a template string and a location to begin parsing, looking only for
+ * interesting tags, and calling itself recursively as necessary. Returns the
+ * index to resume parsing, or -1 if done.
+ */
+ static private int processTemplate(List elements, String template, int index, Map bindings, List aLanguageList)
+ throws java.io.IOException { // System.out.println( "processTemplate: " + index );
+ if (template == null)
+ return -1;
+
+ int start = index;
+
+ while (true) {
+ // search for start of next tag
+ start = template.indexOf('<', start);
+
+ if (start == -1) {
+ // if no tags, send output and return
+ elements.add(new WOStaticElement(template.substring(index)));
+ return -1;
+ }
+
+ // search for end of opening tag
+ int end = template.indexOf(">", start + 1);
+ if (end == -1) {
+ // if no end to tag
+ throw new RuntimeException("No end to tag: " + template.substring(start));
+ }
+
+ boolean hasBody = true;
+ if (template.charAt(end - 1) == '/') {
+ // tag is standalone - no body
+ end = end - 1;
+ hasBody = false;
+ }
+
+ // search for name of tag
+ int endName = start + 1;
+ while (endName < end) {
+ if (Character.isWhitespace(template.charAt(endName)))
+ break;
+ endName++;
+ }
+
+ String name = template.substring(start + 1, endName);
+
+ if (name.toLowerCase().startsWith(OPEN_TAG)) {
+ // add the contents before the tag
+ // System.out.println( index + " : " + start + " : " + hasBody );
+ elements.add(new WOStaticElement(template.substring(index, start)));
+
+ // interesting tag; parse parameters
+ Map params = new HashMap(5); // arbitrary init length
+ if (endName < end) {
+ // delimit by whitespace
+ StringTokenizer tokens = new StringTokenizer(template.substring(endName + 1, end));
+ int equals;
+ String token;
+ String value;
+ while (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+ equals = token.indexOf('=');
+ if (equals != -1) {
+ value = token.substring(equals + 1);
+
+ if (value.startsWith("\"")) {
+ // handle spaces within parameter names
+ while (!value.endsWith("\"")) {
+ value = value + " " + tokens.nextToken();
+ }
+
+ // strip quotation marks
+ if (value.endsWith("\"")) {
+ value = value.substring(1, value.length() - 1);
+ }
+ }
+
+ // register key with specified value
+ params.put(token.substring(0, equals).toLowerCase(), value);
+
+ } else {
+ // no value found, register the key name
+ params.put(token.toLowerCase(), "");
+ }
+ }
+ }
+
+ index = end + (hasBody ? 1 : 2);
+
+ WOElement body = null;
+ if (hasBody) {
+ List childElements = new LinkedList();
+
+ index = processTemplate(childElements, template, index, bindings, aLanguageList);
+ start = index;
+
+ if (index == -1) {
+ throw new RuntimeException("No closing tag found: " + template.substring(end));
+ }
+
+ if (childElements.size() == 1) {
+ body = (WOElement) childElements.get(0);
+ } else {
+ body = new WOParentElement(childElements);
+ }
+ }
+
+ WOElement element = null;
+ String nameProperty = (String) params.get(NAME_KEY);
+ NSDictionary original = (NSDictionary) bindings.get(nameProperty);
+ // System.out.println( nameProperty + " : " + associations );
+ if (original == null) {
+ original = NSDictionary.EmptyDictionary;
+ System.err.println("No associations for: " + nameProperty);
+ System.err.println(bindings);
+ }
+
+ NSDictionary associations = new NSMutableDictionary(original);
+ String elementClass = (String) associations.remove(WOApplication.ELEMENT_CLASS);
+
+ WOApplication application = WOApplication.application();
+ element = application.dynamicElementWithName(elementClass, associations, body, aLanguageList);
+ if (element == null) {
+ // unable to create element: show assocs in static element
+ element = new WOStaticElement(associations.toString());
+ }
+
+ // System.out.println( element );
+ elements.add(element);
+
+ if (!hasBody) {
+ start = end + 2;
+ }
+ } else if (name.toLowerCase().startsWith(CLOSE_TAG)) {
+ // add any contents before the tag
+ elements.add(new WOStaticElement(template.substring(index, start)));
+
// return end + name.length() + 1; // "<" + ">" - 1 = 1
- return end + (hasBody?1:2); // "<" + ">" - 1 = 1
- }
- else
- {
- // tag not interesting: continue
- start = end + (hasBody?1:2);
- }
- }
- }
-
-
- // Utility Methods
-
- static private void rewriteTag( String tagName,
- Map properties, String body, StringBuffer context )
- throws java.io.IOException
- {
- context.append( "<"+tagName );
+ return end + (hasBody ? 1 : 2); // "<" + ">" - 1 = 1
+ } else {
+ // tag not interesting: continue
+ start = end + (hasBody ? 1 : 2);
+ }
+ }
+ }
+
+ // Utility Methods
+
+ static private void rewriteTag(String tagName, Map properties, String body, StringBuffer context)
+ throws java.io.IOException {
+ context.append("<" + tagName);
Iterator it = properties.keySet().iterator();
String key;
- while ( it.hasNext() )
- {
+ while (it.hasNext()) {
key = (String) it.next();
- context.append( " " + key + "=\"" + properties.get( key ) + "\"" );
+ context.append(" " + key + "=\"" + properties.get(key) + "\"");
}
-
- if ( body == null )
- {
- context.append( "/>" );
+
+ if (body == null) {
+ context.append("/>");
return;
}
-
- context.append( ">" + body + "</" + tagName + ">" );
+
+ context.append(">" + body + "</" + tagName + ">");
+ }
+
+ private String justTheClassName() {
+ String className = getClass().getName();
+ int index = className.lastIndexOf(".");
+ if (index == -1)
+ return className;
+ return className.substring(index + 1);
+ }
+
+ private String justTheResourcePath() {
+ int last = -1;
+ char[] src = getClass().getName().toCharArray();
+ char[] dst = new char[src.length];
+ for (int i = 0; i < src.length; i++) {
+ if (src[i] == '.') {
+ dst[i] = '/';
+ last = i;
+ } else {
+ dst[i] = src[i];
+ }
+ }
+ if (last == -1)
+ return null;
+ return new String(dst, 0, last);
}
-
- private String justTheClassName()
- {
- String className = getClass().getName();
- int index = className.lastIndexOf( "." );
- if ( index == -1 ) return className;
- return className.substring( index+1 );
- }
-
- private String justTheResourcePath()
- {
- int last = -1;
- char[] src = getClass().getName().toCharArray();
- char[] dst = new char[ src.length ];
- for ( int i = 0; i < src.length; i++ )
- {
- if ( src[i] == '.' )
- {
- dst[i] = '/';
- last = i;
- }
- else
- {
- dst[i] = src[i];
- }
- }
- if ( last == -1 ) return null;
- return new String( dst, 0, last );
- }
-
- private String readTemplateResource( String name, String framework, String suffix, NSArray languages )
- {
- if ( name == null ) return null;
- name = name + DIRECTORY_SUFFIX + '/' + name + suffix;
- InputStream is = null;
- if ( isCachingEnabled() )
- {
- byte[] data = WOApplication.application().resourceManager().bytesForResourceNamed(
- name, framework, languages );
- if ( data != null )
- {
- is = new ByteArrayInputStream( data );
- }
- }
- else
- {
- is = WOApplication.application().resourceManager().inputStreamForResourceNamed(
- name, framework, languages );
- }
- if ( is == null )
- {
- System.err.println( "No resources found for: " + name );
- return null;
- }
-
- // try to autodetect encoding
- String encoding = "ISO8859_1";
- try
- {
- byte[] header = new byte[4];
- is = new PushbackInputStream( is, 4 );
- is.read( header );
- if ( header[0] < 33 || header[0] > 126 )
- {
- // if any funny characters, presume UTF-16
- encoding = "UTF-16";
- if (!( header[1] < 33 || header[1] > 126 ))
- {
- // if second character is valid, presume UTF-8
- encoding = "UTF-8";
- }
- }
- // check byte-order-mark
- if (header[0] == 0xef && header[1] == 0xbb && header[2] == 0xbf) // utf-8
- {
- encoding = "UTF-8";
- }
- else
- if (header[0] == 0xfe && header[1] == 0xff) // utf-16
- {
- encoding = "UTF-16";
- }
- else
- if (header[0] == 0 && header[1] == 0 && header[2] == 0xfe && header[3] == 0xff) // ucs-4
- {
- encoding = "UCS-4"; //??
- }
- else
- if (header[0] == 0xff && header[1] == 0xfe) // ucs-2le, ucs-4le, and
- {
- encoding = "UCS-16le"; //??
- }
- // put back the header
- ((PushbackInputStream)is).unread( header );
- }
- catch ( Throwable t )
- {
- t.printStackTrace();
- System.err.println(
- "Error while autodetecting encoding: should never happen" );
- }
-
- try
- {
- String line;
- StringBuffer buf = new StringBuffer();
- BufferedReader r = new BufferedReader( new InputStreamReader( is, encoding ) );
- while ( ( line = r.readLine() ) != null )
- {
- buf.append( line );
- buf.append( '\n' );
- }
- is.close(); // release the resource
- return buf.toString();
- }
- catch ( IOException exc )
- {
- System.err.println( "Error while reading: " + name );
- exc.printStackTrace();
- return null;
- }
- }
-
- // Declaration Parsing
-
- /**
- * Parses the declarations in the specified content and returns a map of element names
- * to maps of attribute names to WOAssociations.
- */
- private static NSDictionary processDeclaration( String content )
- {
- int index;
- NSMutableDictionary result = new NSMutableDictionary();
-
- // strip out comments
- StringBuffer stripped = new StringBuffer();
- try
- {
- LineNumberReader reader =
- new LineNumberReader( new StringReader( content ) );
- String line;
- while ( ( line = reader.readLine() ) != null )
- {
- index = line.indexOf("//");
- while (index > -1) {
- //(chochos) This used to truncate lines with quoted URLs
- //in them. We have to check that the "//" is not inside quotes.
- boolean quoted = false;
- if (index > 0) {
- for (int _position = 0; _position < index; _position++)
- if (line.charAt(_position) == '"')
- quoted = !quoted;
- }
- if (!quoted) {
- line = line.substring( 0, index );
- index = -1;
- } else {
- //if we didn't truncate the line it's because the //
- //were quoted. let's look for more, and check if they're not quoted...
- index = line.indexOf("\"", index);
- if (index > 0) {
- index = line.indexOf("//", index);
- }
- }
- }
- stripped.append( line );
- }
+
+ private String readTemplateResource(String name, String framework, String suffix, NSArray languages) {
+ if (name == null)
+ return null;
+ name = name + DIRECTORY_SUFFIX + '/' + name + suffix;
+ InputStream is = null;
+ if (isCachingEnabled()) {
+ byte[] data = WOApplication.application().resourceManager().bytesForResourceNamed(name, framework,
+ languages);
+ if (data != null) {
+ is = new ByteArrayInputStream(data);
+ }
+ } else {
+ is = WOApplication.application().resourceManager().inputStreamForResourceNamed(name, framework, languages);
}
- catch ( IOException exc )
- {
- throw new RuntimeException(
- "Error while stripping comments from declaration: " + stripped );
+ if (is == null) {
+ System.err.println("No resources found for: " + name);
+ return null;
}
- while ( (index = stripped.toString().indexOf( "/*" )) != -1 )
- {
- int j = stripped.toString().indexOf( "*/", index+1 );
- if ( j == -1 ) break;
- stripped.delete( index, j+2 );
- }
-
- String token;
- StringTokenizer tokens = new StringTokenizer( stripped.toString(), "{}", true );
- while ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
-
- // next token is the name and class
- String name, cl;
- index = token.indexOf( ":" );
- if ( index > -1 )
- {
- name = token.substring( 0, index ).trim();
- cl = token.substring( index+1 ).trim();
+
+ // try to autodetect encoding
+ String encoding = "ISO8859_1";
+ try {
+ byte[] header = new byte[4];
+ is = new PushbackInputStream(is, 4);
+ is.read(header);
+ if (header[0] < 33 || header[0] > 126) {
+ // if any funny characters, presume UTF-16
+ encoding = "UTF-16";
+ if (!(header[1] < 33 || header[1] > 126)) {
+ // if second character is valid, presume UTF-8
+ encoding = "UTF-8";
+ }
}
- else
+ // check byte-order-mark
+ if (header[0] == 0xef && header[1] == 0xbb && header[2] == 0xbf) // utf-8
+ {
+ encoding = "UTF-8";
+ } else if (header[0] == 0xfe && header[1] == 0xff) // utf-16
+ {
+ encoding = "UTF-16";
+ } else if (header[0] == 0 && header[1] == 0 && header[2] == 0xfe && header[3] == 0xff) // ucs-4
{
- System.err.println( "Could not parse declaration:" );
- System.err.println( content );
- throw new RuntimeException(
- "Could not parse declaration: " + token );
- }
+ encoding = "UCS-4"; // ??
+ } else if (header[0] == 0xff && header[1] == 0xfe) // ucs-2le, ucs-4le, and
+ {
+ encoding = "UCS-16le"; // ??
+ }
+ // put back the header
+ ((PushbackInputStream) is).unread(header);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ System.err.println("Error while autodetecting encoding: should never happen");
+ }
+
+ try {
+ String line;
+ StringBuffer buf = new StringBuffer();
+ BufferedReader r = new BufferedReader(new InputStreamReader(is, encoding));
+ while ((line = r.readLine()) != null) {
+ buf.append(line);
+ buf.append('\n');
+ }
+ is.close(); // release the resource
+ return buf.toString();
+ } catch (IOException exc) {
+ System.err.println("Error while reading: " + name);
+ exc.printStackTrace();
+ return null;
+ }
+ }
+
+ // Declaration Parsing
+
+ /**
+ * Parses the declarations in the specified content and returns a map of element
+ * names to maps of attribute names to WOAssociations.
+ */
+ private static NSDictionary processDeclaration(String content) {
+ int index;
+ NSMutableDictionary result = new NSMutableDictionary();
+
+ // strip out comments
+ StringBuffer stripped = new StringBuffer();
+ try {
+ LineNumberReader reader = new LineNumberReader(new StringReader(content));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ index = line.indexOf("//");
+ while (index > -1) {
+ // (chochos) This used to truncate lines with quoted URLs
+ // in them. We have to check that the "//" is not inside quotes.
+ boolean quoted = false;
+ if (index > 0) {
+ for (int _position = 0; _position < index; _position++)
+ if (line.charAt(_position) == '"')
+ quoted = !quoted;
+ }
+ if (!quoted) {
+ line = line.substring(0, index);
+ index = -1;
+ } else {
+ // if we didn't truncate the line it's because the //
+ // were quoted. let's look for more, and check if they're not quoted...
+ index = line.indexOf("\"", index);
+ if (index > 0) {
+ index = line.indexOf("//", index);
+ }
+ }
+ }
+ stripped.append(line);
+ }
+ } catch (IOException exc) {
+ throw new RuntimeException("Error while stripping comments from declaration: " + stripped);
+ }
+ while ((index = stripped.toString().indexOf("/*")) != -1) {
+ int j = stripped.toString().indexOf("*/", index + 1);
+ if (j == -1)
+ break;
+ stripped.delete(index, j + 2);
+ }
+
+ String token;
+ StringTokenizer tokens = new StringTokenizer(stripped.toString(), "{}", true);
+ while (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+
+ // next token is the name and class
+ String name, cl;
+ index = token.indexOf(":");
+ if (index > -1) {
+ name = token.substring(0, index).trim();
+ cl = token.substring(index + 1).trim();
+ } else {
+ System.err.println("Could not parse declaration:");
+ System.err.println(content);
+ throw new RuntimeException("Could not parse declaration: " + token);
+ }
// next token is the declaration for the name and class
- if ( ! tokens.hasMoreTokens() )
- {
- System.err.println( "Could not find associations for declaration:" );
- System.err.println( content );
- throw new RuntimeException(
- "Could not find associations for declaration: " + name );
+ if (!tokens.hasMoreTokens()) {
+ System.err.println("Could not find associations for declaration:");
+ System.err.println(content);
+ throw new RuntimeException("Could not find associations for declaration: " + name);
+ }
+
+ token = tokens.nextToken();
+ if (token.equals("{")) {
+ if (!tokens.hasMoreTokens())
+ throw new RuntimeException("Error parsing declaration: expected { but found: '" + token + "'");
+ token = tokens.nextToken();
+ }
+
+ NSMutableDictionary associations = new NSMutableDictionary();
+
+ if (!token.equals("}")) {
+ String line, key, value;
+ StringTokenizer lines = new StringTokenizer(token, ";");
+ while (lines.hasMoreElements()) {
+ line = lines.nextToken();
+ index = line.indexOf("=");
+ if (index > -1) {
+ if (line.length() == index + 1)
+ line += " ";
+ key = line.substring(0, index).trim();
+ value = line.substring(index + 1).trim();
+ } else {
+ // not a valid key: skip
+ key = null;
+ value = null;
+ }
+
+ if (key != null) {
+ // if in quotation marks
+ if ((value.startsWith("\"")) && (value.endsWith("\""))) {
+ // it's a constant value association
+ value = value.substring(1, value.length() - 1);
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ // HACK: needed to be compatible with woextensions
+ // apparently true and false are allowed without quotes
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } else {
+ // HACK: needed to be compatible with woextensions:
+ // apparently a standalone integer is allowed without quotes.
+ try {
+ Integer.parseInt(value); // does it parse?
+ associations.put(key, WOAssociation.associationWithValue(value));
+ } catch (NumberFormatException nfe) {
+ // did not parse:
+ // it's a key path association
+ associations.put(key, WOAssociation.associationWithKeyPath(value));
+ }
+ }
+ }
+ }
+ if (tokens.hasMoreTokens()) {
+ token = tokens.nextToken();
+ if (!token.equals("}"))
+ throw new RuntimeException("Error parsing declaration: expected } but found: '" + token + "'");
+ }
}
-
- token = tokens.nextToken();
- if ( token.equals( "{" ) )
- {
- if ( !tokens.hasMoreTokens() ) throw new RuntimeException(
- "Error parsing declaration: expected { but found: '" + token + "'" );
- token = tokens.nextToken();
- }
-
- NSMutableDictionary associations = new NSMutableDictionary();
-
- if ( !token.equals( "}" ) )
- {
- String line, key, value;
- StringTokenizer lines =
- new StringTokenizer( token, ";" );
- while ( lines.hasMoreElements() )
- {
- line = lines.nextToken();
- index = line.indexOf( "=" );
- if ( index > -1 )
- {
- if ( line.length() == index+ 1 ) line += " ";
- key = line.substring( 0, index ).trim();
- value = line.substring( index+1 ).trim();
- }
- else
- {
- // not a valid key: skip
- key = null;
- value = null;
- }
-
- if ( key != null )
- {
- // if in quotation marks
- if ( ( value.startsWith( "\"" ) ) && ( value.endsWith( "\"" ) ) )
- {
- // it's a constant value association
- value = value.substring( 1, value.length()-1 );
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- else
- if ( value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "false" ) )
- {
- //HACK: needed to be compatible with woextensions
- // apparently true and false are allowed without quotes
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- else
- {
- //HACK: needed to be compatible with woextensions:
- // apparently a standalone integer is allowed without quotes.
- try
- {
- Integer.parseInt( value ); // does it parse?
- associations.put( key,
- WOAssociation.associationWithValue( value ) );
- }
- catch ( NumberFormatException nfe )
- {
- // did not parse:
- // it's a key path association
- associations.put( key,
- WOAssociation.associationWithKeyPath( value ) );
- }
- }
- }
- }
- if ( tokens.hasMoreTokens() )
- {
- token = tokens.nextToken();
- if ( !token.equals( "}" ) ) throw new RuntimeException(
- "Error parsing declaration: expected } but found: '" + token + "'" );
- }
- }
- associations.put( WOApplication.ELEMENT_CLASS, cl ); // store classname
- result.put( name, associations );
-
- }
- //System.out.println( "processDeclaration: " + result );
- return result;
- }
+ associations.put(WOApplication.ELEMENT_CLASS, cl); // store classname
+ result.put(name, associations);
+
+ }
+ // System.out.println( "processDeclaration: " + result );
+ return result;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.32 2003/08/07 00:15:14 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.32 2003/08/07 00:15:14 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.31 2003/07/24 00:23:21 chochos
- * fixed problem with parsing wod files that have //-type comments. Quotes URL's would be truncated.
+ * Revision 1.31 2003/07/24 00:23:21 chochos fixed problem with parsing wod
+ * files that have //-type comments. Quotes URL's would be truncated.
*
- * Revision 1.30 2003/03/28 15:33:11 mpowers
- * Now using a PushBackInputStream for auto detection of content encoding.
- * No longer relying on markSupported() since jar input streams don't have it.
+ * Revision 1.30 2003/03/28 15:33:11 mpowers Now using a PushBackInputStream for
+ * auto detection of content encoding. No longer relying on markSupported()
+ * since jar input streams don't have it.
*
- * Revision 1.29 2003/03/03 16:41:52 mpowers
- * Bad characters in cvs log.
+ * Revision 1.29 2003/03/03 16:41:52 mpowers Bad characters in cvs log.
*
- * Revision 1.28 2003/03/03 16:37:35 mpowers
- * Better handling for string encodings.
- * Now trying to autodetect unicode-formatted templates and declarations.
- * Now handlings block-style comments in declarations.
+ * Revision 1.28 2003/03/03 16:37:35 mpowers Better handling for string
+ * encodings. Now trying to autodetect unicode-formatted templates and
+ * declarations. Now handlings block-style comments in declarations.
*
- * Revision 1.27 2003/01/28 19:33:51 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.27 2003/01/28 19:33:51 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.26 2003/01/24 20:13:22 mpowers
- * Now accepting immutable NSDictionary in constructor, not Map.
+ * Revision 1.26 2003/01/24 20:13:22 mpowers Now accepting immutable
+ * NSDictionary in constructor, not Map.
*
- * Revision 1.25 2003/01/21 17:53:45 mpowers
- * Now correctly reporting error for missing bindings.
+ * Revision 1.25 2003/01/21 17:53:45 mpowers Now correctly reporting error for
+ * missing bindings.
*
- * Revision 1.24 2003/01/20 17:50:11 mpowers
- * Caught a loop condition when same declaration was used twice.
+ * Revision 1.24 2003/01/20 17:50:11 mpowers Caught a loop condition when same
+ * declaration was used twice.
*
- * Revision 1.23 2003/01/19 22:33:25 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.23 2003/01/19 22:33:25 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.22 2003/01/17 22:55:09 mpowers
- * Straighted out the parent binding issue (I think).
- * Fixes for woextensions compatibility.
+ * Revision 1.22 2003/01/17 22:55:09 mpowers Straighted out the parent binding
+ * issue (I think). Fixes for woextensions compatibility.
*
- * Revision 1.21 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.21 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.19 2003/01/17 15:32:22 mpowers
- * Changes to better support generic elements and containers.
- * Now preserving newlines in templates.
+ * Revision 1.19 2003/01/17 15:32:22 mpowers Changes to better support generic
+ * elements and containers. Now preserving newlines in templates.
*
- * Revision 1.17 2003/01/16 22:47:30 mpowers
- * Compatibility changes to support compiling woextensions source.
- * (34 out of 56 classes compile!)
+ * Revision 1.17 2003/01/16 22:47:30 mpowers Compatibility changes to support
+ * compiling woextensions source. (34 out of 56 classes compile!)
*
- * Revision 1.15 2003/01/16 15:50:43 mpowers
- * More robust declaration parsing.
- * Subcomponents are now supported.
- * dynamicElementWithName can now return subcomponents.
+ * Revision 1.15 2003/01/16 15:50:43 mpowers More robust declaration parsing.
+ * Subcomponents are now supported. dynamicElementWithName can now return
+ * subcomponents.
*
- * Revision 1.14 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.14 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.13 2003/01/15 14:33:48 mpowers
- * Refactoring: element id handling is now confined to WOParentElement.
- * Other elements/components should not have to do element id incrementing.
+ * Revision 1.13 2003/01/15 14:33:48 mpowers Refactoring: element id handling is
+ * now confined to WOParentElement. Other elements/components should not have to
+ * do element id incrementing.
*
- * Revision 1.12 2003/01/14 16:05:12 mpowers
- * Removed extraneous printlns.
+ * Revision 1.12 2003/01/14 16:05:12 mpowers Removed extraneous printlns.
*
- * Revision 1.11 2003/01/13 22:24:25 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.11 2003/01/13 22:24:25 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.10 2003/01/10 19:33:28 mpowers
- * Added contextID for the component url generation.
+ * Revision 1.10 2003/01/10 19:33:28 mpowers Added contextID for the component
+ * url generation.
*
- * Revision 1.9 2003/01/10 19:16:40 mpowers
- * Implemented support for page caching.
+ * Revision 1.9 2003/01/10 19:16:40 mpowers Implemented support for page
+ * caching.
*
- * Revision 1.8 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.8 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.7 2003/01/09 16:13:55 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.7 2003/01/09 16:13:55 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.6 2002/12/20 22:56:33 mpowers
- * Reimplemented the template parsing again.
- * Nested components are now correctly parsed.
- * ElementID numbering is now working.
+ * Revision 1.6 2002/12/20 22:56:33 mpowers Reimplemented the template parsing
+ * again. Nested components are now correctly parsed. ElementID numbering is now
+ * working.
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/11/07 18:52:33 mpowers
- * New components courtesy of ezamudio@nasoft.com. Many thanks!
+ * Revision 1.2 2002/11/07 18:52:33 mpowers New components courtesy of
+ * ezamudio@nasoft.com. Many thanks!
*
- * Revision 1.1.1.1 2000/12/21 15:53:01 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:01 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
index 1544934..909212c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentContent.java
@@ -21,25 +21,28 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to include a component's content inside another component. This way, you can create reusable components
- * with content that surrounds the component it's in. In reality all it does is forward the appendToResponse
- * method to the WOElement containing the HTML between the WEBOBJECT tags that define this element.
+ * Used to include a component's content inside another component. This way, you
+ * can create reusable components with content that surrounds the component it's
+ * in. In reality all it does is forward the appendToResponse method to the
+ * WOElement containing the HTML between the WEBOBJECT tags that define this
+ * element.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOComponentContent extends WODynamicElement {
- public WOComponentContent() {
- super();
- }
+ public WOComponentContent() {
+ super();
+ }
- public WOComponentContent(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOComponentContent(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- c.component().rootElement.appendToResponse(r, c);
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ c.component().rootElement.appendToResponse(r, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
index 9f79987..9d35ab4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOComponentRequestHandler.java
@@ -18,212 +18,168 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
-
/**
-* An implementation of WORequestHandler that dispatches Component actions.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOComponentRequestHandler
- extends WORequestHandler
-{
- public WOResponse handleRequest( WORequest aRequest )
- {
- WOApplication application = aRequest.application();
- WOContext context = WOContext.contextWithRequest( aRequest );
- WOResponse response = null;
-
- // no concurrent access is allowed to a user's session:
- // a user/browser/machine with multiple requests will have to wait
- synchronized ( aRequest.request.getSession() )
- {
- try
- {
- application.awake();
-
- WOSession session = null;
- /*
- // the NeXT way
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- if ( session == null )
- {
- response = application.handleSessionRestorationErrorInContext( context );
- }
- }
- else
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
- */
- // the servlet way
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- }
-
- if ( session == null )
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
-
- context.setSession( session );
-
- session.awake();
-
- if ( response == null )
- {
-
- WOComponent page;
- String contextID = aRequest.contextID();
-
- if ( contextID != null )
- {
- page = session.restorePageForContextID( contextID );
- }
- else
- {
- page = application.pageWithName( aRequest.pageName(), context );
- }
-
- if ( page == null )
- {
- //FIXME: should we call this a restoration error, or do we
- // allow a bookmark with an expired context id to resume gracefully?
- page = application.pageWithName( aRequest.pageName(), context );
- //!response = application.handlePageRestorationErrorInContext( context );
- }
- //!else
- {
- context.pushElement( page ); //? needed?
- page.ensureAwakeInContext( context ); //? shouldn't this be in WOApplication?
-
- // only take values from request if there are values in the request
- System.out.println("should I takeValuesFromRequest ? " + ( aRequest.formValueKeys().count() > 0 ));
- if ( aRequest.formValueKeys().count() > 0 )
- {
- application.takeValuesFromRequest( aRequest, context );
- }
-
- // only invoke action if there is a sender id to invoke
- WOActionResults result;
- System.out.println("senderID: " + aRequest.senderID());
- if ( aRequest.senderID() != null )
- {
- result = application.invokeAction( aRequest, context );
- }
- else
- {
- result = null;
- }
-
- if ( result == null || result == page ) // same page is returned
- {
- result = page;
-
- // generate response
- response = new WOResponse();
- application.appendToResponse( response, context );
- page.sleep();
- }
- else // different page is returned
- if ( result instanceof WOComponent )
- {
- page.sleep();
- page = (WOComponent) result;
- page.ensureAwakeInContext( context );
- context.popElement(); // removes page
- context.pushElement( page );
-
- // generate response
- response = new WOResponse();
- application.appendToResponse( response, context );
- page.sleep();
- }
- else // WOResponse was returnd
- {
- response = (WOResponse) result;
- }
-
- context.popElement();
- session.sleep();
- session.savePage( page );
- session.setContext( null );
- application.saveSessionForContext( context );
- }
- }
- }
- catch ( Throwable t )
- {
- response = application.handleException( t, context );
- }
-
- application.sleep();
- }
- return response;
- }
+ * An implementation of WORequestHandler that dispatches Component actions.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOComponentRequestHandler extends WORequestHandler {
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOApplication application = aRequest.application();
+ WOContext context = WOContext.contextWithRequest(aRequest);
+ WOResponse response = null;
+
+ // no concurrent access is allowed to a user's session:
+ // a user/browser/machine with multiple requests will have to wait
+ synchronized (aRequest.request.getSession()) {
+ try {
+ application.awake();
+
+ WOSession session = null;
+ /*
+ * // the NeXT way String sessionID = aRequest.sessionID(); if ( sessionID !=
+ * null ) { session = application.restoreSessionWithID( sessionID, context ); if
+ * ( session == null ) { response =
+ * application.handleSessionRestorationErrorInContext( context ); } } else {
+ * session = application.createSessionForRequest( aRequest ); if ( session ==
+ * null ) { response = application.handleSessionCreationErrorInContext( context
+ * ); } else { session.setContext( context ); } }
+ */
+ // the servlet way
+ String sessionID = aRequest.sessionID();
+ if (sessionID != null) {
+ session = application.restoreSessionWithID(sessionID, context);
+ }
+
+ if (session == null) {
+ session = application.createSessionForRequest(aRequest);
+ if (session == null) {
+ response = application.handleSessionCreationErrorInContext(context);
+ } else {
+ session.setContext(context);
+ }
+ }
+
+ context.setSession(session);
+
+ session.awake();
+
+ if (response == null) {
+
+ WOComponent page;
+ String contextID = aRequest.contextID();
+
+ if (contextID != null) {
+ page = session.restorePageForContextID(contextID);
+ } else {
+ page = application.pageWithName(aRequest.pageName(), context);
+ }
+
+ if (page == null) {
+ // FIXME: should we call this a restoration error, or do we
+ // allow a bookmark with an expired context id to resume gracefully?
+ page = application.pageWithName(aRequest.pageName(), context);
+ // !response = application.handlePageRestorationErrorInContext( context );
+ }
+ // !else
+ {
+ context.pushElement(page); // ? needed?
+ page.ensureAwakeInContext(context); // ? shouldn't this be in WOApplication?
+
+ // only take values from request if there are values in the request
+ System.out
+ .println("should I takeValuesFromRequest ? " + (aRequest.formValueKeys().count() > 0));
+ if (aRequest.formValueKeys().count() > 0) {
+ application.takeValuesFromRequest(aRequest, context);
+ }
+
+ // only invoke action if there is a sender id to invoke
+ WOActionResults result;
+ System.out.println("senderID: " + aRequest.senderID());
+ if (aRequest.senderID() != null) {
+ result = application.invokeAction(aRequest, context);
+ } else {
+ result = null;
+ }
+
+ if (result == null || result == page) // same page is returned
+ {
+ result = page;
+
+ // generate response
+ response = new WOResponse();
+ application.appendToResponse(response, context);
+ page.sleep();
+ } else // different page is returned
+ if (result instanceof WOComponent) {
+ page.sleep();
+ page = (WOComponent) result;
+ page.ensureAwakeInContext(context);
+ context.popElement(); // removes page
+ context.pushElement(page);
+
+ // generate response
+ response = new WOResponse();
+ application.appendToResponse(response, context);
+ page.sleep();
+ } else // WOResponse was returnd
+ {
+ response = (WOResponse) result;
+ }
+
+ context.popElement();
+ session.sleep();
+ session.savePage(page);
+ session.setContext(null);
+ application.saveSessionForContext(context);
+ }
+ }
+ } catch (Throwable t) {
+ response = application.handleException(t, context);
+ }
+
+ application.sleep();
+ }
+ return response;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.8 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.8 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.7 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.7 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.6 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.6 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.4 2003/01/14 15:51:09 mpowers
- * No longer calling takeValues or invokeAction if there are no request params
+ * Revision 1.4 2003/01/14 15:51:09 mpowers No longer calling takeValues or
+ * invokeAction if there are no request params
*
- * Revision 1.3 2003/01/13 22:24:34 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.3 2003/01/13 22:24:34 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.1 2003/01/09 16:13:59 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.1 2003/01/09 16:13:59 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.2 2002/12/17 14:57:44 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:44 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
index 124ca11..d0ab35e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOConditional.java
@@ -21,14 +21,13 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOConditional renders whatever is inside its opening and closing tags
- * only if a condition is met.
- * Bindings are:
+ * WOConditional renders whatever is inside its opening and closing tags only if
+ * a condition is met. Bindings are:
* <ul>
- * <li>condition: a boolean property that indicates whether the contents of the element
- * should be displayed, invoked, or passed the request form values.</li>
- * <li>negate: if this is true, then the behavior of the element is reversed, showing its
- * contents only if the condition is NOT met.</li>
+ * <li>condition: a boolean property that indicates whether the contents of the
+ * element should be displayed, invoked, or passed the request form values.</li>
+ * <li>negate: if this is true, then the behavior of the element is reversed,
+ * showing its contents only if the condition is NOT met.</li>
* </ul>
*
* @author ezamudio@nasoft.com
@@ -37,63 +36,65 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOConditional extends WODynamicElement {
- public boolean condition;
- public boolean negate;
-
- protected WOConditional() {
- super();
- }
-
- public WOConditional(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setCondition(boolean value) {
- condition = value;
- }
- public boolean condition() {
- return condition;
- }
-
- public void setNegate(boolean value) {
- negate = value;
- }
- public boolean negate() {
- return negate;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- condition = booleanForProperty("condition", c);
- negate = booleanForProperty("negate", c);
- }
-
- public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
- if (rootElement == null)
- return;
- pullValuesFromParent(aContext.component());
- if ((condition && !negate) || (!condition && negate)) {
- rootElement.takeValuesFromRequest(aRequest, aContext);
- }
- }
-
- public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
- if (rootElement == null)
- return null;
- pullValuesFromParent(aContext.component());
- WOActionResults el = null;
- if ((condition && !negate) || (!condition && negate)) {
- el = rootElement.invokeAction(aRequest, aContext);
- }
- return el;
- }
-
- public void appendToResponse(WOResponse aResponse, WOContext aContext) {
- if (rootElement == null)
- return;
- pullValuesFromParent(aContext.component());
- if ((condition && !negate) || (!condition && negate)) {
- rootElement.appendToResponse(aResponse, aContext);
- }
- }
+ public boolean condition;
+ public boolean negate;
+
+ protected WOConditional() {
+ super();
+ }
+
+ public WOConditional(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setCondition(boolean value) {
+ condition = value;
+ }
+
+ public boolean condition() {
+ return condition;
+ }
+
+ public void setNegate(boolean value) {
+ negate = value;
+ }
+
+ public boolean negate() {
+ return negate;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ condition = booleanForProperty("condition", c);
+ negate = booleanForProperty("negate", c);
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement == null)
+ return;
+ pullValuesFromParent(aContext.component());
+ if ((condition && !negate) || (!condition && negate)) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ if (rootElement == null)
+ return null;
+ pullValuesFromParent(aContext.component());
+ WOActionResults el = null;
+ if ((condition && !negate) || (!condition && negate)) {
+ el = rootElement.invokeAction(aRequest, aContext);
+ }
+ return el;
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ if (rootElement == null)
+ return;
+ pullValuesFromParent(aContext.component());
+ if ((condition && !negate) || (!condition && negate)) {
+ rootElement.appendToResponse(aResponse, aContext);
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
index 4f774e6..40c5f5c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOContext.java
@@ -25,548 +25,455 @@ import java.util.List;
import java.util.Map;
/**
-* A pure java implementation of WOContext.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOContext
-{
+ * A pure java implementation of WOContext.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOContext {
private WOSession session;
private WORequest request;
private WOResponse response;
- private List elementStack;
+ private List elementStack;
private boolean isInForm;
private boolean isDistributionEnabled;
- private static final String EMPTY = "";
- private static final String SEP = ".";
- private static final String ZERO = "0";
- private static final String HTTP = "http://";
- private static final String HTTPS = "https://";
+ private static final String EMPTY = "";
+ private static final String SEP = ".";
+ private static final String ZERO = "0";
+ private static final String HTTP = "http://";
+ private static final String HTTPS = "https://";
// package access
WOComponent page;
WOComponent component;
StringBuffer elementID;
-
- private static volatile int contextCounter = 0;
- private String contextID;
-
- /**
- * Default constructor performs necessary initialization.
- * Subclassers should override the static factory method below.
- */
- public WOContext ()
- {
- contextID = null;
- elementID = new StringBuffer();
- elementStack = new LinkedList();
- }
-
- /**
- * Preferred constructor performs necessary initialization.
- * Subclassers should override this method.
- */
- public WOContext (WORequest aRequest)
- {
- this();
- request = aRequest;
- response = new WOResponse();
- }
-
- /**
- * Simply calls the preferred constructor.
- * Included for compatibility.
- */
- public static WOContext contextWithRequest (WORequest aRequest)
- {
- String id = Integer.toString( contextCounter++ );
- WOContext result = new WOContext( aRequest );
- result.contextID = id;
- return result;
- }
-
- /**
- * Returns the context id.
- */
- public String contextID ()
- {
- return contextID;
- }
-
- /**
- * Returns the sender id, or null if it doesn't exist.
- */
- public String senderID ()
- {
- return request.senderID();
- }
-
- /**
- * Returns the element id, or null if it doesn't exist.
- */
- public String elementID ()
- {
- return elementID.toString();
- }
-
- /**
- * Returns this context's application, or null if it doesn't exist.
- */
- public WOApplication application ()
- {
- return request.application();
- }
-
- /**
- * Returns whether a session has been created for the associated request.
- */
- public boolean hasSession ()
- {
- return ( session != null );
- }
-
- /**
- * Returns this context's session, creating one if it doesn't exist.
- */
- public WOSession session ()
- {
- if ( session == null )
- {
- // so far we can't figure out how the direct action handler can avoid creating a session
- throw new RuntimeException( "WOContext.session: Lazy instantiation not yet implemented." );
-/*
- session = application().restoreSessionWithID(
- request.sessionID(), this );
- if ( session == null )
- {
- session = application().createSessionForRequest( request );
- session.setContext( this );
- }
-*/
- }
- return session;
- }
-
- /**
- * Package access only.
- */
- void setSession( WOSession aSession )
- {
- session = aSession;
- }
-
- /**
- * Returns this context's request.
- */
- public WORequest request ()
- {
- return request;
- }
-
- /**
- * Returns this context's response.
- */
- public WOResponse response ()
- {
- return response;
- }
-
- /**
- * Returns the current page.
- */
- public WOComponent page ()
- {
- return (WOComponent) elementStack.get( elementStack.size()-1 );
- }
-
- /**
- * Returns the current component.
- */
- public WOComponent component ()
- {
- Object o;
- Iterator i = elementStack.iterator();
- while ( i.hasNext() )
- {
- o = i.next();
- if ( o instanceof WOComponent ) return (WOComponent) o;
- }
- return null;
- }
-
- /**
- * Returns the current component's parent.
- */
- WOComponent parent ()
- {
- Object o;
- Iterator i = elementStack.iterator();
- if ( i.hasNext() )
- {
- // skip current component
- o = i.next();
- }
- while ( i.hasNext() )
- {
- o = i.next();
- if ( o instanceof WOComponent )
- {
- return (WOComponent) o;
- }
- }
- return null;
- }
-
- /**
- * Pushes an element onto the stack.
- * Package access only.
- */
- void pushElement( WOElement aComponent )
- {
- elementStack.add( 0, aComponent );
- }
-
- /**
- * Pops an element off the stack.
- * Package access only.
- */
- WOElement popElement()
- {
- return (WOElement) elementStack.remove(0);
- }
-
- /**
- * Returns whether the current context is in a form.
- */
- public boolean isInForm ()
- {
- return isInForm;
- }
-
- /**
- * Sets whether the current context is in a WOForm.
- */
- public void setInForm (boolean inForm)
- {
- isInForm = inForm;
- }
-
- /**
- * Appends the specified string to the end of the element id.
- * For example, if the element id is "0.1", sending "Test"
- * changes the element id to "0.1.Test".
- */
- public void appendElementIDComponent (String aString)
- {
- if ( elementID.length() > 0 )
- {
- elementID.append( SEP );
- }
- elementID.append( aString );
- }
-
- /**
- * Appends a zero to the element id to represent the first
- * new child component. For example, if the element id is "0.1",
- * calling this changes the element id to "0.1.0".
- */
- public void appendZeroElementIDComponent ()
- {
- if ( elementID.length() > 0 )
- {
- elementID.append( SEP );
- }
- elementID.append( ZERO );
- }
-
- /**
- * Increments the last component of the element id.
- * For example, if the element id is "0.1", calling this
- * changes the element id to "0.2".
- */
- public void incrementLastElementIDComponent ()
- {
- String last;
- String id = elementID.toString();
- int index = id.lastIndexOf( SEP );
- if ( index == -1 )
- {
- last = id;
- }
- else
- {
- last = id.substring( index + 1 );
- }
-
- deleteLastElementIDComponent();
-
- try
- {
- appendElementIDComponent(
- Integer.toString( Integer.parseInt( last ) + 1 ) );
- }
- catch ( Exception exc )
- {
- System.err.println( "Error parsing id: " + last );
- appendZeroElementIDComponent();
- }
- //System.out.println( "WOContext: " + elementID );
- }
-
- /**
- * Deletes the last component of the element id.
- * For example, if the element id is "0.1", callling this
- * changes the element id to "0".
- */
- public void deleteLastElementIDComponent ()
- {
- int index = elementID.toString().lastIndexOf( SEP );
- if ( index == -1 )
- {
- elementID.setLength( 0 );
- }
- else
- {
- elementID.setLength( index );
- }
- }
-
- /**
- * Deletes all components of the element id.
- * This makes the element id an empty string.
- */
- public void deleteAllElementIDComponents ()
- {
- elementID.setLength( 0 );
- }
-
- /**
- * Returns a URL for the named action with query parameters
- * as specified by the dictionary.
- */
- public String directActionURLForActionNamed (
- String anActionName, Map aQueryDict)
- {
- StringBuffer query = new StringBuffer();
-
- try
- {
- String key;
- Iterator i = aQueryDict.keySet().iterator();
- while ( i.hasNext() )
- {
- key = i.next().toString();
- query.append( URI.encode( key,
- URI.allowed_within_query ) );
- query.append( '=' );
- query.append( URI.encode( aQueryDict.get( key ).toString(),
- URI.allowed_within_query ) );
- if ( i.hasNext() )
- {
- query.append( '&' );
- }
- }
- }
- catch ( IOException exc )
- {
- // report error
- System.err.println(
- "directActionURLForActionNamed: " + anActionName + " : " + aQueryDict );
- System.err.println( exc );
-
- // delete query string
- query = new StringBuffer();
- }
-
- return urlWithRequestHandlerKey(
- WOApplication.directActionRequestHandlerKey(),
- anActionName, query.toString() );
- }
-
- /**
- * Returns the complete URL for the current component action.
- */
- public String componentActionURL ()
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( request().applicationName() );
- buffer.append( '/' );
- buffer.append( WOApplication.application().componentRequestHandlerKey() );
- buffer.append( '/' );
- buffer.append( page().name() );
- buffer.append( '/' );
- buffer.append( contextID );
- buffer.append( '/' );
- buffer.append( elementID );
- return buffer.toString();
- }
-
- /**
- * Returns a URL relative to the servlet for the specified
- * request handler, action, and query string.
- */
- public String urlWithRequestHandlerKey (
- String aRequestHandlerKey, String aPath, String aQueryString)
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( request().applicationName() );
- buffer.append( '/' );
- buffer.append( aRequestHandlerKey );
- buffer.append( '/' );
- buffer.append( aPath );
- if ( aQueryString != null && aQueryString.trim().length() > 0 )
- {
- buffer.append( '?' );
- buffer.append( aQueryString );
- }
- return buffer.toString();
- }
-
- /**
- * Returns the complete URL for the specified request handler,
- * path, and query string. isSecure determines the protocol:
- * http or https. port is appended to the protocol, if zero,
- * the port is omitted from the URL.
- */
- public String completeURLWithRequestHandlerKey (
- String aRequestHandlerKey, String aPath, String aQueryString,
- boolean isSecure, int port)
- {
- StringBuffer buffer = new StringBuffer();
-
- if ( isSecure )
- {
- buffer.append( HTTPS );
- }
- else
- {
- buffer.append( HTTP );
- }
-
- buffer.append( request.applicationHost() );
-
- if ( port != 0 && port != 80 )
- {
- buffer.append( ':' );
- buffer.append( Integer.toString( port ) );
- }
-
- buffer.append( urlWithRequestHandlerKey(
- aRequestHandlerKey, aPath, aQueryString ) );
-
- return buffer.toString();
- }
-
- /**
- * Sets whether distribution is enabled.
- */
- public void setDistributionEnabled (boolean distributionEnabled)
- {
- isDistributionEnabled = distributionEnabled;
- }
-
- /**
- * Returns whether distribution is enabled.
- */
- public boolean isDistributionEnabled ()
- {
- return isDistributionEnabled;
- }
-
- /**
- * This method is not included in the WOContext specification.
- * This implementation returns "" since only cookie ids are
- * currently supported.
- */
- String urlSessionPrefix ()
- {
- return EMPTY; // "/" + sessionid;
- }
-
- /**
- * Returns the relative URL for the current page.
- */
- String url ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public String toString()
- {
- return "[WOContext@"+Integer.toHexString(System.identityHashCode(this))
- +":id=" + contextID +":page=" + page + ":component=" + component + ":element=" + elementID + "]";
- }
+
+ private static volatile int contextCounter = 0;
+ private String contextID;
+
+ /**
+ * Default constructor performs necessary initialization. Subclassers should
+ * override the static factory method below.
+ */
+ public WOContext() {
+ contextID = null;
+ elementID = new StringBuffer();
+ elementStack = new LinkedList();
+ }
+
+ /**
+ * Preferred constructor performs necessary initialization. Subclassers should
+ * override this method.
+ */
+ public WOContext(WORequest aRequest) {
+ this();
+ request = aRequest;
+ response = new WOResponse();
+ }
+
+ /**
+ * Simply calls the preferred constructor. Included for compatibility.
+ */
+ public static WOContext contextWithRequest(WORequest aRequest) {
+ String id = Integer.toString(contextCounter++);
+ WOContext result = new WOContext(aRequest);
+ result.contextID = id;
+ return result;
+ }
+
+ /**
+ * Returns the context id.
+ */
+ public String contextID() {
+ return contextID;
+ }
+
+ /**
+ * Returns the sender id, or null if it doesn't exist.
+ */
+ public String senderID() {
+ return request.senderID();
+ }
+
+ /**
+ * Returns the element id, or null if it doesn't exist.
+ */
+ public String elementID() {
+ return elementID.toString();
+ }
+
+ /**
+ * Returns this context's application, or null if it doesn't exist.
+ */
+ public WOApplication application() {
+ return request.application();
+ }
+
+ /**
+ * Returns whether a session has been created for the associated request.
+ */
+ public boolean hasSession() {
+ return (session != null);
+ }
+
+ /**
+ * Returns this context's session, creating one if it doesn't exist.
+ */
+ public WOSession session() {
+ if (session == null) {
+ // so far we can't figure out how the direct action handler can avoid creating a
+ // session
+ throw new RuntimeException("WOContext.session: Lazy instantiation not yet implemented.");
+ /*
+ * session = application().restoreSessionWithID( request.sessionID(), this ); if
+ * ( session == null ) { session = application().createSessionForRequest(
+ * request ); session.setContext( this ); }
+ */
+ }
+ return session;
+ }
+
+ /**
+ * Package access only.
+ */
+ void setSession(WOSession aSession) {
+ session = aSession;
+ }
+
+ /**
+ * Returns this context's request.
+ */
+ public WORequest request() {
+ return request;
+ }
+
+ /**
+ * Returns this context's response.
+ */
+ public WOResponse response() {
+ return response;
+ }
+
+ /**
+ * Returns the current page.
+ */
+ public WOComponent page() {
+ return (WOComponent) elementStack.get(elementStack.size() - 1);
+ }
+
+ /**
+ * Returns the current component.
+ */
+ public WOComponent component() {
+ Object o;
+ Iterator i = elementStack.iterator();
+ while (i.hasNext()) {
+ o = i.next();
+ if (o instanceof WOComponent)
+ return (WOComponent) o;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the current component's parent.
+ */
+ WOComponent parent() {
+ Object o;
+ Iterator i = elementStack.iterator();
+ if (i.hasNext()) {
+ // skip current component
+ o = i.next();
+ }
+ while (i.hasNext()) {
+ o = i.next();
+ if (o instanceof WOComponent) {
+ return (WOComponent) o;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Pushes an element onto the stack. Package access only.
+ */
+ void pushElement(WOElement aComponent) {
+ elementStack.add(0, aComponent);
+ }
+
+ /**
+ * Pops an element off the stack. Package access only.
+ */
+ WOElement popElement() {
+ return (WOElement) elementStack.remove(0);
+ }
+
+ /**
+ * Returns whether the current context is in a form.
+ */
+ public boolean isInForm() {
+ return isInForm;
+ }
+
+ /**
+ * Sets whether the current context is in a WOForm.
+ */
+ public void setInForm(boolean inForm) {
+ isInForm = inForm;
+ }
+
+ /**
+ * Appends the specified string to the end of the element id. For example, if
+ * the element id is "0.1", sending "Test" changes the element id to "0.1.Test".
+ */
+ public void appendElementIDComponent(String aString) {
+ if (elementID.length() > 0) {
+ elementID.append(SEP);
+ }
+ elementID.append(aString);
+ }
+
+ /**
+ * Appends a zero to the element id to represent the first new child component.
+ * For example, if the element id is "0.1", calling this changes the element id
+ * to "0.1.0".
+ */
+ public void appendZeroElementIDComponent() {
+ if (elementID.length() > 0) {
+ elementID.append(SEP);
+ }
+ elementID.append(ZERO);
+ }
+
+ /**
+ * Increments the last component of the element id. For example, if the element
+ * id is "0.1", calling this changes the element id to "0.2".
+ */
+ public void incrementLastElementIDComponent() {
+ String last;
+ String id = elementID.toString();
+ int index = id.lastIndexOf(SEP);
+ if (index == -1) {
+ last = id;
+ } else {
+ last = id.substring(index + 1);
+ }
+
+ deleteLastElementIDComponent();
+
+ try {
+ appendElementIDComponent(Integer.toString(Integer.parseInt(last) + 1));
+ } catch (Exception exc) {
+ System.err.println("Error parsing id: " + last);
+ appendZeroElementIDComponent();
+ }
+ // System.out.println( "WOContext: " + elementID );
+ }
+
+ /**
+ * Deletes the last component of the element id. For example, if the element id
+ * is "0.1", callling this changes the element id to "0".
+ */
+ public void deleteLastElementIDComponent() {
+ int index = elementID.toString().lastIndexOf(SEP);
+ if (index == -1) {
+ elementID.setLength(0);
+ } else {
+ elementID.setLength(index);
+ }
+ }
+
+ /**
+ * Deletes all components of the element id. This makes the element id an empty
+ * string.
+ */
+ public void deleteAllElementIDComponents() {
+ elementID.setLength(0);
+ }
+
+ /**
+ * Returns a URL for the named action with query parameters as specified by the
+ * dictionary.
+ */
+ public String directActionURLForActionNamed(String anActionName, Map aQueryDict) {
+ StringBuffer query = new StringBuffer();
+
+ try {
+ String key;
+ Iterator i = aQueryDict.keySet().iterator();
+ while (i.hasNext()) {
+ key = i.next().toString();
+ query.append(URI.encode(key, URI.allowed_within_query));
+ query.append('=');
+ query.append(URI.encode(aQueryDict.get(key).toString(), URI.allowed_within_query));
+ if (i.hasNext()) {
+ query.append('&');
+ }
+ }
+ } catch (IOException exc) {
+ // report error
+ System.err.println("directActionURLForActionNamed: " + anActionName + " : " + aQueryDict);
+ System.err.println(exc);
+
+ // delete query string
+ query = new StringBuffer();
+ }
+
+ return urlWithRequestHandlerKey(WOApplication.directActionRequestHandlerKey(), anActionName, query.toString());
+ }
+
+ /**
+ * Returns the complete URL for the current component action.
+ */
+ public String componentActionURL() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(request().applicationName());
+ buffer.append('/');
+ buffer.append(WOApplication.application().componentRequestHandlerKey());
+ buffer.append('/');
+ buffer.append(page().name());
+ buffer.append('/');
+ buffer.append(contextID);
+ buffer.append('/');
+ buffer.append(elementID);
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a URL relative to the servlet for the specified request handler,
+ * action, and query string.
+ */
+ public String urlWithRequestHandlerKey(String aRequestHandlerKey, String aPath, String aQueryString) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(request().applicationName());
+ buffer.append('/');
+ buffer.append(aRequestHandlerKey);
+ buffer.append('/');
+ buffer.append(aPath);
+ if (aQueryString != null && aQueryString.trim().length() > 0) {
+ buffer.append('?');
+ buffer.append(aQueryString);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the complete URL for the specified request handler, path, and query
+ * string. isSecure determines the protocol: http or https. port is appended to
+ * the protocol, if zero, the port is omitted from the URL.
+ */
+ public String completeURLWithRequestHandlerKey(String aRequestHandlerKey, String aPath, String aQueryString,
+ boolean isSecure, int port) {
+ StringBuffer buffer = new StringBuffer();
+
+ if (isSecure) {
+ buffer.append(HTTPS);
+ } else {
+ buffer.append(HTTP);
+ }
+
+ buffer.append(request.applicationHost());
+
+ if (port != 0 && port != 80) {
+ buffer.append(':');
+ buffer.append(Integer.toString(port));
+ }
+
+ buffer.append(urlWithRequestHandlerKey(aRequestHandlerKey, aPath, aQueryString));
+
+ return buffer.toString();
+ }
+
+ /**
+ * Sets whether distribution is enabled.
+ */
+ public void setDistributionEnabled(boolean distributionEnabled) {
+ isDistributionEnabled = distributionEnabled;
+ }
+
+ /**
+ * Returns whether distribution is enabled.
+ */
+ public boolean isDistributionEnabled() {
+ return isDistributionEnabled;
+ }
+
+ /**
+ * This method is not included in the WOContext specification. This
+ * implementation returns "" since only cookie ids are currently supported.
+ */
+ String urlSessionPrefix() {
+ return EMPTY; // "/" + sessionid;
+ }
+
+ /**
+ * Returns the relative URL for the current page.
+ */
+ String url() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public String toString() {
+ return "[WOContext@" + Integer.toHexString(System.identityHashCode(this)) + ":id=" + contextID + ":page=" + page
+ + ":component=" + component + ":element=" + elementID + "]";
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.19 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.19 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.18 2003/02/21 16:40:23 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.18 2003/02/21 16:40:23 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.17 2003/01/24 20:12:54 mpowers
- * Better parent determination.
+ * Revision 1.17 2003/01/24 20:12:54 mpowers Better parent determination.
*
- * Revision 1.16 2003/01/21 22:27:02 mpowers
- * Corrected context id usage.
+ * Revision 1.16 2003/01/21 22:27:02 mpowers Corrected context id usage.
* Implemented backtracking.
*
- * Revision 1.15 2003/01/17 20:58:19 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.15 2003/01/17 20:58:19 mpowers Fixed up WOHyperlink.
*
- * Revision 1.14 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.14 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.13 2003/01/14 19:48:36 mpowers
- * - fixes to property synchronization
- * - forms now pass takeValuesFromRequest to children
- * - fixes to action invocation
- * - now supporting multipleSubmit in forms
+ * Revision 1.13 2003/01/14 19:48:36 mpowers - fixes to property synchronization
+ * - forms now pass takeValuesFromRequest to children - fixes to action
+ * invocation - now supporting multipleSubmit in forms
*
- * Revision 1.12 2003/01/13 22:24:44 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.12 2003/01/13 22:24:44 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.11 2003/01/10 20:17:41 mpowers
- * Component action urls are now working.
+ * Revision 1.11 2003/01/10 20:17:41 mpowers Component action urls are now
+ * working.
*
- * Revision 1.8 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.8 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.7 2003/01/09 16:13:59 mpowers
- * Implemented WOComponentRequestHandler:
- * Bringing the request-response cycle more into conformance.
+ * Revision 1.7 2003/01/09 16:13:59 mpowers Implemented
+ * WOComponentRequestHandler: Bringing the request-response cycle more into
+ * conformance.
*
- * Revision 1.4 2002/12/20 22:56:33 mpowers
- * Reimplemented the template parsing again.
- * Nested components are now correctly parsed.
- * ElementID numbering is now working.
+ * Revision 1.4 2002/12/20 22:56:33 mpowers Reimplemented the template parsing
+ * again. Nested components are now correctly parsed. ElementID numbering is now
+ * working.
*
- * Revision 1.3 2002/12/18 14:12:38 mpowers
- * Support for differentiated request handlers.
- * Support url generation for WOContext and WORequest.
+ * Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
+ * handlers. Support url generation for WOContext and WORequest.
*
- * Revision 1.2 2002/12/17 14:57:42 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:42 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers Contributing wotonomy.
*
- * Revision 1.3 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.3 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
index 78427f0..4c5f498 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOCookie.java
@@ -21,183 +21,159 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDate;
/**
-* A pure java implementation of WOCookie that extends
-* javax.servlet.httpd.Cookie for greater compatibility.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOCookie
- extends javax.servlet.http.Cookie
-{
- /**
- * Default constructor.
- */
- public WOCookie ()
- {
- super( "", "" );
- }
-
- /**
- * Constructs a cookie with the specified name and value.
- */
- public WOCookie( String aName, String aValue )
- {
- super( aName, aValue );
- }
-
- /**
- * Constructs a cookie with the specified name and value.
- * Also sets the path to the current application's path.
- */
- public static WOCookie cookieWithName (String aName, String aValue)
- {
- WOCookie result = new WOCookie( aName, aValue );
- //TODO: Set the path to the current application's path.
- return result;
- }
-
- /**
- * Constructs a cookie with the specified attributes.
- */
- public static WOCookie cookieWithName (String aName, String aValue,
- String aPath, String aDomain, NSDate expirationDate, boolean secure)
- {
- WOCookie result = new WOCookie( aName, aValue );
- result.setPath( aPath );
- result.setDomain( aDomain );
- result.setExpires( expirationDate );
- result.setSecure( secure );
+ * A pure java implementation of WOCookie that extends
+ * javax.servlet.httpd.Cookie for greater compatibility.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOCookie extends javax.servlet.http.Cookie {
+ /**
+ * Default constructor.
+ */
+ public WOCookie() {
+ super("", "");
+ }
+
+ /**
+ * Constructs a cookie with the specified name and value.
+ */
+ public WOCookie(String aName, String aValue) {
+ super(aName, aValue);
+ }
+
+ /**
+ * Constructs a cookie with the specified name and value. Also sets the path to
+ * the current application's path.
+ */
+ public static WOCookie cookieWithName(String aName, String aValue) {
+ WOCookie result = new WOCookie(aName, aValue);
+ // TODO: Set the path to the current application's path.
+ return result;
+ }
+
+ /**
+ * Constructs a cookie with the specified attributes.
+ */
+ public static WOCookie cookieWithName(String aName, String aValue, String aPath, String aDomain,
+ NSDate expirationDate, boolean secure) {
+ WOCookie result = new WOCookie(aName, aValue);
+ result.setPath(aPath);
+ result.setDomain(aDomain);
+ result.setExpires(expirationDate);
+ result.setSecure(secure);
return result;
}
-
- /**
- * Returns the name of the cookie.
- */
- public String name ()
- {
- return this.getName();
- }
-
- /**
- * Sets the name of the cookie.
- */
- public void setName (String aString)
- {
- // super.setName( aString );
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Returns the value of the cookie.
- */
- public String value ()
- {
- return this.getValue();
- }
-
- /**
- * Sets the value of the cookie.
- */
- public void setValue (String aString)
- {
- super.setValue( aString );
- }
-
- /**
- * Gets the domain of the cookie.
- */
- public String domain ()
- {
- return this.getDomain();
- }
-
- /**
- * Sets the domain of the cookie.
- */
- public void setDomain (String aString)
- {
- super.setDomain( aString );
- }
-
- /**
- * Gets the path of the cookie.
- */
- public String path ()
- {
- return this.getPath();
- }
-
- /**
- * Sets the path of the cookie.
- */
- public void setPath (String aString)
- {
- super.setPath( aString );
- }
-
- /**
- * Gets the expiration date of the cookie.
- * If in the past, the cookie will persist until browser shutdown.
- */
- public NSDate expires ()
- {
- return new NSDate( this.getMaxAge() );
- }
-
- /**
- * Sets the expiration date of the cookie.
- */
- public void setExpires (NSDate aDate)
- {
- this.setMaxAge( (int) aDate.timeIntervalSinceNow() );
- }
-
- /**
- * Returns whether the cookie will only be sent over a secure protocol.
- */
- public boolean isSecure ()
- {
- return this.getSecure();
- }
-
- /**
- * Sets whether the cookie will only be sent over a secure protocol.
- */
- public void setIsSecure (boolean isSecure)
- {
- this.setSecure( isSecure );
- }
-
- /**
- * Returns the string as it appears in the HTTP header of the response.
- * This would normally be called by WOResponse, but is handled automatically
- * by the servlet implementation.
- */
- public String headerString ()
- {
- new RuntimeException( "Not implemented yet." );
- return null;
- }
+
+ /**
+ * Returns the name of the cookie.
+ */
+ public String name() {
+ return this.getName();
+ }
+
+ /**
+ * Sets the name of the cookie.
+ */
+ public void setName(String aString) {
+ // super.setName( aString );
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the value of the cookie.
+ */
+ public String value() {
+ return this.getValue();
+ }
+
+ /**
+ * Sets the value of the cookie.
+ */
+ public void setValue(String aString) {
+ super.setValue(aString);
+ }
+
+ /**
+ * Gets the domain of the cookie.
+ */
+ public String domain() {
+ return this.getDomain();
+ }
+
+ /**
+ * Sets the domain of the cookie.
+ */
+ public void setDomain(String aString) {
+ super.setDomain(aString);
+ }
+
+ /**
+ * Gets the path of the cookie.
+ */
+ public String path() {
+ return this.getPath();
+ }
+
+ /**
+ * Sets the path of the cookie.
+ */
+ public void setPath(String aString) {
+ super.setPath(aString);
+ }
+
+ /**
+ * Gets the expiration date of the cookie. If in the past, the cookie will
+ * persist until browser shutdown.
+ */
+ public NSDate expires() {
+ return new NSDate(this.getMaxAge());
+ }
+
+ /**
+ * Sets the expiration date of the cookie.
+ */
+ public void setExpires(NSDate aDate) {
+ this.setMaxAge((int) aDate.timeIntervalSinceNow());
+ }
+
+ /**
+ * Returns whether the cookie will only be sent over a secure protocol.
+ */
+ public boolean isSecure() {
+ return this.getSecure();
+ }
+
+ /**
+ * Sets whether the cookie will only be sent over a secure protocol.
+ */
+ public void setIsSecure(boolean isSecure) {
+ this.setSecure(isSecure);
+ }
+
+ /**
+ * Returns the string as it appears in the HTTP header of the response. This
+ * would normally be called by WOResponse, but is handled automatically by the
+ * servlet implementation.
+ */
+ public String headerString() {
+ new RuntimeException("Not implemented yet.");
+ return null;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:04 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
index 09d0131..08b591f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectAction.java
@@ -29,289 +29,241 @@ import net.wotonomy.foundation.internal.Introspector;
import net.wotonomy.foundation.internal.ValueConverter;
/**
-* A pure java implementation of WODirectAction.
-* This class provides a number of services to subclasses,
-* including access to the query parameters, the request,
-* the session, and logging and debugging facilities.
-* A new instance of the class is created and then destroyed
-* for every request-response cycle.<br><br>
-*
-* Subclass this to implement direct actions for your
-* application. Subclasses would typically override the
-* constructor to initialize state based on the request,
-* and then provide additional methods that would be invoked
-* based on the value at the end of the URI. <br><br>
-*
-* Example: "http://www/MyApp.woa/MyActions/search" would call
-* the method named "searchAction" on the DirectAction subclass
-* named "MyActions". If the subclass name is omitted, a subclass
-* named "DirectAction" is assumed to exist within the application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODirectAction
-{
+ * A pure java implementation of WODirectAction. This class provides a number of
+ * services to subclasses, including access to the query parameters, the
+ * request, the session, and logging and debugging facilities. A new instance of
+ * the class is created and then destroyed for every request-response cycle.<br>
+ * <br>
+ *
+ * Subclass this to implement direct actions for your application. Subclasses
+ * would typically override the constructor to initialize state based on the
+ * request, and then provide additional methods that would be invoked based on
+ * the value at the end of the URI. <br>
+ * <br>
+ *
+ * Example: "http://www/MyApp.woa/MyActions/search" would call the method named
+ * "searchAction" on the DirectAction subclass named "MyActions". If the
+ * subclass name is omitted, a subclass named "DirectAction" is assumed to exist
+ * within the application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODirectAction {
private WORequest request;
- WOContext context;
+ WOContext context;
/**
- * Default constructor. This is called implicitly by
- * subclasses in all cases. Package access only.
- */
- WODirectAction ()
- {
-
- }
+ * Default constructor. This is called implicitly by subclasses in all cases.
+ * Package access only.
+ */
+ WODirectAction() {
+
+ }
/**
- * Request constructor. This is the constructor used
- * to create an action in response to a user request.
- * Override to perform any necessary initialization in
- * your subclass.
- */
- public WODirectAction (WORequest aRequest)
- {
- this();
- request = aRequest;
- }
+ * Request constructor. This is the constructor used to create an action in
+ * response to a user request. Override to perform any necessary initialization
+ * in your subclass.
+ */
+ public WODirectAction(WORequest aRequest) {
+ this();
+ request = aRequest;
+ }
- /**
- * Returns the response from the component named "Main".
- */
- public WOActionResults defaultAction()
- {
- return pageWithName("Main").generateResponse();
- }
-
/**
- * Returns the WORequest object for the current request.
- */
- public WORequest request ()
- {
- return request;
- }
+ * Returns the response from the component named "Main".
+ */
+ public WOActionResults defaultAction() {
+ return pageWithName("Main").generateResponse();
+ }
/**
- * Returns the existing session, or null if no session exists.
- */
- public WOSession existingSession ()
- {
- //FIXME: this is incorrect
- HttpSession session = request.servletRequest().getSession();
- if ( session == null ) return null;
- WOSession wosession = new WOSession();
- wosession.setServletSession( session );
- return wosession;
- }
+ * Returns the WORequest object for the current request.
+ */
+ public WORequest request() {
+ return request;
+ }
/**
- * Returns the existing session if it exists. If no session
- * exists, returns a newly created session. Note that if the
- * user client does not support session ids/cookies, this will
- * create a new session with each request.
- */
- public WOSession session ()
- {
- //FIXME: this is incorrect
- WOSession wosession = new WOSession();
- wosession.setServletSession(
- request.servletRequest().getSession( true ) );
- return wosession;
- }
+ * Returns the existing session, or null if no session exists.
+ */
+ public WOSession existingSession() {
+ // FIXME: this is incorrect
+ HttpSession session = request.servletRequest().getSession();
+ if (session == null)
+ return null;
+ WOSession wosession = new WOSession();
+ wosession.setServletSession(session);
+ return wosession;
+ }
/**
- * Returns the named WOComponent.
- */
- public WOComponent pageWithName (String aString)
- {
- return request.application().pageWithName( aString, context );
- }
+ * Returns the existing session if it exists. If no session exists, returns a
+ * newly created session. Note that if the user client does not support session
+ * ids/cookies, this will create a new session with each request.
+ */
+ public WOSession session() {
+ // FIXME: this is incorrect
+ WOSession wosession = new WOSession();
+ wosession.setServletSession(request.servletRequest().getSession(true));
+ return wosession;
+ }
/**
- * Appends "Action" to the specified string and tries to invoke
- * method with that name and no arguments. Returns null if
- * the method does not exist. If anAction is null, "defaultAction"
- * will be assumed.
- */
- public WOActionResults performActionNamed (String anAction)
- {
- if ( anAction == null ) anAction = "default";
- try
- {
- NSSelector sel = new NSSelector( anAction+"Action" );
- return (WOActionResults) sel.invoke( this );
- }
- catch ( NoSuchMethodException exc )
- {
+ * Returns the named WOComponent.
+ */
+ public WOComponent pageWithName(String aString) {
+ return request.application().pageWithName(aString, context);
+ }
+
+ /**
+ * Appends "Action" to the specified string and tries to invoke method with that
+ * name and no arguments. Returns null if the method does not exist. If anAction
+ * is null, "defaultAction" will be assumed.
+ */
+ public WOActionResults performActionNamed(String anAction) {
+ if (anAction == null)
+ anAction = "default";
+ try {
+ NSSelector sel = new NSSelector(anAction + "Action");
+ return (WOActionResults) sel.invoke(this);
+ } catch (NoSuchMethodException exc) {
// returns below
- }
- catch ( InvocationTargetException exc )
- {
+ } catch (InvocationTargetException exc) {
Throwable e = exc.getTargetException();
- exc.printStackTrace();
- throw new RuntimeException( e.toString() );
- }
- catch ( Exception exc )
- {
- exc.printStackTrace();
- throw new RuntimeException( exc.toString() );
+ exc.printStackTrace();
+ throw new RuntimeException(e.toString());
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ throw new RuntimeException(exc.toString());
}
- WOResponse error = new WOResponse();
- error.setStatus( 404 ); // not found
- error.appendContentString(
- "Could not find method named \"" + anAction + "Action\"." );
- return error;
- }
+ WOResponse error = new WOResponse();
+ error.setStatus(404); // not found
+ error.appendContentString("Could not find method named \"" + anAction + "Action\".");
+ return error;
+ }
/**
- * Assigns the arrays of form values for the specified keys
- * to properties on this object with matching names whose type
- * is NSArray or is convertable from a Collection.
- */
- public void takeFormValueArraysForKeyArray (NSArray anArray)
- {
- if ( anArray == null ) return;
-
- Method m;
- Object key;
- Object value;
- java.util.Enumeration e = anArray.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.formValuesForKey( key.toString() );
- try
- {
- // obtain setter method for this class
- m = Introspector.getPropertyWriteMethod(
- this.getClass(), key.toString(),
- new Class[] { Introspector.WILD } );
- if ( m != null )
- {
- // if value isn't null, try to convert it to type
- if ( value != null )
- {
- Class[] paramTypes = m.getParameterTypes();
- if ( ! paramTypes[0].isAssignableFrom(
- value.getClass() ) )
- {
- //TODO: find a constructor whose parameter
- // is assignable from value.getClass()
- // and instantiate it in the place of value.
+ * Assigns the arrays of form values for the specified keys to properties on
+ * this object with matching names whose type is NSArray or is convertable from
+ * a Collection.
+ */
+ public void takeFormValueArraysForKeyArray(NSArray anArray) {
+ if (anArray == null)
+ return;
+
+ Method m;
+ Object key;
+ Object value;
+ java.util.Enumeration e = anArray.objectEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.formValuesForKey(key.toString());
+ try {
+ // obtain setter method for this class
+ m = Introspector.getPropertyWriteMethod(this.getClass(), key.toString(),
+ new Class[] { Introspector.WILD });
+ if (m != null) {
+ // if value isn't null, try to convert it to type
+ if (value != null) {
+ Class[] paramTypes = m.getParameterTypes();
+ if (!paramTypes[0].isAssignableFrom(value.getClass())) {
+ // TODO: find a constructor whose parameter
+ // is assignable from value.getClass()
+ // and instantiate it in the place of value.
}
- }
- // set property to value
- m.invoke( this, new Object[] { value } );
- }
- }
- catch ( Exception exc )
- {
- // show error and continue
- debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
- }
+ }
+ // set property to value
+ m.invoke(this, new Object[] { value });
+ }
+ } catch (Exception exc) {
+ // show error and continue
+ debugString("WODirectAction.takeFormValuesForKeyArray: " + exc);
+ }
}
-
- }
+
+ }
/**
- * Assigns the form values for the specified keys to properties
- * on this object with matching names.
- */
- public void takeFormValuesForKeyArray (NSArray anArray)
- {
- if ( anArray == null ) return;
-
- Method m;
- Object key;
- Object value;
- java.util.Enumeration e = anArray.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.formValueForKey( key.toString() );
- try
- {
- // obtain setter method for this class
- m = Introspector.getPropertyWriteMethod(
- this.getClass(), key.toString(),
- new Class[] { Introspector.WILD } );
- if ( m != null )
- {
- // if value isn't null, try to convert it to type
- if ( value != null )
- {
- Class[] paramTypes = m.getParameterTypes();
- Object convertedValue =
- ValueConverter.convertObjectToClass(
- value, paramTypes[0] );
- if ( convertedValue != null )
- {
- value = convertedValue;
- }
- }
- // set property to value
- m.invoke( this, new Object[] { value } );
- }
- }
- catch ( Exception exc )
- {
- // show error and continue
- debugString( "WODirectAction.takeFormValuesForKeyArray: " + exc );
- }
+ * Assigns the form values for the specified keys to properties on this object
+ * with matching names.
+ */
+ public void takeFormValuesForKeyArray(NSArray anArray) {
+ if (anArray == null)
+ return;
+
+ Method m;
+ Object key;
+ Object value;
+ java.util.Enumeration e = anArray.objectEnumerator();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.formValueForKey(key.toString());
+ try {
+ // obtain setter method for this class
+ m = Introspector.getPropertyWriteMethod(this.getClass(), key.toString(),
+ new Class[] { Introspector.WILD });
+ if (m != null) {
+ // if value isn't null, try to convert it to type
+ if (value != null) {
+ Class[] paramTypes = m.getParameterTypes();
+ Object convertedValue = ValueConverter.convertObjectToClass(value, paramTypes[0]);
+ if (convertedValue != null) {
+ value = convertedValue;
+ }
+ }
+ // set property to value
+ m.invoke(this, new Object[] { value });
+ }
+ } catch (Exception exc) {
+ // show error and continue
+ debugString("WODirectAction.takeFormValuesForKeyArray: " + exc);
+ }
}
-
- }
+
+ }
/**
- * Writes a message to the standard error stream.
- */
- public static void logString (String aString)
- {
- System.err.println( aString );
- }
+ * Writes a message to the standard error stream.
+ */
+ public static void logString(String aString) {
+ System.err.println(aString);
+ }
/**
- * Writes a message to the standard error stream
- * if debugging is activated.
- */
- public static void debugString (String aString)
- {
- // TODO: Check to see if debugging is enabled.
- System.err.println( aString );
- }
+ * Writes a message to the standard error stream if debugging is activated.
+ */
+ public static void debugString(String aString) {
+ // TODO: Check to see if debugging is enabled.
+ System.err.println(aString);
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/01/13 22:24:51 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.5 2003/01/13 22:24:51 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.4 2003/01/09 21:16:48 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.4 2003/01/09 21:16:48 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.3 2003/01/07 15:58:11 mpowers
- * Implementing the request-response cycle.
- * WOSession refactored to support distribution.
+ * Revision 1.3 2003/01/07 15:58:11 mpowers Implementing the request-response
+ * cycle. WOSession refactored to support distribution.
*
- * Revision 1.2 2002/12/17 14:57:43 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:43 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:18 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:18 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
index eac826b..228f387 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODirectActionRequestHandler.java
@@ -21,201 +21,161 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSArray;
/**
-* An implementation of WORequestHandler that dispatches
-* DirectActions. <br><br>
-*
-* See WODirectAction for the rules for parsing a request.
-* In short, className defaults to "DirectAction", and the
-* action defaults to "default". The action class is expected
-* to have a constructor that takes a WORequest parameter.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODirectActionRequestHandler
- extends WORequestHandler
-{
- public WOResponse handleRequest (WORequest aRequest)
- {
- WOResponse response = null;
-
- // no concurrent access is allowed to a user's session:
- // a user/browser/machine with multiple requests will have to wait.
- // NOTE: this forces a session creation for any direct action (!)
- synchronized ( aRequest.request.getSession() )
- {
- WOApplication application = aRequest.application();
- WOContext context = WOContext.contextWithRequest( aRequest );
-
- String className = "DirectAction";
- String actionName = "default";
- NSArray path = aRequest.requestHandlerPathArray();
- if ( path.count() > 0 )
- {
- className = path.objectAtIndex( 0 ).toString();
- if ( path.count() > 1 )
- {
- actionName = path.objectAtIndex( path.count() - 1 ).toString();
- }
- if ( path.count() > 2 )
- {
- for ( int i = 1; i < path.count()-1; i++ )
- {
- className = className + "." +
- path.objectAtIndex( i ).toString();
- }
- }
- }
-
- //FIXME: sessions are supposed to be lazily created for direct actions
-
- WOSession session = null;
-
- String sessionID = aRequest.sessionID();
- if ( sessionID != null )
- {
- session = application.restoreSessionWithID( sessionID, context );
- }
-
- if ( session == null )
- {
- session = application.createSessionForRequest( aRequest );
- if ( session == null )
- {
- response = application.handleSessionCreationErrorInContext( context );
- }
- else
- {
- session.setContext( context );
- }
- }
-
- context.setSession( session );
-
- application.awake();
- session.awake();
-
- try
- {
-
- if ( response == null )
- {
- Class c = null;
- c = application.getLocalClass( className );
- if ( ( c == null ) && ( path.count() == 1 ) )
- {
- actionName = className;
- className = "DirectAction";
- c = application.getLocalClass( className );
- }
- if ( c == null )
- {
- throw new RuntimeException(
- "Could not find class named \"" + className
- + "\": " );
- }
- java.lang.reflect.Constructor ctor =
- c.getConstructor( new Class[] { WORequest.class } );
-
- WODirectAction action = (WODirectAction)
- ctor.newInstance( new Object[] { aRequest } );
- action.context = context; //HACK: how else can action call pageWithName?
-
- WOActionResults result = action.performActionNamed( actionName );
- if ( result instanceof WOComponent )
- {
- //HACK: I'm not sure where this should have gone: seems hackish here.
- context.pushElement( (WOComponent) result );
- ((WOComponent)result).ensureAwakeInContext( context );
- //context.popElement();
- }
- response = result.generateResponse(); // calls session.savePage (?)
- if ( result instanceof WOComponent )
- {
- //HACK: I'm not sure where this should have gone: seems hackish here.
- ((WOComponent)result).sleep();
- }
- }
- }
- catch ( NoSuchMethodException exc )
- {
- WOResponse error = new WOResponse();
- exc.printStackTrace();
- error.setStatus( 404 ); // not found
- error.appendContentString(
- "Could not find request constructor for class named \""
- + className + "\": " );
- response = error;
- }
- catch ( Exception exc )
- {
- WOResponse error = new WOResponse();
- error.setStatus( 500 ); // error
- if ( exc.getMessage() != null )
- {
- error.appendContentString( exc.getMessage() );
- exc.printStackTrace();
- }
- else
- {
- error.appendContentString( exc.toString() );
- exc.printStackTrace();
- }
- response = error;
- }
-
- session.sleep();
- session.setContext( null );
- application.saveSessionForContext( context );
- application.sleep();
- }
- return response;
- }
-
+ * An implementation of WORequestHandler that dispatches DirectActions. <br>
+ * <br>
+ *
+ * See WODirectAction for the rules for parsing a request. In short, className
+ * defaults to "DirectAction", and the action defaults to "default". The action
+ * class is expected to have a constructor that takes a WORequest parameter.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODirectActionRequestHandler extends WORequestHandler {
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOResponse response = null;
+
+ // no concurrent access is allowed to a user's session:
+ // a user/browser/machine with multiple requests will have to wait.
+ // NOTE: this forces a session creation for any direct action (!)
+ synchronized (aRequest.request.getSession()) {
+ WOApplication application = aRequest.application();
+ WOContext context = WOContext.contextWithRequest(aRequest);
+
+ String className = "DirectAction";
+ String actionName = "default";
+ NSArray path = aRequest.requestHandlerPathArray();
+ if (path.count() > 0) {
+ className = path.objectAtIndex(0).toString();
+ if (path.count() > 1) {
+ actionName = path.objectAtIndex(path.count() - 1).toString();
+ }
+ if (path.count() > 2) {
+ for (int i = 1; i < path.count() - 1; i++) {
+ className = className + "." + path.objectAtIndex(i).toString();
+ }
+ }
+ }
+
+ // FIXME: sessions are supposed to be lazily created for direct actions
+
+ WOSession session = null;
+
+ String sessionID = aRequest.sessionID();
+ if (sessionID != null) {
+ session = application.restoreSessionWithID(sessionID, context);
+ }
+
+ if (session == null) {
+ session = application.createSessionForRequest(aRequest);
+ if (session == null) {
+ response = application.handleSessionCreationErrorInContext(context);
+ } else {
+ session.setContext(context);
+ }
+ }
+
+ context.setSession(session);
+
+ application.awake();
+ session.awake();
+
+ try {
+
+ if (response == null) {
+ Class c = null;
+ c = application.getLocalClass(className);
+ if ((c == null) && (path.count() == 1)) {
+ actionName = className;
+ className = "DirectAction";
+ c = application.getLocalClass(className);
+ }
+ if (c == null) {
+ throw new RuntimeException("Could not find class named \"" + className + "\": ");
+ }
+ java.lang.reflect.Constructor ctor = c.getConstructor(new Class[] { WORequest.class });
+
+ WODirectAction action = (WODirectAction) ctor.newInstance(new Object[] { aRequest });
+ action.context = context; // HACK: how else can action call pageWithName?
+
+ WOActionResults result = action.performActionNamed(actionName);
+ if (result instanceof WOComponent) {
+ // HACK: I'm not sure where this should have gone: seems hackish here.
+ context.pushElement((WOComponent) result);
+ ((WOComponent) result).ensureAwakeInContext(context);
+ // context.popElement();
+ }
+ response = result.generateResponse(); // calls session.savePage (?)
+ if (result instanceof WOComponent) {
+ // HACK: I'm not sure where this should have gone: seems hackish here.
+ ((WOComponent) result).sleep();
+ }
+ }
+ } catch (NoSuchMethodException exc) {
+ WOResponse error = new WOResponse();
+ exc.printStackTrace();
+ error.setStatus(404); // not found
+ error.appendContentString("Could not find request constructor for class named \"" + className + "\": ");
+ response = error;
+ } catch (Exception exc) {
+ WOResponse error = new WOResponse();
+ error.setStatus(500); // error
+ if (exc.getMessage() != null) {
+ error.appendContentString(exc.getMessage());
+ exc.printStackTrace();
+ } else {
+ error.appendContentString(exc.toString());
+ exc.printStackTrace();
+ }
+ response = error;
+ }
+
+ session.sleep();
+ session.setContext(null);
+ application.saveSessionForContext(context);
+ application.sleep();
+ }
+ return response;
+ }
+
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.10 2003/03/28 17:26:18 mpowers
- * Implemented package support: Applications can now live in packages.
- * Better support for locating package local classes.
+ * Revision 1.10 2003/03/28 17:26:18 mpowers Implemented package support:
+ * Applications can now live in packages. Better support for locating package
+ * local classes.
*
- * Revision 1.9 2003/01/19 22:33:26 mpowers
- * Fixed problems with classpath and dynamic class loading.
- * Dynamic elements now pass on ensureAwakeInContext.
+ * Revision 1.9 2003/01/19 22:33:26 mpowers Fixed problems with classpath and
+ * dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles <standalone/> tags.
*
- * Revision 1.8 2003/01/17 20:34:57 mpowers
- * Better handling for components and parents in the context's element stack.
+ * Revision 1.8 2003/01/17 20:34:57 mpowers Better handling for components and
+ * parents in the context's element stack.
*
- * Revision 1.7 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.7 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.5 2003/01/13 22:25:00 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.5 2003/01/13 22:25:00 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.4 2003/01/09 21:16:49 mpowers
- * Bringing request-response cycle more into conformance.
+ * Revision 1.4 2003/01/09 21:16:49 mpowers Bringing request-response cycle more
+ * into conformance.
*
- * Revision 1.2 2002/12/17 14:57:44 mpowers
- * Minor corrections to WORequests's parsing, and updated javadocs.
+ * Revision 1.2 2002/12/17 14:57:44 mpowers Minor corrections to WORequests's
+ * parsing, and updated javadocs.
*
- * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:53:19 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:50 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:50 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
index bda1dd5..0bdefdf 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
@@ -49,2407 +49,1950 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* WODisplayGroup manages a set of objects,
-* allowing them to be sorted, batched, and filtered.
-* WODisplay also acts as a bridge to the wotonomy's
-* control package, including WODisplayGroup and
-* EOEditingContext.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODisplayGroup extends Observable
- implements EOObserving, EOEditingContext.Editor,
- java.io.Serializable
-{
- /**
- * Notification sent when the display group is about to fetch.
- */
- public static final String DisplayGroupWillFetchNotification
- = "DisplayGroupWillFetchNotification";
-
- private static boolean
- globalDefaultForValidatesChangesImmediately = true;
- private static String
- globalDefaultStringMatchFormat = "caseInsensitiveLike";
- private static String
- globalDefaultStringMatchOperator = "%@*";
-
- protected NSMutableArray allObjects;
- protected NSArray allObjectsProxy;
- protected NSMutableArray displayedObjects;
- protected NSArray displayedObjectsProxy;
- protected NSMutableArray selectedObjects;
- protected NSArray selectedObjectsProxy;
- protected NSMutableArray selectedIndexes;
-
- private String defaultStringMatchOperator;
- private String defaultStringMatchFormat;
-
- private boolean validatesChangesImmediately;
- private Object delegate;
- private EODataSource dataSource;
- private EOQualifier qualifier;
- private NSMutableArray sortOrderings;
- private NSArray sortOrderingsProxy;
-
- private NSArray localKeys;
- private NSDictionary insertedObjectDefaultValues;
- private boolean fetchesOnLoad;
- private boolean selectsFirstObjectAfterFetch;
- private boolean usesOptimisticRefresh;
- private boolean inQueryMode;
-
- // change detection: package access for helper classes
- boolean selectionChanged;
- int updatedObjectIndex;
-
- // batching
- private int batchIndex;
- private int batchSize;
-
- // this property is not in the spec
- private boolean compareByReference = false;
-
- private EOObserving lastGroupObserver;
-
- /**
- * Creates a new display group.
- */
- public WODisplayGroup()
- {
- validatesChangesImmediately =
- globalDefaultForValidatesChangesImmediately();
- defaultStringMatchOperator =
- globalDefaultStringMatchFormat();
- defaultStringMatchFormat =
- globalDefaultStringMatchOperator();
-
- allObjects = new ObservableArray( this );
- allObjectsProxy = NSArray.arrayBackedByList( allObjects );
- displayedObjects = new NSMutableArray();
- displayedObjectsProxy = NSArray.arrayBackedByList( displayedObjects );
- selectedObjects = new NSMutableArray();
- selectedObjectsProxy = NSArray.arrayBackedByList( selectedObjects );
- sortOrderings = new NSMutableArray();
- sortOrderingsProxy = NSArray.arrayBackedByList( sortOrderings );
- selectedIndexes = new NSMutableArray();
-
- delegate = null;
- dataSource = null;
- qualifier = null;
-
- localKeys = new NSArray(); // not implemented
- insertedObjectDefaultValues = new NSDictionary();
- fetchesOnLoad = false; // not implemented
- selectsFirstObjectAfterFetch = false;
- usesOptimisticRefresh = false;
- inQueryMode = false; // not implemented
-
- selectionChanged = false;
- updatedObjectIndex = -1;
-
- batchIndex = 0;
- batchSize = 0;
- }
-
-
-
- // specify optional data source
-
- /**
- * Sets the data source that will be used by
- * this display group.
- */
- public void setDataSource ( EODataSource aDataSource )
- {
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // un-register for notifications from existing parent store
- NSNotificationCenter.defaultCenter().removeObserver(
- this, null, dataSource.editingContext() );
- dataSource.editingContext().removeEditor( this );
- if ( dataSource.editingContext().messageHandler() == this )
- {
- dataSource.editingContext().setMessageHandler( null );
- }
-
- }
-
- dataSource = aDataSource;
-
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // register for notifications from parent store
- NSNotificationCenter.defaultCenter().addObserver(
- this, new NSSelector( "objectsInvalidatedInEditingContext",
- new Class[] { NSNotification.class } ),
- null, dataSource.editingContext() );
-
- // add ourselves as editor
- dataSource.editingContext().addEditor( this );
-
- // add ourselves as message handler if no such handler exists
- if ( dataSource.editingContext().messageHandler() == null )
- {
- dataSource.editingContext().setMessageHandler( this );
- }
- }
- }
-
- /**
- * Returns the current data source backing this display group,
- * or null if no dataSource is currently used.
- */
- public EODataSource dataSource()
- {
- return dataSource;
- }
-
- /**
- * Returns the key by which this display group is bound a master
- * display group, or null if this is not a detail display group.
- */
- public String detailKey()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).key();
- }
- return null;
- }
-
- /**
- * Sets the key by which this display group is bound a master
- * display group. Does nothing if this is not a detail display group.
- */
- public void setDetailKey( String aKey )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setKey( aKey );
- }
- }
-
- /**
- * Returns whether the data source is a detail data source,
- * suggesting that this is a detail display group.
- */
- public boolean hasDetailDataSource()
- {
- return ( dataSource instanceof PropertyDataSource );
- }
-
- /**
- * Returns the selected object in the master display group,
- * or null if this is not a detail display group.
- */
- public Object masterObject()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).source();
- }
- return null;
- }
-
- /**
- * Sets the master object in the detail data source.
- * Does nothing if there is no detail data source.
- */
- public void setMasterObject( Object anObject )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setSource( anObject );
- }
- }
-
- // specify optional delegate
-
- /**
- * Sets the display group delegate that
- * will be used by this display group.
- */
- public void setDelegate ( Object aDelegate )
- {
- delegate = aDelegate;
- }
-
- /**
- * Returns the current delegate for this display group,
- * or null if no delegate is currently set.
- */
- public Object delegate()
- {
- return delegate;
- }
-
-
-
- // display group configuration
-
- /**
- * Returns the current string matching format.
- * If not set, defaults to "%@*".
- */
- public String defaultStringMatchFormat()
- {
- return defaultStringMatchFormat;
- }
-
- /**
- * Returns the current string matching operator.
- * If not set, defaults to "caseInsensitiveLike".
- */
- public String defaultStringMatchOperator()
- {
- return defaultStringMatchOperator;
- }
-
- /**
- * Sets the display group and associations to edit a
- * "query by example" query object. This method is
- * used for target/action connections.
- */
- public void enterQueryMode ( Object aSender )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this display group should immediate
- * fetch when loaded.
- */
- public boolean fetchesOnLoad()
- {
- return fetchesOnLoad;
- }
-
- /**
- * Returns whether this display group is in "query by
- * example" mode.
- */
- public boolean inQueryMode()
- {
- return inQueryMode;
- }
-
- /**
- * Returns a Map of default values that are applied
- * to new objects that are inserted into the list.
- */
- public NSDictionary insertedObjectDefaultValues()
- {
- return insertedObjectDefaultValues;
- }
-
- /**
- * Returns the keys that were declared when read from
- * an external resource file.
- */
- public NSArray localKeys()
- {
- return localKeys;
- }
-
- /**
- * Sets whether this display group will select the
- * first object in the list after a fetch.
- */
- public boolean selectsFirstObjectAfterFetch()
- {
- return selectsFirstObjectAfterFetch;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by this display group.
- */
- public void setDefaultStringMatchFormat ( String aFormat )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by this display group.
- */
- public void setDefaultStringMatchOperator ( String anOperator )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether this display group will fetch objects
- * from its data source on load.
- */
- public void setFetchesOnLoad ( boolean willFetch )
- {
- fetchesOnLoad = willFetch;
- }
-
- /**
- * Sets whether this display group is in "query by example"
- * mode. If true, all associations will bind to a special
- * "example" object.
- */
- public void setInQueryMode ( boolean isInQueryMode )
- {
- inQueryMode = isInQueryMode;
- }
-
- /**
- * Sets the mapping that contains the values that will
- * be applied to new objects inserted into the display group.
- */
- public void setInsertedObjectDefaultValues ( Map aMap )
- {
- insertedObjectDefaultValues = new NSDictionary( aMap );
- }
-
- /**
- * Sets the keys that are declared when instantiated from
- * an external resource file.
- */
- public void setLocalKeys ( List aKeyList )
- {
- localKeys = new NSArray( (Collection) aKeyList );
- }
-
- /**
- * Sets whether the first object in the list will be
- * selected after a fetch.
- */
- public void setSelectsFirstObjectAfterFetch (
- boolean selectsFirst )
- {
- selectsFirstObjectAfterFetch = selectsFirst;
- }
-
- /**
- * Sets the order of the keys by which this display group
- * will be ordered after a fetch or after a call to
- * updateDisplayedObjects(). The elements in the display
- * group will be sorted first by the first key, within
- * the first key, by the second key, and so on.
- */
- public void setSortOrderings ( List aList )
- {
- sortOrderings.removeAllObjects();
-
- Object o;
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- // handle the convenience of specifying just a key
- if ( ! ( o instanceof EOSortOrdering ) )
- {
- o = new EOSortOrdering(
- o.toString(), EOSortOrdering.CompareAscending );
- }
- sortOrderings.add( o );
- }
- }
-
- /**
- * Sets whether only changed objects are refreshed (optimistic),
- * or whether all objects are refreshed (pessimistic, default).
- * By default, when the display group receives notification that
- * one of its objects has changed, updateDisplayedObjects is called.
- */
- public void setUsesOptimisticRefresh ( boolean isOptimistic )
- {
- usesOptimisticRefresh = isOptimistic;
- }
-
- /**
- * Sets whether changes made by associations are validated
- * immediately, or when changes are saved.
- */
- public void setValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- validatesChangesImmediately = validatesImmediately;
- }
-
- /**
- * Returns a read-only List of sort orderings for this display group.
- */
- public NSArray sortOrderings()
- {
- return sortOrderingsProxy;
- }
-
- /**
- * Returns whether this display group refreshes only
- * the changed objects or all objects on refresh.
- */
- public boolean usesOptimisticRefresh()
- {
- return usesOptimisticRefresh;
- }
-
- /**
- * Returns whether this display group validates changes
- * immediately. Otherwise, validation should occur when
- * changes are saved. Default is the global default,
- * which is initially true.
- */
- public boolean validatesChangesImmediately()
- {
- return validatesChangesImmediately;
- }
-
-
- // qualification
-
- /**
- * Returns a qualifier that will be applied all the objects
- * in this display group to determine which objects will
- * be displayed.
- */
- public EOQualifier qualifier()
- {
- return qualifier;
- }
-
- /**
- * Returns a new qualifier built from the three query
- * value maps: greater than, equal to, and less than.
- */
- public EOQualifier qualifierFromQueryValues()
- {
- //TODO: assemble qualifier from query values
-
- return new EOQualifier()
- {
- // use inner class until we actually implement one
- public EOQualifier qualifierWithBindings(
- Map aMap,
- boolean requireAll )
- {
- return null;
- }
- public Throwable
- validateKeysWithRootClassDescription( Class aClass )
- {
- return null;
- }
- public boolean evaluateWithObject(Object o)
- {
- return false;
- }
- };
- }
-
- /**
- * Calls qualifierFromQueryValues(), applies the result
- * to the data source, and calls fetch().
- */
- public void qualifyDataSource()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Calls qualifierFromQueryValues(), sets the qualifier
- * with setQualifier(), and calls updateDisplayedObjects().
- */
- public void qualifyDisplayGroup()
- {
- setQualifier( qualifierFromQueryValues() );
- updateDisplayedObjects();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSDictionary queryBindingValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSMutableDictionary queryBindings()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a matching query.
- */
- public NSMutableDictionary queryMatch()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a minimum value query.
- */
- public NSMutableDictionary queryMin()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a maximum value query.
- */
- public NSMutableDictionary queryMax()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSMutableDictionary queryOperator()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a list containing all supported qualifier operators.
- */
- public NSArray allQualifierOperators()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSDictionary queryOperatorValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the qualifier that will be used by
- * updateDisplayedObjects() to filter displayed objects.
- */
- public void setQualifier ( EOQualifier aQualifier )
- {
- qualifier = aQualifier;
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to binding values.
- */
- public void setQueryBindingValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to operator values.
- */
- public void setQueryOperatorValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
-
-
- // qualifier query values
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for equality.
- */
- public NSDictionary equalToQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public NSDictionary greaterThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public NSDictionary lessThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the Map that contains the mappings of keys
- * to query values that will be used to test for equality.
- */
- public void setEqualToQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public void setGreaterThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public void setLessThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Deprecated: returns true.
- */
- public boolean endEditing()
- {
- return true;
- }
-
-
- // object management
-
- /**
- * Returns a read-only List containing all objects managed by the display group.
- * This includes those objects not visible due to disqualification.
- */
- public NSArray allObjects()
- { //System.out.println( "avoided allocation: allObjects" );
- return allObjectsProxy;
- }
-
- /**
- * Returns the total number of batches held by this display group.
- */
- public int batchCount()
- {
- if ( batchSize < 1 ) return 1;
- int count = displayedObjects.count();
- if ( count == 0 ) return 1;
- return ((count-1) / batchSize) + 1;
- }
-
- /**
- * Returns the index of the currently displayed batch.
- */
- public int currentBatchIndex()
- {
- return batchIndex;
- }
-
- /**
- * Sets the index of the currently displayed batch.
- */
- public void setCurrentBatchIndex( int aBatchIndex )
- {
- batchIndex = aBatchIndex;
- updateDisplayedObjects();
- }
-
- /**
- * Sets the displayed objects to the batch containing
- * the first selected object, and updates the current
- * batch index, and returns null to force a page reload.
- * Displays the first batch is there is no selection.
- */
- public Object displayBatchContainingSelectedObject()
- {
- if ( batchSize < 1 ) return null;
- NSArray indexes = selectionIndexes();
- if ( indexes.count() > 0 )
- {
- batchIndex =
- ((Number)indexes.objectAtIndex( 0 )).intValue() / batchSize;
- }
- else
- {
- batchIndex = 0;
- }
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no next batch
- * the first batch is displayed.
- */
- public Object displayNextBatch()
- {
- batchIndex = (batchIndex + 1) % batchCount();
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no previous
- * batch, the last batch is displayed.
- */
- public Object displayPreviousBatch()
- {
- batchIndex--;
- if ( batchIndex < 0 ) batchIndex = batchCount() - 1;
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Returns whether the displayed objects have been batched.
- */
- public boolean hasMultipleBatches()
- {
- return batchCount() > 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first displayed object in the current batch.
- */
- public int indexOfFirstDisplayedObject()
- {
- if ( batchSize < 1 ) return 1;
- return batchIndex * batchSize + 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first last object in the current batch.
- */
- public int indexOfLastDisplayedObject()
- {
- if ( batchSize < 1 ) return displayedObjects.count();
- return Math.min(
- ((batchIndex+1) * batchSize),
- displayedObjects.count() );
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public int numberOfObjectsPerBatch()
- {
- return batchSize;
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public void setNumberOfObjectsPerBatch( int aSize )
- {
- batchSize = aSize;
- updateDisplayedObjects();
- }
-
- /**
- * Clears the current selection.
- * @return True is the selection was cleared,
- * False if the selection could not be cleared
- * @see #setSelectionIndexes
- */
- public boolean clearSelection()
- {
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, new NSArray( selectedObjects ) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- selectionChanged = true;
- willChange();
-
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Convenience for binding to a component action:
- * calls deleteSelection() and then displayBatchContainingSelectedObject()
- * and returns null, which is a suitable result from a component action.
- */
- public Object delete()
- {
- deleteSelection();
- displayBatchContainingSelectedObject();
- return null;
- }
-
- /**
- * Deletes the object at the specified index,
- * notifying the delegate before and after the operation,
- * and then updating the selection if needed.
- * @return True if delete was successful, false if the
- * object was not deleted.
- */
- public boolean deleteObjectAtIndex ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- Object result = notifyDelegate(
- "displayGroupShouldDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- deleteObjectAtIndexNoNotify( anIndex );
-
- if ( dataSource != null )
- {
- dataSource.deleteObject( target );
- }
-
- notifyDelegate(
- "displayGroupDidDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
-
- return true;
- }
-
- private void deleteObjectAtIndexNoNotify ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- int i;
-
- // remove from selected objects if necessary
- i = indexOf( selectedObjects, target );
- if ( i != NSArray.NotFound )
- {
- selectionChanged = true;
- willChange(); // notify before removing
- selectedObjects.removeObjectAtIndex( i );
- selectedIndexes.remove( new Integer( i ) ); // comps by value
- }
- else // notify - no selection change needed
- {
- willChange();
- }
-
- // remove from all objects
- i = indexOf( allObjects, target );
- if ( i != NSArray.NotFound )
- {
- allObjects.removeObjectAtIndex( i );
- }
- else // otherwise should never happen
- {
+ * WODisplayGroup manages a set of objects, allowing them to be sorted, batched,
+ * and filtered. WODisplay also acts as a bridge to the wotonomy's control
+ * package, including WODisplayGroup and EOEditingContext.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODisplayGroup extends Observable implements EOObserving, EOEditingContext.Editor, java.io.Serializable {
+ /**
+ * Notification sent when the display group is about to fetch.
+ */
+ public static final String DisplayGroupWillFetchNotification = "DisplayGroupWillFetchNotification";
+
+ private static boolean globalDefaultForValidatesChangesImmediately = true;
+ private static String globalDefaultStringMatchFormat = "caseInsensitiveLike";
+ private static String globalDefaultStringMatchOperator = "%@*";
+
+ protected NSMutableArray allObjects;
+ protected NSArray allObjectsProxy;
+ protected NSMutableArray displayedObjects;
+ protected NSArray displayedObjectsProxy;
+ protected NSMutableArray selectedObjects;
+ protected NSArray selectedObjectsProxy;
+ protected NSMutableArray selectedIndexes;
+
+ private String defaultStringMatchOperator;
+ private String defaultStringMatchFormat;
+
+ private boolean validatesChangesImmediately;
+ private Object delegate;
+ private EODataSource dataSource;
+ private EOQualifier qualifier;
+ private NSMutableArray sortOrderings;
+ private NSArray sortOrderingsProxy;
+
+ private NSArray localKeys;
+ private NSDictionary insertedObjectDefaultValues;
+ private boolean fetchesOnLoad;
+ private boolean selectsFirstObjectAfterFetch;
+ private boolean usesOptimisticRefresh;
+ private boolean inQueryMode;
+
+ // change detection: package access for helper classes
+ boolean selectionChanged;
+ int updatedObjectIndex;
+
+ // batching
+ private int batchIndex;
+ private int batchSize;
+
+ // this property is not in the spec
+ private boolean compareByReference = false;
+
+ private EOObserving lastGroupObserver;
+
+ /**
+ * Creates a new display group.
+ */
+ public WODisplayGroup() {
+ validatesChangesImmediately = globalDefaultForValidatesChangesImmediately();
+ defaultStringMatchOperator = globalDefaultStringMatchFormat();
+ defaultStringMatchFormat = globalDefaultStringMatchOperator();
+
+ allObjects = new ObservableArray(this);
+ allObjectsProxy = NSArray.arrayBackedByList(allObjects);
+ displayedObjects = new NSMutableArray();
+ displayedObjectsProxy = NSArray.arrayBackedByList(displayedObjects);
+ selectedObjects = new NSMutableArray();
+ selectedObjectsProxy = NSArray.arrayBackedByList(selectedObjects);
+ sortOrderings = new NSMutableArray();
+ sortOrderingsProxy = NSArray.arrayBackedByList(sortOrderings);
+ selectedIndexes = new NSMutableArray();
+
+ delegate = null;
+ dataSource = null;
+ qualifier = null;
+
+ localKeys = new NSArray(); // not implemented
+ insertedObjectDefaultValues = new NSDictionary();
+ fetchesOnLoad = false; // not implemented
+ selectsFirstObjectAfterFetch = false;
+ usesOptimisticRefresh = false;
+ inQueryMode = false; // not implemented
+
+ selectionChanged = false;
+ updatedObjectIndex = -1;
+
+ batchIndex = 0;
+ batchSize = 0;
+ }
+
+ // specify optional data source
+
+ /**
+ * Sets the data source that will be used by this display group.
+ */
+ public void setDataSource(EODataSource aDataSource) {
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // un-register for notifications from existing parent store
+ NSNotificationCenter.defaultCenter().removeObserver(this, null, dataSource.editingContext());
+ dataSource.editingContext().removeEditor(this);
+ if (dataSource.editingContext().messageHandler() == this) {
+ dataSource.editingContext().setMessageHandler(null);
+ }
+
+ }
+
+ dataSource = aDataSource;
+
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // register for notifications from parent store
+ NSNotificationCenter.defaultCenter().addObserver(this,
+ new NSSelector("objectsInvalidatedInEditingContext", new Class[] { NSNotification.class }), null,
+ dataSource.editingContext());
+
+ // add ourselves as editor
+ dataSource.editingContext().addEditor(this);
+
+ // add ourselves as message handler if no such handler exists
+ if (dataSource.editingContext().messageHandler() == null) {
+ dataSource.editingContext().setMessageHandler(this);
+ }
+ }
+ }
+
+ /**
+ * Returns the current data source backing this display group, or null if no
+ * dataSource is currently used.
+ */
+ public EODataSource dataSource() {
+ return dataSource;
+ }
+
+ /**
+ * Returns the key by which this display group is bound a master display group,
+ * or null if this is not a detail display group.
+ */
+ public String detailKey() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).key();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the key by which this display group is bound a master display group.
+ * Does nothing if this is not a detail display group.
+ */
+ public void setDetailKey(String aKey) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setKey(aKey);
+ }
+ }
+
+ /**
+ * Returns whether the data source is a detail data source, suggesting that this
+ * is a detail display group.
+ */
+ public boolean hasDetailDataSource() {
+ return (dataSource instanceof PropertyDataSource);
+ }
+
+ /**
+ * Returns the selected object in the master display group, or null if this is
+ * not a detail display group.
+ */
+ public Object masterObject() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).source();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the master object in the detail data source. Does nothing if there is no
+ * detail data source.
+ */
+ public void setMasterObject(Object anObject) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setSource(anObject);
+ }
+ }
+
+ // specify optional delegate
+
+ /**
+ * Sets the display group delegate that will be used by this display group.
+ */
+ public void setDelegate(Object aDelegate) {
+ delegate = aDelegate;
+ }
+
+ /**
+ * Returns the current delegate for this display group, or null if no delegate
+ * is currently set.
+ */
+ public Object delegate() {
+ return delegate;
+ }
+
+ // display group configuration
+
+ /**
+ * Returns the current string matching format. If not set, defaults to "%@*".
+ */
+ public String defaultStringMatchFormat() {
+ return defaultStringMatchFormat;
+ }
+
+ /**
+ * Returns the current string matching operator. If not set, defaults to
+ * "caseInsensitiveLike".
+ */
+ public String defaultStringMatchOperator() {
+ return defaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the display group and associations to edit a "query by example" query
+ * object. This method is used for target/action connections.
+ */
+ public void enterQueryMode(Object aSender) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this display group should immediate fetch when loaded.
+ */
+ public boolean fetchesOnLoad() {
+ return fetchesOnLoad;
+ }
+
+ /**
+ * Returns whether this display group is in "query by example" mode.
+ */
+ public boolean inQueryMode() {
+ return inQueryMode;
+ }
+
+ /**
+ * Returns a Map of default values that are applied to new objects that are
+ * inserted into the list.
+ */
+ public NSDictionary insertedObjectDefaultValues() {
+ return insertedObjectDefaultValues;
+ }
+
+ /**
+ * Returns the keys that were declared when read from an external resource file.
+ */
+ public NSArray localKeys() {
+ return localKeys;
+ }
+
+ /**
+ * Sets whether this display group will select the first object in the list
+ * after a fetch.
+ */
+ public boolean selectsFirstObjectAfterFetch() {
+ return selectsFirstObjectAfterFetch;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchFormat(String aFormat) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchOperator(String anOperator) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether this display group will fetch objects from its data source on
+ * load.
+ */
+ public void setFetchesOnLoad(boolean willFetch) {
+ fetchesOnLoad = willFetch;
+ }
+
+ /**
+ * Sets whether this display group is in "query by example" mode. If true, all
+ * associations will bind to a special "example" object.
+ */
+ public void setInQueryMode(boolean isInQueryMode) {
+ inQueryMode = isInQueryMode;
+ }
+
+ /**
+ * Sets the mapping that contains the values that will be applied to new objects
+ * inserted into the display group.
+ */
+ public void setInsertedObjectDefaultValues(Map aMap) {
+ insertedObjectDefaultValues = new NSDictionary(aMap);
+ }
+
+ /**
+ * Sets the keys that are declared when instantiated from an external resource
+ * file.
+ */
+ public void setLocalKeys(List aKeyList) {
+ localKeys = new NSArray((Collection) aKeyList);
+ }
+
+ /**
+ * Sets whether the first object in the list will be selected after a fetch.
+ */
+ public void setSelectsFirstObjectAfterFetch(boolean selectsFirst) {
+ selectsFirstObjectAfterFetch = selectsFirst;
+ }
+
+ /**
+ * Sets the order of the keys by which this display group will be ordered after
+ * a fetch or after a call to updateDisplayedObjects(). The elements in the
+ * display group will be sorted first by the first key, within the first key, by
+ * the second key, and so on.
+ */
+ public void setSortOrderings(List aList) {
+ sortOrderings.removeAllObjects();
+
+ Object o;
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ // handle the convenience of specifying just a key
+ if (!(o instanceof EOSortOrdering)) {
+ o = new EOSortOrdering(o.toString(), EOSortOrdering.CompareAscending);
+ }
+ sortOrderings.add(o);
+ }
+ }
+
+ /**
+ * Sets whether only changed objects are refreshed (optimistic), or whether all
+ * objects are refreshed (pessimistic, default). By default, when the display
+ * group receives notification that one of its objects has changed,
+ * updateDisplayedObjects is called.
+ */
+ public void setUsesOptimisticRefresh(boolean isOptimistic) {
+ usesOptimisticRefresh = isOptimistic;
+ }
+
+ /**
+ * Sets whether changes made by associations are validated immediately, or when
+ * changes are saved.
+ */
+ public void setValidatesChangesImmediately(boolean validatesImmediately) {
+ validatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Returns a read-only List of sort orderings for this display group.
+ */
+ public NSArray sortOrderings() {
+ return sortOrderingsProxy;
+ }
+
+ /**
+ * Returns whether this display group refreshes only the changed objects or all
+ * objects on refresh.
+ */
+ public boolean usesOptimisticRefresh() {
+ return usesOptimisticRefresh;
+ }
+
+ /**
+ * Returns whether this display group validates changes immediately. Otherwise,
+ * validation should occur when changes are saved. Default is the global
+ * default, which is initially true.
+ */
+ public boolean validatesChangesImmediately() {
+ return validatesChangesImmediately;
+ }
+
+ // qualification
+
+ /**
+ * Returns a qualifier that will be applied all the objects in this display
+ * group to determine which objects will be displayed.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns a new qualifier built from the three query value maps: greater than,
+ * equal to, and less than.
+ */
+ public EOQualifier qualifierFromQueryValues() {
+ // TODO: assemble qualifier from query values
+
+ return new EOQualifier() {
+ // use inner class until we actually implement one
+ public EOQualifier qualifierWithBindings(Map aMap, boolean requireAll) {
+ return null;
+ }
+
+ public Throwable validateKeysWithRootClassDescription(Class aClass) {
+ return null;
+ }
+
+ public boolean evaluateWithObject(Object o) {
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), applies the result to the data source, and
+ * calls fetch().
+ */
+ public void qualifyDataSource() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), sets the qualifier with setQualifier(), and
+ * calls updateDisplayedObjects().
+ */
+ public void qualifyDisplayGroup() {
+ setQualifier(qualifierFromQueryValues());
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSDictionary queryBindingValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSMutableDictionary queryBindings() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * matching query.
+ */
+ public NSMutableDictionary queryMatch() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * minimum value query.
+ */
+ public NSMutableDictionary queryMin() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * maximum value query.
+ */
+ public NSMutableDictionary queryMax() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSMutableDictionary queryOperator() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a list containing all supported qualifier operators.
+ */
+ public NSArray allQualifierOperators() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSDictionary queryOperatorValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the qualifier that will be used by updateDisplayedObjects() to filter
+ * displayed objects.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to binding values.
+ */
+ public void setQueryBindingValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to operator values.
+ */
+ public void setQueryOperatorValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ // qualifier query values
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public NSDictionary equalToQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for greater value.
+ */
+ public NSDictionary greaterThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for lesser value.
+ */
+ public NSDictionary lessThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the Map that contains the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public void setEqualToQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for greater value.
+ */
+ public void setGreaterThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for lesser value.
+ */
+ public void setLessThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Deprecated: returns true.
+ */
+ public boolean endEditing() {
+ return true;
+ }
+
+ // object management
+
+ /**
+ * Returns a read-only List containing all objects managed by the display group.
+ * This includes those objects not visible due to disqualification.
+ */
+ public NSArray allObjects() { // System.out.println( "avoided allocation: allObjects" );
+ return allObjectsProxy;
+ }
+
+ /**
+ * Returns the total number of batches held by this display group.
+ */
+ public int batchCount() {
+ if (batchSize < 1)
+ return 1;
+ int count = displayedObjects.count();
+ if (count == 0)
+ return 1;
+ return ((count - 1) / batchSize) + 1;
+ }
+
+ /**
+ * Returns the index of the currently displayed batch.
+ */
+ public int currentBatchIndex() {
+ return batchIndex;
+ }
+
+ /**
+ * Sets the index of the currently displayed batch.
+ */
+ public void setCurrentBatchIndex(int aBatchIndex) {
+ batchIndex = aBatchIndex;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Sets the displayed objects to the batch containing the first selected object,
+ * and updates the current batch index, and returns null to force a page reload.
+ * Displays the first batch is there is no selection.
+ */
+ public Object displayBatchContainingSelectedObject() {
+ if (batchSize < 1)
+ return null;
+ NSArray indexes = selectionIndexes();
+ if (indexes.count() > 0) {
+ batchIndex = ((Number) indexes.objectAtIndex(0)).intValue() / batchSize;
+ } else {
+ batchIndex = 0;
+ }
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no next batch the
+ * first batch is displayed.
+ */
+ public Object displayNextBatch() {
+ batchIndex = (batchIndex + 1) % batchCount();
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no previous
+ * batch, the last batch is displayed.
+ */
+ public Object displayPreviousBatch() {
+ batchIndex--;
+ if (batchIndex < 0)
+ batchIndex = batchCount() - 1;
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Returns whether the displayed objects have been batched.
+ */
+ public boolean hasMultipleBatches() {
+ return batchCount() > 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * displayed object in the current batch.
+ */
+ public int indexOfFirstDisplayedObject() {
+ if (batchSize < 1)
+ return 1;
+ return batchIndex * batchSize + 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * last object in the current batch.
+ */
+ public int indexOfLastDisplayedObject() {
+ if (batchSize < 1)
+ return displayedObjects.count();
+ return Math.min(((batchIndex + 1) * batchSize), displayedObjects.count());
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public int numberOfObjectsPerBatch() {
+ return batchSize;
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public void setNumberOfObjectsPerBatch(int aSize) {
+ batchSize = aSize;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Clears the current selection.
+ *
+ * @return True is the selection was cleared, False if the selection could not
+ * be cleared
+ * @see #setSelectionIndexes
+ */
+ public boolean clearSelection() {
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, new NSArray(selectedObjects) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ selectionChanged = true;
+ willChange();
+
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Convenience for binding to a component action: calls deleteSelection() and
+ * then displayBatchContainingSelectedObject() and returns null, which is a
+ * suitable result from a component action.
+ */
+ public Object delete() {
+ deleteSelection();
+ displayBatchContainingSelectedObject();
+ return null;
+ }
+
+ /**
+ * Deletes the object at the specified index, notifying the delegate before and
+ * after the operation, and then updating the selection if needed.
+ *
+ * @return True if delete was successful, false if the object was not deleted.
+ */
+ public boolean deleteObjectAtIndex(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ Object result = notifyDelegate("displayGroupShouldDeleteObject",
+ new Class[] { WODisplayGroup.class, Object.class }, new Object[] { this, target });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ deleteObjectAtIndexNoNotify(anIndex);
+
+ if (dataSource != null) {
+ dataSource.deleteObject(target);
+ }
+
+ notifyDelegate("displayGroupDidDeleteObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, target });
+
+ return true;
+ }
+
+ private void deleteObjectAtIndexNoNotify(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ int i;
+
+ // remove from selected objects if necessary
+ i = indexOf(selectedObjects, target);
+ if (i != NSArray.NotFound) {
+ selectionChanged = true;
+ willChange(); // notify before removing
+ selectedObjects.removeObjectAtIndex(i);
+ selectedIndexes.remove(new Integer(i)); // comps by value
+ } else // notify - no selection change needed
+ {
+ willChange();
+ }
+
+ // remove from all objects
+ i = indexOf(allObjects, target);
+ if (i != NSArray.NotFound) {
+ allObjects.removeObjectAtIndex(i);
+ } else // otherwise should never happen
+ {
// throw new WotonomyException(
// "Displayed object not found in allObjects" );
- }
-
- // remove from displayed objects
- displayedObjects.removeObjectAtIndex( anIndex );
- }
-
- /**
- * Deletes the currently selected objects.
- * This implementation calls deleteObjectAtIndex() for
- * each index in the selection list, immediately returning
- * false if any delete operation fails.
- * @return True if all selected objects were deleted,
- * false if any deletion failed.
- */
- public boolean deleteSelection()
- {
- int i;
- boolean result = true;
-
- Enumeration e = new NSArray( selectedObjects ).objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i == NSArray.NotFound )
- {
- // should never happen
- throw new WotonomyException(
- "Selected object not found in displayedObjects" );
- }
- result = result && deleteObjectAtIndex( i );
- }
-
- return result;
- }
-
- /**
- * Returns a read-only List of all objects in the display group
- * that are currently displayed by the associations.
- */
- public NSArray displayedObjects()
- { // System.out.println( "avoided allocation: displayedObjects" );
- if ( batchSize < 1 ) return displayedObjectsProxy;
- return displayedObjectsProxy.subarrayWithRange(
- new NSRange( batchIndex * batchSize, batchSize ) );
- }
-
- /**
- * Requests a list of objects from the DataSource
- * and calls setObjectArray to populate the list.
- * More specifically, calls endEditing(), asks the
- * delegate, fetches the objects, notifies the delegate,
- * and populates the list. Returns null to force a
- * page reload.
- */
- public Object fetch()
- {
- endEditing();
-
- if ( dataSource == null )
- {
- return null;
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldFetch",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return null;
- }
-
- NSNotificationCenter.defaultCenter().postNotification(
- DisplayGroupWillFetchNotification, this, new NSDictionary() );
-
- NSArray objectList = dataSource.fetchObjects();
-
- notifyDelegate(
- "displayGroupDidFetchObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, objectList } );
-
- setObjectArray( objectList );
-
- if ( ( selectsFirstObjectAfterFetch ) && ( displayedObjects.size() > 0 ) )
- {
- setSelectionIndexes( new NSArray( new Integer( 0 ) ) );
- }
-
- return null;
- }
-
- /**
- * Convenience to call insertNewObjectAtIndex with the current selection plus one,
- * or at the end of the list if there is no selection.
- * Returns null to force a page reload.
- */
- public Object insert()
- {
- NSArray indexes = selectionIndexes();
- int size = indexes.count();
- if ( size == 0 )
- {
- insertNewObjectAtIndex( displayedObjects.count() );
- }
- else
- {
- insertNewObjectAtIndex(
- ((Number)selectedIndexes.objectAtIndex( size-1 )).intValue()+1 );
- }
- return null;
- }
-
- /**
- * Creates a new object at the specified index.
- * Calls insertObjectAtIndex() with the result
- * from sending createObject() to the data source.
- * @return the newly created object.
- */
- public Object insertNewObjectAtIndex ( int anIndex )
- {
- Object result = null;
- if ( dataSource != null )
- {
- result = dataSource.createObject();
- }
- if ( result != null )
- {
- if ( insertedObjectDefaultValues != null )
- {
- Duplicator.writePropertiesForObject(
- insertedObjectDefaultValues, result );
- }
- insertObjectAtIndex( result, anIndex );
- }
- else // create failed
- {
- if ( delegate() != null )
- {
- NSSelector selector = new NSSelector(
- "displayGroupCreateObjectFailed",
- new Class[] { WODisplayGroup.class, EODataSource.class } );
- if ( selector.implementedByObject( delegate() ) )
- {
- try
- {
- selector.invoke( delegate(), new Object[] { this, dataSource } );
- return result;
- }
- catch ( Exception exc )
- {
- System.err.println( "Error notifying delegate: displayGroupCreateObjectFailed" );
- exc.printStackTrace();
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Inserts the specified object into the list at
- * the specified index.
- */
- public void insertObjectAtIndex ( Object anObject, int anIndex )
- {
- Object result = notifyDelegate(
- "displayGroupShouldInsertObject",
- new Class[] { WODisplayGroup.class, Object.class, int.class },
- new Object[] { this, anObject, new Integer(anIndex) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return;
- }
-
- updatedObjectIndex = anIndex;
- willChange();
-
- int i;
-
- // add to all objects
- if ( anIndex == displayedObjects.size() )
- {
- allObjects.addObject( anObject );
- }
- else // insert before same object
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
- int targetIndex = indexOf( allObjects, target );
- if ( targetIndex != NSArray.NotFound )
- {
- allObjects.insertObjectAtIndex( anObject, targetIndex );
- }
- else // should never happen
- {
- throw new WotonomyException(
- "Could not find displayed object in all objects list: "
- + target );
- }
- }
-
- // add to displayed objects
- displayedObjects.insertObjectAtIndex( anObject, anIndex );
-
- if ( dataSource != null )
- {
- if ( dataSource instanceof OrderedDataSource )
- {
- ((OrderedDataSource)dataSource).insertObjectAtIndex(
- anObject, anIndex );
- }
- else
- {
- dataSource.insertObject( anObject );
- }
- }
-
- notifyDelegate(
- "displayGroupDidInsertObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, anObject } );
- }
-
- /**
- * Sets contentsChanged to true and notifies all observers.
- */
- public void redisplay()
- {
- willChange();
- }
-
- /**
- * Sets the selection to the next displayed object after the current
- * selection. If the last object is selected, or if no object
- * is selected, then the first object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectNext()
- {
- int count = displayedObjects.count();
- if ( count == 0 ) return null;
- if ( count == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- int i = -1;
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = -1;
-
- // select next object
- i++;
- if ( i != displayedObjects.count() )
- {
- // set to next object
- selectedObject = displayedObjects.objectAtIndex( i );
- }
- else // out of range
- {
- // set to null
- selectedObject = displayedObjects.objectAtIndex( 0 );
- }
-
- selectObject( selectedObject );
- return null;
- }
-
- /**
- * Sets the selection to the specified object.
- * If the specified object is null or does not exist
- * in the list of displayed objects, the selection
- * will be cleared.
- * @return true if the object was selected.
- */
- public boolean selectObject ( Object anObject )
- {
- if ( ( anObject == null ) ||
- ( indexOf( displayedObjects, anObject )
- == NSArray.NotFound ) )
- {
- clearSelection();
- return false;
- }
-
- selectObjectsIdenticalTo( new NSArray( new Object[] { anObject } ) );
- return true;
- }
-
- /**
- * Sets the selection to the specified objects.
- * If the specified list is null or if none of the objects
- * in the list exist in the list of displayed objects, the
- * selection will be cleared.
- * @return true if all specified objects were selected.
- */
- public boolean selectObjectsIdenticalTo ( List anObjectList )
- {
- // optimization: check for resetting of selection
- if ( ( anObjectList != null ) && ( selectedObjects.size() == anObjectList.size() ) )
- {
- boolean identical = true;
- int size = selectedObjects.size();
- for ( int i = 0; ( i < size ) && identical; i++ )
- {
- // compare by reference
- if ( anObjectList.get( i ) != selectedObjects.get( i ) )
- {
- identical = false;
- }
- else if ( displayedObjects.indexOfIdenticalObject(
- anObjectList.get( i ) ) == NSArray.NotFound )
- {
- identical = false;
- }
- }
- if ( identical )
- {
- return true;
- }
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- // need to notify the calling component
- // to revert back to the previous selection
- selectionChanged = true;
- willChange();
- return false;
- }
-
- int i;
- selectionChanged = true;
- willChange();
- Object o;
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- != NSArray.NotFound )
- {
- selectedObjects.addObject( o );
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Calls selectObjectsIdenticalTo and if false is returned
- * and selectFirstIfNoMatch is true, selects the first object.
- */
- public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(
- List anObjectList, boolean selectFirstIfNoMatch )
- {
- if ( selectObjectsIdenticalTo( anObjectList ) )
- {
- return true;
- }
- if ( selectFirstIfNoMatch )
- {
- clearSelection();
- selectNext();
- return true;
- }
- return false;
- }
-
- /**
- * Sets the selection to the previous displayed object before the current
- * selection. If the first object is selected, or if no object
- * is selected, then the last object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectPrevious()
- {
- int i = displayedObjects.count();
- if ( i == 0 ) return null;
- if ( i == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = displayedObjects.count();
-
- // select next object
- i--;
- if ( i < 0 )
- {
- // out of range - select last object
- i = displayedObjects.count() - 1;
- }
-
- selectObject( displayedObjects.objectAtIndex( i ) );
- return null;
- }
-
- /**
- * Returns the currently selected object, or null if
- * there is no selection.
- */
- public Object selectedObject()
- {
- if ( selectedObjects.count() == 0 )
- {
- return null;
- }
- return selectedObjects.objectAtIndex( 0 );
- }
-
- /**
- * Returns a read-only List containing all selected objects, if any.
- * Returns an empty list if no objects are selected.
- */
- public NSArray selectedObjects()
- { // System.out.println( "avoided allocation: selectedObjects" );
- return selectedObjectsProxy;
- }
-
- /**
- * Returns a read-only List containing the indexes of all selected
- * objects, if any. The list contains instances of
- * java.lang.Number; call intValue() to retrieve the index.
- */
- public NSArray selectionIndexes()
- {
+ }
+
+ // remove from displayed objects
+ displayedObjects.removeObjectAtIndex(anIndex);
+ }
+
+ /**
+ * Deletes the currently selected objects. This implementation calls
+ * deleteObjectAtIndex() for each index in the selection list, immediately
+ * returning false if any delete operation fails.
+ *
+ * @return True if all selected objects were deleted, false if any deletion
+ * failed.
+ */
+ public boolean deleteSelection() {
+ int i;
+ boolean result = true;
+
+ Enumeration e = new NSArray(selectedObjects).objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i == NSArray.NotFound) {
+ // should never happen
+ throw new WotonomyException("Selected object not found in displayedObjects");
+ }
+ result = result && deleteObjectAtIndex(i);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a read-only List of all objects in the display group that are
+ * currently displayed by the associations.
+ */
+ public NSArray displayedObjects() { // System.out.println( "avoided allocation: displayedObjects" );
+ if (batchSize < 1)
+ return displayedObjectsProxy;
+ return displayedObjectsProxy.subarrayWithRange(new NSRange(batchIndex * batchSize, batchSize));
+ }
+
+ /**
+ * Requests a list of objects from the DataSource and calls setObjectArray to
+ * populate the list. More specifically, calls endEditing(), asks the delegate,
+ * fetches the objects, notifies the delegate, and populates the list. Returns
+ * null to force a page reload.
+ */
+ public Object fetch() {
+ endEditing();
+
+ if (dataSource == null) {
+ return null;
+ }
+
+ Object result = notifyDelegate("displayGroupShouldFetch", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return null;
+ }
+
+ NSNotificationCenter.defaultCenter().postNotification(DisplayGroupWillFetchNotification, this,
+ new NSDictionary());
+
+ NSArray objectList = dataSource.fetchObjects();
+
+ notifyDelegate("displayGroupDidFetchObjects", new Class[] { WODisplayGroup.class, List.class },
+ new Object[] { this, objectList });
+
+ setObjectArray(objectList);
+
+ if ((selectsFirstObjectAfterFetch) && (displayedObjects.size() > 0)) {
+ setSelectionIndexes(new NSArray(new Integer(0)));
+ }
+
+ return null;
+ }
+
+ /**
+ * Convenience to call insertNewObjectAtIndex with the current selection plus
+ * one, or at the end of the list if there is no selection. Returns null to
+ * force a page reload.
+ */
+ public Object insert() {
+ NSArray indexes = selectionIndexes();
+ int size = indexes.count();
+ if (size == 0) {
+ insertNewObjectAtIndex(displayedObjects.count());
+ } else {
+ insertNewObjectAtIndex(((Number) selectedIndexes.objectAtIndex(size - 1)).intValue() + 1);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new object at the specified index. Calls insertObjectAtIndex() with
+ * the result from sending createObject() to the data source.
+ *
+ * @return the newly created object.
+ */
+ public Object insertNewObjectAtIndex(int anIndex) {
+ Object result = null;
+ if (dataSource != null) {
+ result = dataSource.createObject();
+ }
+ if (result != null) {
+ if (insertedObjectDefaultValues != null) {
+ Duplicator.writePropertiesForObject(insertedObjectDefaultValues, result);
+ }
+ insertObjectAtIndex(result, anIndex);
+ } else // create failed
+ {
+ if (delegate() != null) {
+ NSSelector selector = new NSSelector("displayGroupCreateObjectFailed",
+ new Class[] { WODisplayGroup.class, EODataSource.class });
+ if (selector.implementedByObject(delegate())) {
+ try {
+ selector.invoke(delegate(), new Object[] { this, dataSource });
+ return result;
+ } catch (Exception exc) {
+ System.err.println("Error notifying delegate: displayGroupCreateObjectFailed");
+ exc.printStackTrace();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified object into the list at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ Object result = notifyDelegate("displayGroupShouldInsertObject",
+ new Class[] { WODisplayGroup.class, Object.class, int.class },
+ new Object[] { this, anObject, new Integer(anIndex) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return;
+ }
+
+ updatedObjectIndex = anIndex;
+ willChange();
+
+ int i;
+
+ // add to all objects
+ if (anIndex == displayedObjects.size()) {
+ allObjects.addObject(anObject);
+ } else // insert before same object
+ {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+ int targetIndex = indexOf(allObjects, target);
+ if (targetIndex != NSArray.NotFound) {
+ allObjects.insertObjectAtIndex(anObject, targetIndex);
+ } else // should never happen
+ {
+ throw new WotonomyException("Could not find displayed object in all objects list: " + target);
+ }
+ }
+
+ // add to displayed objects
+ displayedObjects.insertObjectAtIndex(anObject, anIndex);
+
+ if (dataSource != null) {
+ if (dataSource instanceof OrderedDataSource) {
+ ((OrderedDataSource) dataSource).insertObjectAtIndex(anObject, anIndex);
+ } else {
+ dataSource.insertObject(anObject);
+ }
+ }
+
+ notifyDelegate("displayGroupDidInsertObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, anObject });
+ }
+
+ /**
+ * Sets contentsChanged to true and notifies all observers.
+ */
+ public void redisplay() {
+ willChange();
+ }
+
+ /**
+ * Sets the selection to the next displayed object after the current selection.
+ * If the last object is selected, or if no object is selected, then the first
+ * object becomes selected. If multiple items are selected, the first selected
+ * item is considered the selected item for the purposes of this method. Does
+ * not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectNext() {
+ int count = displayedObjects.count();
+ if (count == 0)
+ return null;
+ if (count == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ int i = -1;
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = -1;
+
+ // select next object
+ i++;
+ if (i != displayedObjects.count()) {
+ // set to next object
+ selectedObject = displayedObjects.objectAtIndex(i);
+ } else // out of range
+ {
+ // set to null
+ selectedObject = displayedObjects.objectAtIndex(0);
+ }
+
+ selectObject(selectedObject);
+ return null;
+ }
+
+ /**
+ * Sets the selection to the specified object. If the specified object is null
+ * or does not exist in the list of displayed objects, the selection will be
+ * cleared.
+ *
+ * @return true if the object was selected.
+ */
+ public boolean selectObject(Object anObject) {
+ if ((anObject == null) || (indexOf(displayedObjects, anObject) == NSArray.NotFound)) {
+ clearSelection();
+ return false;
+ }
+
+ selectObjectsIdenticalTo(new NSArray(new Object[] { anObject }));
+ return true;
+ }
+
+ /**
+ * Sets the selection to the specified objects. If the specified list is null or
+ * if none of the objects in the list exist in the list of displayed objects,
+ * the selection will be cleared.
+ *
+ * @return true if all specified objects were selected.
+ */
+ public boolean selectObjectsIdenticalTo(List anObjectList) {
+ // optimization: check for resetting of selection
+ if ((anObjectList != null) && (selectedObjects.size() == anObjectList.size())) {
+ boolean identical = true;
+ int size = selectedObjects.size();
+ for (int i = 0; (i < size) && identical; i++) {
+ // compare by reference
+ if (anObjectList.get(i) != selectedObjects.get(i)) {
+ identical = false;
+ } else if (displayedObjects.indexOfIdenticalObject(anObjectList.get(i)) == NSArray.NotFound) {
+ identical = false;
+ }
+ }
+ if (identical) {
+ return true;
+ }
+ }
+
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ // need to notify the calling component
+ // to revert back to the previous selection
+ selectionChanged = true;
+ willChange();
+ return false;
+ }
+
+ int i;
+ selectionChanged = true;
+ willChange();
+ Object o;
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) != NSArray.NotFound) {
+ selectedObjects.addObject(o);
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Calls selectObjectsIdenticalTo and if false is returned and
+ * selectFirstIfNoMatch is true, selects the first object.
+ */
+ public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(List anObjectList, boolean selectFirstIfNoMatch) {
+ if (selectObjectsIdenticalTo(anObjectList)) {
+ return true;
+ }
+ if (selectFirstIfNoMatch) {
+ clearSelection();
+ selectNext();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the selection to the previous displayed object before the current
+ * selection. If the first object is selected, or if no object is selected, then
+ * the last object becomes selected. If multiple items are selected, the first
+ * selected item is considered the selected item for the purposes of this
+ * method. Does not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectPrevious() {
+ int i = displayedObjects.count();
+ if (i == 0)
+ return null;
+ if (i == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = displayedObjects.count();
+
+ // select next object
+ i--;
+ if (i < 0) {
+ // out of range - select last object
+ i = displayedObjects.count() - 1;
+ }
+
+ selectObject(displayedObjects.objectAtIndex(i));
+ return null;
+ }
+
+ /**
+ * Returns the currently selected object, or null if there is no selection.
+ */
+ public Object selectedObject() {
+ if (selectedObjects.count() == 0) {
+ return null;
+ }
+ return selectedObjects.objectAtIndex(0);
+ }
+
+ /**
+ * Returns a read-only List containing all selected objects, if any. Returns an
+ * empty list if no objects are selected.
+ */
+ public NSArray selectedObjects() { // System.out.println( "avoided allocation: selectedObjects" );
+ return selectedObjectsProxy;
+ }
+
+ /**
+ * Returns a read-only List containing the indexes of all selected objects, if
+ * any. The list contains instances of java.lang.Number; call intValue() to
+ * retrieve the index.
+ */
+ public NSArray selectionIndexes() {
// return selectedIndexes;
- int i;
- NSMutableArray result = new NSMutableArray();
- Enumeration e = selectedObjects.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i != NSArray.NotFound )
- {
- result.addObject( new Integer( i ) );
- }
- else
- {
- System.err.println(
- "Should never happen: selected objects not in displayed objects" );
- new RuntimeException().printStackTrace( System.err );
- }
- }
- return result;
- }
-
- /**
- * Sets the objects managed by this display group.
- * updateDisplayedObjects() is called to filter the
- * display objects. The previous selection will be
- * maintained if possible. The data source is not
- * notified.
- */
- public void setObjectArray ( List anObjectList )
- {
- if ( anObjectList == null ) anObjectList = new NSArray();
-
- Object result = notifyDelegate(
- "displayGroupDisplayArrayForObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( result != null )
- {
- anObjectList = (List) result;
- }
-
- willChange();
-
- NSArray oldSelectedObjects = new NSArray( selectedObjects ); // copy
-
- // reset allObjects to new list
- allObjects.removeAllObjects();
- allObjects.addObjectsFromArray( anObjectList );
-
- // update the displayed object list
- updateDisplayedObjects();
-
- // restore the selection if possible
- selectObjectsIdenticalTo( oldSelectedObjects );
-
- batchIndex = 0;
- displayBatchContainingSelectedObject();
- }
-
- /**
- * Sets the currently selected object, or clears the
- * selection if the object is not found or is null.
- * Note: it's not clear how this differs from
- * selectObject in the spec. It is recommended that
- * you call selectObject for now.
- */
- public void setSelectedObject ( Object anObject )
- {
- selectObject( anObject );
- }
-
- /**
- * Sets the current selection to the specified objects.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- * Note: it's not clear how this differs from
- * selectObjectsIdenticalTo in the spec.
- * It is recommended that you call that method for now.
- */
- public void setSelectedObjects ( List aList )
- {
- selectObjectsIdenticalTo( aList );
- }
-
- /**
- * Sets the current selection to the objects at the
- * specified indexes. Items in the list are assumed
- * to be instances of java.lang.Number.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- */
- public boolean setSelectionIndexes ( List aList )
- {
- Object o;
- int index;
- NSMutableArray objects = new NSMutableArray();
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- index = ((Number)it.next()).intValue();
- if ( index < displayedObjects.count() )
- {
- o = displayedObjects.objectAtIndex( index );
- if ( o != null )
- {
- objects.add( o );
- }
- }
- }
- return selectObjectsIdenticalTo( objects );
- }
-
- /**
- * Applies the qualifier to all objects and sorts
- * the results to update the list of displayed objects.
- * Observing associations are notified to reflect the changes.
- */
- public void updateDisplayedObjects()
- {
- updatedObjectIndex = -1;
- willChange();
-
- displayedObjects.removeAllObjects();
-
- displayedObjects.addObjectsFromArray( allObjects );
-
- // apply qualifier, if any
- if ( qualifier != null )
- {
- EOQualifier.filterArrayWithQualifier(
- displayedObjects, qualifier );
- }
-
- // apply sort orderings, if any
- NSArray orderings = sortOrderings();
- if ( orderings != null )
- {
- if ( orderings.count() > 0 )
- {
- selectionChanged = true;
- willChange();
- EOSortOrdering.sortArrayUsingKeyOrderArray(
- displayedObjects, orderings );
- }
- }
-
- // make sure the selectedObjects is a subset of displayedObjects
- int i;
- Object o;
- Iterator it = new LinkedList( selectedObjects ).iterator();
- boolean removeflag = false;
- selectedIndexes.removeAllObjects();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- == NSArray.NotFound )
- {
- selectedObjects.removeIdenticalObject( o );
- removeflag = true;
- }
- else
- {
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- //Note: it is important to put the
- //selectionChanged = true line below remove.
- if (removeflag)
- {
- selectionChanged = true;
- willChange();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- }
- }
-
- /**
- * Returns the index of the changed object. If more than
- * one object has changed, -1 is returned.
- */
- public int updatedObjectIndex()
- {
- return updatedObjectIndex;
- }
-
- // getting and setting values in objects
-
- /**
- * Returns a value on the selected object for the specified key.
- */
- public Object selectedObjectValueForKey ( String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return null;
- return valueForObject( selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * all selected objects.
- */
- public boolean setSelectedObjectValue (
- Object aValue, String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return false;
- return setValueForObject( aValue, selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * the specified object. Validations may be triggered,
- * and error dialogs may appear to the user.
- * @return True if the value was set successfully,
- * false if the value could not be set and the update
- * operation should not continue.
- */
- public boolean setValueForObject (
- Object aValue, Object anObject, String aKey )
- {
- // notify object's observers:
- // this includes us, and will notify our observers
- EOObserverCenter.notifyObserversObjectWillChange( anObject );
-
- //TODO: if key is null, need to remove old object
- // and add new object instead of simply replacing it.
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( anObject, aValue, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return false;
- }
-
- notifyDelegate(
- "displayGroupDidSetValueForObject",
- new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
- new Object[] { this, aValue, anObject, aKey } );
-
- return true;
- }
-
- /**
- * Calls setValueForObject() for the object at
- * the specified index.
- */
- public boolean setValueForObjectAtIndex (
- Object aValue, int anIndex, String aKey )
- {
- return setValueForObject(
- aValue, displayedObjects.objectAtIndex( anIndex ), aKey );
- }
-
- /**
- * Returns the value for the specified key on the specified object.
- */
- public Object valueForObject ( Object anObject, String aKey )
- {
- // empty string is considered the identity property
- if ( aKey == null ) return anObject;
- if ( aKey.equals( "" ) ) return anObject;
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)anObject).valueForKey( aKey );
- }
- else
- {
- return EOKeyValueCodingSupport.valueForKey( anObject, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return null;
- }
- }
-
- /**
- * Calls valueForObject() for the object at the specified index.
- * Returns null if out of bounds.
- */
- public Object valueForObjectAtIndex ( int anIndex, String aKey )
- {
- if ( displayedObjects.count() <= anIndex ) return null;
- Object o = displayedObjects.objectAtIndex( anIndex );
- return valueForObject( o, aKey );
- }
-
- /**
- * Prints out the list of displayed objects.
- */
- public String toString()
- {
- return displayedObjects.toString();
- }
-
-
- /**
- * Handles notifications from the data source's editing context,
- * looking for InvalidatedAllObjectsInStoreNotification and
- * ObjectsChangedInEditingContextNotification, refetching in
- * the former case and updating displayed objects in the latter.
- * Note: This method is not in the public specification.
- */
- public void objectsInvalidatedInEditingContext( NSNotification aNotification )
- {
- if ( EOObjectStore.InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRefetch",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- fetch();
- }
- }
- else
- if ( EOEditingContext.ObjectsChangedInEditingContextNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRedisplay",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- int index;
- Enumeration e;
- boolean didChange = false;
- NSDictionary userInfo = aNotification.userInfo();
-
- // inserts are ignored
-
- // mark updated objects as updated
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- e = updates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: updated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // treat invalidated objects as updated
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- e = invalidates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: invalidated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // remove deletes from display group if they exist
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- e = deletes.objectEnumerator();
- Object o;
- while ( e.hasMoreElements() )
- {
- o = e.nextElement();
- index = indexOf( displayedObjects, o );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: deleted: " + o );
- deleteObjectAtIndexNoNotify( index );
- }
- }
-
- if ( !usesOptimisticRefresh() )
- {
- updateDisplayedObjects();
- }
- }
- }
-
- }
-
- // static methods
-
- /**
- * Specifies the default behavior for whether changes
- * should be validated immediately for all display groups.
- */
- public static boolean
- globalDefaultForValidatesChangesImmediately()
- {
- return globalDefaultForValidatesChangesImmediately;
- }
-
- /**
- * Specifies the default string matching format for all
- * display groups.
- */
- public static String globalDefaultStringMatchFormat()
- {
- return globalDefaultStringMatchFormat;
- }
-
- /**
- * Specifies the default string matching operator for all
- * display groups.
- */
- public static String globalDefaultStringMatchOperator()
- {
- return globalDefaultStringMatchOperator;
- }
-
- /**
- * Sets the default behavior for validating changes
- * for all display groups.
- */
- public static void
- setGlobalDefaultForValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- globalDefaultForValidatesChangesImmediately =
- validatesImmediately;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchFormat ( String aFormat )
- {
- globalDefaultStringMatchFormat = aFormat;
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchOperator ( String anOperator )
- {
- globalDefaultStringMatchOperator = anOperator;
- }
-
- /**
- * Needed because we don't inherit from NSObject.
- * Calls EOObserverCenter.notifyObserversObjectWillChange.
- */
- protected void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- /**
- * Returns the index of the specified object in the
- * specified NSArray, comparing by value or by reference
- * as determined by the private instance variable
- * compareByReference. If not found, returns NSArray.NotFound.
- */
- private int indexOf( NSArray anArray, Object anObject )
- {
- if ( compareByReference )
- {
- return anArray.indexOfIdenticalObject( anObject );
- }
- else
- {
- return anArray.indexOf( anObject );
- }
- }
-
- // interface EOObserving
-
- /**
- * Receives notifications of changes from objects that
- * are managed by this display group. This implementation
- * sets updatedObjectIndex as appropriate.
- */
- public void objectWillChange(Object anObject)
- {
- int index = indexOf( displayedObjects, anObject );
- if ( index != NSArray.NotFound )
- {
- updatedObjectIndex = index;
- willChange();
- }
- }
-
- // interface EOEditingContext.Editor
-
- /**
- * Called before the editing context begins to save changes.
- * This implementation calls endEditing().
- */
- public void editingContextWillSaveChanges(
- EOEditingContext anEditingContext )
- {
- endEditing();
- }
-
- /**
- * Called to determine whether this editor has changes
- * that have not been committed to the object in the context.
- * This implementation returns false.
- */
- public boolean editorHasChangesForEditingContext(
- EOEditingContext anEditingContext )
- {
- return false;
- }
-
- // interface EOEditingContext.MessageHandler
-
- /**
- * Called to display a message for an error that occurred
- * in the specified editing context. If the delegate allows,
- * this implementation writes a message to the standard output.
- * Override to customize.
- */
- public void editingContextPresentErrorMessage(
- EOEditingContext anEditingContext,
- String aMessage )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", aMessage } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- System.out.println( aMessage );
- }
- }
-
- /**
- * Called by the specified object store to determine whether
- * fetching should continue, where count is the current count
- * and limit is the limit as specified by the fetch specification.
- * This implementation returns true. Override to customize.
- */
- public boolean editingContextShouldContinueFetching(
- EOEditingContext anEditingContext,
- int count,
- int limit,
- EOObjectStore anObjectStore )
- {
- return true;
- }
-
- /**
- * Sends the specified message to the delegate.
- * Returns the return value of the method,
- * or null if no return value or no delegate
- * or no implementation.
- */
- private Object notifyDelegate(
- String aMethodName, Class[] types, Object[] params )
- {
- try
- {
- Object delegate = delegate();
- if ( delegate == null ) return null;
- return NSSelector.invoke(
- aMethodName, types, delegate, params );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while messaging delegate: " +
- delegate + " : " + aMethodName );
- exc.printStackTrace();
- }
-
- return null;
- }
-
- /**
- * DisplayGroups can delegate important decisions to a Delegate.
- * Note that DisplayGroup doesn't require its delegates to implement
- * this interface: rather, this interface defines the methods that
- * DisplayGroup will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- void displayGroupCreateObjectFailed (
- WODisplayGroup aDisplayGroup,
- EODataSource aDataSource );
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- void displayGroupDidChangeDataSource (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after a change occurs in the specified
- * display group's selected objects.
- */
- void displayGroupDidChangeSelectedObjects (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- void displayGroupDidChangeSelection (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group has
- * deleted the specified object.
- */
- void displayGroupDidDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- void displayGroupDidFetchObjects (
- WODisplayGroup aDisplayGroup,
- List anObjectList );
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- void displayGroupDidInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- void displayGroupDidSetValueForObject (
- WODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey );
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- NSArray displayGroupDisplayArrayForObjects (
- WODisplayGroup aDisplayGroup,
- List aList );
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- boolean displayGroupShouldChangeSelection (
- WODisplayGroup aDisplayGroup,
- List aSelectionList );
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- boolean displayGroupShouldDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- boolean displayGroupShouldDisplayAlert (
- WODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage );
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- boolean displayGroupShouldFetch (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- boolean displayGroupShouldInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * ObjectsChangedInEditingContextNotification.
- * @return True to allow the display group to
- * update the display (recommended), false
- * to prevent the update.
- */
- boolean displayGroupShouldRedisplay (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * InvalidatedAllObjectsInStoreNotification.
- * @return True to allow the display group to
- * refetch (recommended), false to prevent the
- * refetch.
- */
- boolean displayGroupShouldRefetch (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- }
+ int i;
+ NSMutableArray result = new NSMutableArray();
+ Enumeration e = selectedObjects.objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i != NSArray.NotFound) {
+ result.addObject(new Integer(i));
+ } else {
+ System.err.println("Should never happen: selected objects not in displayed objects");
+ new RuntimeException().printStackTrace(System.err);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the objects managed by this display group. updateDisplayedObjects() is
+ * called to filter the display objects. The previous selection will be
+ * maintained if possible. The data source is not notified.
+ */
+ public void setObjectArray(List anObjectList) {
+ if (anObjectList == null)
+ anObjectList = new NSArray();
+
+ Object result = notifyDelegate("displayGroupDisplayArrayForObjects",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if (result != null) {
+ anObjectList = (List) result;
+ }
+
+ willChange();
+
+ NSArray oldSelectedObjects = new NSArray(selectedObjects); // copy
+
+ // reset allObjects to new list
+ allObjects.removeAllObjects();
+ allObjects.addObjectsFromArray(anObjectList);
+
+ // update the displayed object list
+ updateDisplayedObjects();
+
+ // restore the selection if possible
+ selectObjectsIdenticalTo(oldSelectedObjects);
+
+ batchIndex = 0;
+ displayBatchContainingSelectedObject();
+ }
+
+ /**
+ * Sets the currently selected object, or clears the selection if the object is
+ * not found or is null. Note: it's not clear how this differs from selectObject
+ * in the spec. It is recommended that you call selectObject for now.
+ */
+ public void setSelectedObject(Object anObject) {
+ selectObject(anObject);
+ }
+
+ /**
+ * Sets the current selection to the specified objects. The previous selection
+ * is cleared, and any objects in the display group that are in the specified
+ * list are then selected. If no items in the specified list are found in the
+ * display group, then the selection is effectively cleared. Note: it's not
+ * clear how this differs from selectObjectsIdenticalTo in the spec. It is
+ * recommended that you call that method for now.
+ */
+ public void setSelectedObjects(List aList) {
+ selectObjectsIdenticalTo(aList);
+ }
+
+ /**
+ * Sets the current selection to the objects at the specified indexes. Items in
+ * the list are assumed to be instances of java.lang.Number. The previous
+ * selection is cleared, and any objects in the display group that are in the
+ * specified list are then selected. If no items in the specified list are found
+ * in the display group, then the selection is effectively cleared.
+ */
+ public boolean setSelectionIndexes(List aList) {
+ Object o;
+ int index;
+ NSMutableArray objects = new NSMutableArray();
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ index = ((Number) it.next()).intValue();
+ if (index < displayedObjects.count()) {
+ o = displayedObjects.objectAtIndex(index);
+ if (o != null) {
+ objects.add(o);
+ }
+ }
+ }
+ return selectObjectsIdenticalTo(objects);
+ }
+
+ /**
+ * Applies the qualifier to all objects and sorts the results to update the list
+ * of displayed objects. Observing associations are notified to reflect the
+ * changes.
+ */
+ public void updateDisplayedObjects() {
+ updatedObjectIndex = -1;
+ willChange();
+
+ displayedObjects.removeAllObjects();
+
+ displayedObjects.addObjectsFromArray(allObjects);
+
+ // apply qualifier, if any
+ if (qualifier != null) {
+ EOQualifier.filterArrayWithQualifier(displayedObjects, qualifier);
+ }
+
+ // apply sort orderings, if any
+ NSArray orderings = sortOrderings();
+ if (orderings != null) {
+ if (orderings.count() > 0) {
+ selectionChanged = true;
+ willChange();
+ EOSortOrdering.sortArrayUsingKeyOrderArray(displayedObjects, orderings);
+ }
+ }
+
+ // make sure the selectedObjects is a subset of displayedObjects
+ int i;
+ Object o;
+ Iterator it = new LinkedList(selectedObjects).iterator();
+ boolean removeflag = false;
+ selectedIndexes.removeAllObjects();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) == NSArray.NotFound) {
+ selectedObjects.removeIdenticalObject(o);
+ removeflag = true;
+ } else {
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ // Note: it is important to put the
+ // selectionChanged = true line below remove.
+ if (removeflag) {
+ selectionChanged = true;
+ willChange();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ }
+ }
+
+ /**
+ * Returns the index of the changed object. If more than one object has changed,
+ * -1 is returned.
+ */
+ public int updatedObjectIndex() {
+ return updatedObjectIndex;
+ }
+
+ // getting and setting values in objects
+
+ /**
+ * Returns a value on the selected object for the specified key.
+ */
+ public Object selectedObjectValueForKey(String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return null;
+ return valueForObject(selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on all selected objects.
+ */
+ public boolean setSelectedObjectValue(Object aValue, String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return false;
+ return setValueForObject(aValue, selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on the specified object.
+ * Validations may be triggered, and error dialogs may appear to the user.
+ *
+ * @return True if the value was set successfully, false if the value could not
+ * be set and the update operation should not continue.
+ */
+ public boolean setValueForObject(Object aValue, Object anObject, String aKey) {
+ // notify object's observers:
+ // this includes us, and will notify our observers
+ EOObserverCenter.notifyObserversObjectWillChange(anObject);
+
+ // TODO: if key is null, need to remove old object
+ // and add new object instead of simply replacing it.
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).takeValueForKey(aValue, aKey);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(anObject, aValue, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return false;
+ }
+
+ notifyDelegate("displayGroupDidSetValueForObject",
+ new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
+ new Object[] { this, aValue, anObject, aKey });
+
+ return true;
+ }
+
+ /**
+ * Calls setValueForObject() for the object at the specified index.
+ */
+ public boolean setValueForObjectAtIndex(Object aValue, int anIndex, String aKey) {
+ return setValueForObject(aValue, displayedObjects.objectAtIndex(anIndex), aKey);
+ }
+
+ /**
+ * Returns the value for the specified key on the specified object.
+ */
+ public Object valueForObject(Object anObject, String aKey) {
+ // empty string is considered the identity property
+ if (aKey == null)
+ return anObject;
+ if (aKey.equals(""))
+ return anObject;
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) anObject).valueForKey(aKey);
+ } else {
+ return EOKeyValueCodingSupport.valueForKey(anObject, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Calls valueForObject() for the object at the specified index. Returns null if
+ * out of bounds.
+ */
+ public Object valueForObjectAtIndex(int anIndex, String aKey) {
+ if (displayedObjects.count() <= anIndex)
+ return null;
+ Object o = displayedObjects.objectAtIndex(anIndex);
+ return valueForObject(o, aKey);
+ }
+
+ /**
+ * Prints out the list of displayed objects.
+ */
+ public String toString() {
+ return displayedObjects.toString();
+ }
+
+ /**
+ * Handles notifications from the data source's editing context, looking for
+ * InvalidatedAllObjectsInStoreNotification and
+ * ObjectsChangedInEditingContextNotification, refetching in the former case and
+ * updating displayed objects in the latter. Note: This method is not in the
+ * public specification.
+ */
+ public void objectsInvalidatedInEditingContext(NSNotification aNotification) {
+ if (EOObjectStore.InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRefetch",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ fetch();
+ }
+ } else if (EOEditingContext.ObjectsChangedInEditingContextNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRedisplay",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ int index;
+ Enumeration e;
+ boolean didChange = false;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // inserts are ignored
+
+ // mark updated objects as updated
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ e = updates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: updated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // treat invalidated objects as updated
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ e = invalidates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: invalidated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // remove deletes from display group if they exist
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ e = deletes.objectEnumerator();
+ Object o;
+ while (e.hasMoreElements()) {
+ o = e.nextElement();
+ index = indexOf(displayedObjects, o);
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: deleted: " + o );
+ deleteObjectAtIndexNoNotify(index);
+ }
+ }
+
+ if (!usesOptimisticRefresh()) {
+ updateDisplayedObjects();
+ }
+ }
+ }
+
+ }
+
+ // static methods
+
+ /**
+ * Specifies the default behavior for whether changes should be validated
+ * immediately for all display groups.
+ */
+ public static boolean globalDefaultForValidatesChangesImmediately() {
+ return globalDefaultForValidatesChangesImmediately;
+ }
+
+ /**
+ * Specifies the default string matching format for all display groups.
+ */
+ public static String globalDefaultStringMatchFormat() {
+ return globalDefaultStringMatchFormat;
+ }
+
+ /**
+ * Specifies the default string matching operator for all display groups.
+ */
+ public static String globalDefaultStringMatchOperator() {
+ return globalDefaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the default behavior for validating changes for all display groups.
+ */
+ public static void setGlobalDefaultForValidatesChangesImmediately(boolean validatesImmediately) {
+ globalDefaultForValidatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchFormat(String aFormat) {
+ globalDefaultStringMatchFormat = aFormat;
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchOperator(String anOperator) {
+ globalDefaultStringMatchOperator = anOperator;
+ }
+
+ /**
+ * Needed because we don't inherit from NSObject. Calls
+ * EOObserverCenter.notifyObserversObjectWillChange.
+ */
+ protected void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ /**
+ * Returns the index of the specified object in the specified NSArray, comparing
+ * by value or by reference as determined by the private instance variable
+ * compareByReference. If not found, returns NSArray.NotFound.
+ */
+ private int indexOf(NSArray anArray, Object anObject) {
+ if (compareByReference) {
+ return anArray.indexOfIdenticalObject(anObject);
+ } else {
+ return anArray.indexOf(anObject);
+ }
+ }
+
+ // interface EOObserving
+
+ /**
+ * Receives notifications of changes from objects that are managed by this
+ * display group. This implementation sets updatedObjectIndex as appropriate.
+ */
+ public void objectWillChange(Object anObject) {
+ int index = indexOf(displayedObjects, anObject);
+ if (index != NSArray.NotFound) {
+ updatedObjectIndex = index;
+ willChange();
+ }
+ }
+
+ // interface EOEditingContext.Editor
+
+ /**
+ * Called before the editing context begins to save changes. This implementation
+ * calls endEditing().
+ */
+ public void editingContextWillSaveChanges(EOEditingContext anEditingContext) {
+ endEditing();
+ }
+
+ /**
+ * Called to determine whether this editor has changes that have not been
+ * committed to the object in the context. This implementation returns false.
+ */
+ public boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext) {
+ return false;
+ }
+
+ // interface EOEditingContext.MessageHandler
+
+ /**
+ * Called to display a message for an error that occurred in the specified
+ * editing context. If the delegate allows, this implementation writes a message
+ * to the standard output. Override to customize.
+ */
+ public void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", aMessage });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ System.out.println(aMessage);
+ }
+ }
+
+ /**
+ * Called by the specified object store to determine whether fetching should
+ * continue, where count is the current count and limit is the limit as
+ * specified by the fetch specification. This implementation returns true.
+ * Override to customize.
+ */
+ public boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit,
+ EOObjectStore anObjectStore) {
+ return true;
+ }
+
+ /**
+ * Sends the specified message to the delegate. Returns the return value of the
+ * method, or null if no return value or no delegate or no implementation.
+ */
+ private Object notifyDelegate(String aMethodName, Class[] types, Object[] params) {
+ try {
+ Object delegate = delegate();
+ if (delegate == null)
+ return null;
+ return NSSelector.invoke(aMethodName, types, delegate, params);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while messaging delegate: " + delegate + " : " + aMethodName);
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * DisplayGroups can delegate important decisions to a Delegate. Note that
+ * DisplayGroup doesn't require its delegates to implement this interface:
+ * rather, this interface defines the methods that DisplayGroup will attempt to
+ * invoke dynamically on its delegate. The delegate may choose to implement only
+ * a subset of the methods on the interface.
+ */
+ public interface Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ void displayGroupCreateObjectFailed(WODisplayGroup aDisplayGroup, EODataSource aDataSource);
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ void displayGroupDidChangeDataSource(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after a change occurs in the specified display group's selected
+ * objects.
+ */
+ void displayGroupDidChangeSelectedObjects(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ void displayGroupDidChangeSelection(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group has deleted the specified object.
+ */
+ void displayGroupDidDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ void displayGroupDidFetchObjects(WODisplayGroup aDisplayGroup, List anObjectList);
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ void displayGroupDidInsertObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ void displayGroupDidSetValueForObject(WODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey);
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ NSArray displayGroupDisplayArrayForObjects(WODisplayGroup aDisplayGroup, List aList);
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ boolean displayGroupShouldChangeSelection(WODisplayGroup aDisplayGroup, List aSelectionList);
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ boolean displayGroupShouldDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ boolean displayGroupShouldDisplayAlert(WODisplayGroup aDisplayGroup, String aTitle, String aMessage);
+
+ /**
+ * Called by the specified display group before it attempts fetch objects.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ boolean displayGroupShouldFetch(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ boolean displayGroupShouldInsertObject(WODisplayGroup aDisplayGroup, Object anObject, int anIndex);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * ObjectsChangedInEditingContextNotification.
+ *
+ * @return True to allow the display group to update the display (recommended),
+ * false to prevent the update.
+ */
+ boolean displayGroupShouldRedisplay(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * InvalidatedAllObjectsInStoreNotification.
+ *
+ * @return True to allow the display group to refetch (recommended), false to
+ * prevent the refetch.
+ */
+ boolean displayGroupShouldRefetch(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.6 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.5 2003/01/22 23:01:06 mpowers
- * Better handling for index out of bounds.
+ * Revision 1.5 2003/01/22 23:01:06 mpowers Better handling for index out of
+ * bounds.
*
- * Revision 1.4 2003/01/21 22:27:02 mpowers
- * Corrected context id usage.
+ * Revision 1.4 2003/01/21 22:27:02 mpowers Corrected context id usage.
* Implemented backtracking.
*
- * Revision 1.3 2003/01/21 17:54:01 mpowers
- * Batch indices are one-based, not zero-based.
+ * Revision 1.3 2003/01/21 17:54:01 mpowers Batch indices are one-based, not
+ * zero-based.
*
- * Revision 1.2 2003/01/21 14:38:42 mpowers
- * Fixed batching.
+ * Revision 1.2 2003/01/21 14:38:42 mpowers Fixed batching.
*
- * Revision 1.1 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.1 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.46 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.46 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.45 2002/10/24 18:20:20 mpowers
- * Because NSArray is read-only, we are returning our internal representations
- * to callers of allObjects(), displayedObjects(), and selectedObjects().
+ * Revision 1.45 2002/10/24 18:20:20 mpowers Because NSArray is read-only, we
+ * are returning our internal representations to callers of allObjects(),
+ * displayedObjects(), and selectedObjects().
*
- * Revision 1.44 2002/08/06 18:20:25 mpowers
- * Now posting DisplayGroupWillFetch notifications before fetch.
- * Implemented support for usesOptimisticRefresh.
- * No longer supporting inserted/updated/deleted lists: not part of spec.
+ * Revision 1.44 2002/08/06 18:20:25 mpowers Now posting DisplayGroupWillFetch
+ * notifications before fetch. Implemented support for usesOptimisticRefresh. No
+ * longer supporting inserted/updated/deleted lists: not part of spec.
*
- * Revision 1.43 2002/05/17 15:01:49 mpowers
- * Implemented dynamic lookup of delegate methods so delegates no longer
- * need to implement the DisplayGroup.Delegate interface.
+ * Revision 1.43 2002/05/17 15:01:49 mpowers Implemented dynamic lookup of
+ * delegate methods so delegates no longer need to implement the
+ * DisplayGroup.Delegate interface.
*
- * Revision 1.42 2002/03/26 21:46:06 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.42 2002/03/26 21:46:06 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
- * Revision 1.41 2002/03/11 03:17:56 mpowers
- * Provided control point for coalesced changes.
+ * Revision 1.41 2002/03/11 03:17:56 mpowers Provided control point for
+ * coalesced changes.
*
- * Revision 1.40 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.40 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.39 2002/02/19 22:26:04 mpowers
- * Implemented EOEditingContext.MessageHandler support.
+ * Revision 1.39 2002/02/19 22:26:04 mpowers Implemented
+ * EOEditingContext.MessageHandler support.
*
- * Revision 1.38 2002/02/19 16:37:38 mpowers
- * Implemented support for EOEditingContext.Editor
+ * Revision 1.38 2002/02/19 16:37:38 mpowers Implemented support for
+ * EOEditingContext.Editor
*
- * Revision 1.37 2001/12/11 22:17:48 mpowers
- * Now properly handling exceptions in valueForObject.
- * No longer trying to retain selection based only on index.
+ * Revision 1.37 2001/12/11 22:17:48 mpowers Now properly handling exceptions in
+ * valueForObject. No longer trying to retain selection based only on index.
*
- * Revision 1.36 2001/11/08 21:42:00 mpowers
- * Now we know what to do with shouldRefetch and shouldRedisplay.
+ * Revision 1.36 2001/11/08 21:42:00 mpowers Now we know what to do with
+ * shouldRefetch and shouldRedisplay.
*
- * Revision 1.35 2001/11/04 18:26:58 mpowers
- * Fixed bug where exceptions were not properly reported when updating
- * a value and the display group did not have a delegate.
+ * Revision 1.35 2001/11/04 18:26:58 mpowers Fixed bug where exceptions were not
+ * properly reported when updating a value and the display group did not have a
+ * delegate.
*
- * Revision 1.34 2001/11/02 20:59:36 mpowers
- * Now correctly ensuring selected objects are a subset of displayed objects.
+ * Revision 1.34 2001/11/02 20:59:36 mpowers Now correctly ensuring selected
+ * objects are a subset of displayed objects.
*
- * Revision 1.33 2001/10/30 22:56:45 mpowers
- * Added support for EOQualifier.
+ * Revision 1.33 2001/10/30 22:56:45 mpowers Added support for EOQualifier.
*
- * Revision 1.32 2001/10/23 22:27:53 mpowers
- * Now running at ObserverPrioritySixth.
+ * Revision 1.32 2001/10/23 22:27:53 mpowers Now running at
+ * ObserverPrioritySixth.
*
- * Revision 1.31 2001/10/23 18:45:05 mpowers
- * Rolling back changes.
+ * Revision 1.31 2001/10/23 18:45:05 mpowers Rolling back changes.
*
- * Revision 1.28 2001/08/22 19:23:41 mpowers
- * No longer asserting objects in all objects list.
+ * Revision 1.28 2001/08/22 19:23:41 mpowers No longer asserting objects in all
+ * objects list.
*
- * Revision 1.27 2001/07/30 16:17:01 mpowers
- * Minor code cleanup.
+ * Revision 1.27 2001/07/30 16:17:01 mpowers Minor code cleanup.
*
- * Revision 1.26 2001/07/10 22:49:07 mpowers
- * Fixed bug in optimization for selectObjectsIdenticalTo (found by Dongzhi).
+ * Revision 1.26 2001/07/10 22:49:07 mpowers Fixed bug in optimization for
+ * selectObjectsIdenticalTo (found by Dongzhi).
*
- * Revision 1.25 2001/06/19 15:40:21 mpowers
- * Now only changing the selection if the new selection is different
- * from the old.
+ * Revision 1.25 2001/06/19 15:40:21 mpowers Now only changing the selection if
+ * the new selection is different from the old.
*
- * Revision 1.24 2001/05/24 17:36:15 mpowers
- * Fixed problem with selectedObjectsIdenticalTo: it was using compare
- * by value instead of compare by reference.
+ * Revision 1.24 2001/05/24 17:36:15 mpowers Fixed problem with
+ * selectedObjectsIdenticalTo: it was using compare by value instead of compare
+ * by reference.
*
- * Revision 1.23 2001/05/18 21:09:19 mpowers
- * Now throwing exceptions if the delegate cannot handle error from update.
+ * Revision 1.23 2001/05/18 21:09:19 mpowers Now throwing exceptions if the
+ * delegate cannot handle error from update.
*
- * Revision 1.22 2001/05/14 15:26:12 mpowers
- * Now checking for null delegate before and after selection change.
+ * Revision 1.22 2001/05/14 15:26:12 mpowers Now checking for null delegate
+ * before and after selection change.
*
- * Revision 1.21 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.21 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.20 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.20 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.19 2001/04/13 16:38:09 mpowers
- * Alpha3 release.
+ * Revision 1.19 2001/04/13 16:38:09 mpowers Alpha3 release.
*
- * Revision 1.18 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.18 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.17 2001/03/29 03:31:13 mpowers
- * No longer using Introspector.
+ * Revision 1.17 2001/03/29 03:31:13 mpowers No longer using Introspector.
*
- * Revision 1.16 2001/02/27 03:32:18 mpowers
- * Implemented default values for new objects.
+ * Revision 1.16 2001/02/27 03:32:18 mpowers Implemented default values for new
+ * objects.
*
- * Revision 1.15 2001/02/27 02:11:17 mpowers
- * Now throwing exception when cloning fails.
- * Removed debugging printlns.
+ * Revision 1.15 2001/02/27 02:11:17 mpowers Now throwing exception when cloning
+ * fails. Removed debugging printlns.
*
- * Revision 1.14 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.14 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.13 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.13 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.12 2001/02/22 20:55:06 mpowers
- * Implemented notification handling.
+ * Revision 1.12 2001/02/22 20:55:06 mpowers Implemented notification handling.
*
- * Revision 1.11 2001/02/21 20:40:42 mpowers
- * setObjectArray now falls back to index when trying to retain the
- * same selection.
+ * Revision 1.11 2001/02/21 20:40:42 mpowers setObjectArray now falls back to
+ * index when trying to retain the same selection.
*
- * Revision 1.10 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.10 2001/02/20 16:38:55 mpowers MasterDetailAssociations now
+ * observe their controlled display group's objects for changes to that the
+ * parent object will be marked as updated. Before, only inserts and deletes to
+ * an object's items are registered. Also, moved ObservableArray to package
+ * access.
*
- * Revision 1.9 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.9 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.8 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.7 2001/01/24 16:35:37 mpowers
- * Improved documentation on TreeAssociation.
- * SortOrderings are now inherited from parent nodes.
- * Updates after sorting are still lost on TreeController.
+ * Revision 1.7 2001/01/24 16:35:37 mpowers Improved documentation on
+ * TreeAssociation. SortOrderings are now inherited from parent nodes. Updates
+ * after sorting are still lost on TreeController.
*
- * Revision 1.6 2001/01/24 14:23:05 mpowers
- * Added support for OrderedDataSource.
+ * Revision 1.6 2001/01/24 14:23:05 mpowers Added support for OrderedDataSource.
*
- * Revision 1.5 2001/01/12 17:21:37 mpowers
- * Implicit creation of EOSortOrderings now happens in setSortOrderings.
+ * Revision 1.5 2001/01/12 17:21:37 mpowers Implicit creation of EOSortOrderings
+ * now happens in setSortOrderings.
*
- * Revision 1.4 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.4 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.3 2001/01/10 22:49:44 mpowers
- * Implemented similarly named selection methods instead of
- * throwing exceptions.
+ * Revision 1.3 2001/01/10 22:49:44 mpowers Implemented similarly named
+ * selection methods instead of throwing exceptions.
*
- * Revision 1.2 2001/01/09 20:12:52 mpowers
- * Moved inner classes to package access.
+ * Revision 1.2 2001/01/09 20:12:52 mpowers Moved inner classes to package
+ * access.
*
- * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers Contributing wotonomy.
*
- * Revision 1.21 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.21 2000/12/20 16:25:39 michael Added log to all files.
*
- * Revision 1.20 2000/12/15 15:04:42 michael
- * Added doc.
+ * Revision 1.20 2000/12/15 15:04:42 michael Added doc.
*
- * Revision 1.19 2000/12/11 13:32:48 michael
- * Finish the much better TreeAssociation implementation.
- * TreeAssociation now has no gui dependencies.
+ * Revision 1.19 2000/12/11 13:32:48 michael Finish the much better
+ * TreeAssociation implementation. TreeAssociation now has no gui dependencies.
*
- * Revision 1.18 2000/12/05 17:41:46 michael
- * Broadcasts selection change after delegate refuses selection change
- * so the initiating association gets refreshed.
+ * Revision 1.18 2000/12/05 17:41:46 michael Broadcasts selection change after
+ * delegate refuses selection change so the initiating association gets
+ * refreshed.
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
index 6e449c3..6abb7d6 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODynamicElement.java
@@ -27,182 +27,175 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* The base class for dynamic WOElements. Dynamic elements
-* are expected to do something useful with user-entered data
-* in the request and with any binding associations with the
-* context's current WOComponent.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WODynamicElement
- extends WOElement
-{
+ * The base class for dynamic WOElements. Dynamic elements are expected to do
+ * something useful with user-entered data in the request and with any binding
+ * associations with the context's current WOComponent.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WODynamicElement extends WOElement {
protected String name;
protected WOElement rootElement;
- protected NSDictionary associations;
-
- /**
- * The default constructor.
- */
- protected WODynamicElement ()
- {
- name = null;
- associations = new NSMutableDictionary();
- rootElement = null;
- }
-
- /**
- * Required constructor specifying the class name of the component,
- * a map of associations, and the root element of the tree that
- * contains this element (which may be null). The map keys
- * correspond to properties of this element, and the values are
- * associations to be applied to the context's current component.
- */
- public WODynamicElement (
- String aName, NSDictionary anAssociationMap, WOElement aRootElement)
- {
- this();
- name = aName;
- associations = anAssociationMap;
- rootElement = aRootElement;
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.ensureAwakeInContext( aContext );
- }
- }
-
- /**
- * Use this method to get a map with the properties that start with
- * a question mark. These are supposed to go at the end of a URL, and it is
- * very useful for components that generate URLs, specially with direct
- * actions.
- * @param c The component where the values of the properties have to be
- * retrieved from.
- */
- Map urlFields(WOComponent c) {
- HashMap map = new HashMap(associations.count());
- Enumeration enumeration = associations.keyEnumerator();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (key.charAt(0) == '?') {
- map.put(key.substring(1), valueForProperty(key, c));
- }
- }
- return map;
- }
-
- /** Convenience method for getting the value of an association. */
- Object valueForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- if (a != null)
- return a.valueInComponent(c);
- return null;
- }
-
- /** Convenience method for getting the string value of an association. */
- String stringForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- Object result = null;
- if (a != null) result = a.valueInComponent(c);
- if ( result == null ) return null;
- return result.toString();
- }
-
- /** Convenience method for getting the string value of an association. */
- boolean booleanForProperty(String key, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- Object result = null;
- if (a != null) result = a.valueInComponent(c);
- if ( result == null ) return false;
- if ( result.toString().toLowerCase().equals( "true" ) ) return true;
- return Boolean.TRUE.equals( result );
- }
-
- /** Convenience method for setting the value of an association. */
- void setValueForProperty(String key, Object value, WOComponent c) {
- WOAssociation a = (WOAssociation)associations.objectForKey(key);
- if ( a != null && a.isValueSettable() )
- a.setValue(value, c);
- }
-
- /** this method composes a String suitable for inclusion inside a HTML tag. It includes
- the key-value pairs of all the associations not mentioned in the standardProperties
- parameter. This is very useful for including extra properties in tags without having to worry
- if the HTML specification has changed or if non-standard tags are being used.
- @param c The component where the associations' values should be retrieved from.
- @param standardProperties An array of Strings with all the associations that should be
- excluded from the resulting string. */
- String additionalHTMLProperties(WOComponent c, NSArray standardProperties) {
- Enumeration enumeration = associations.keyEnumerator();
- StringBuffer buf = new StringBuffer();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- if (!(standardProperties.containsObject(key) || key.charAt(0)=='?')) {
- buf.append(' ');
- buf.append(key);
- buf.append("=\"");
- buf.append(valueForProperty(key, c));
- buf.append('\"');
- }
- }
- return buf.toString();
- }
-
- /**
- * This method is called to retrieve user-entered data from
- * the request. WOElements should retrieve data from the
- * request based on their elementID and set values in the
- * context's current WOComponent, typically those values that
- * are associated with the element in the binding. This
- * implementation does nothing.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
-
+ protected NSDictionary associations;
+
+ /**
+ * The default constructor.
+ */
+ protected WODynamicElement() {
+ name = null;
+ associations = new NSMutableDictionary();
+ rootElement = null;
+ }
+
+ /**
+ * Required constructor specifying the class name of the component, a map of
+ * associations, and the root element of the tree that contains this element
+ * (which may be null). The map keys correspond to properties of this element,
+ * and the values are associations to be applied to the context's current
+ * component.
+ */
+ public WODynamicElement(String aName, NSDictionary anAssociationMap, WOElement aRootElement) {
+ this();
+ name = aName;
+ associations = anAssociationMap;
+ rootElement = aRootElement;
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.ensureAwakeInContext(aContext);
+ }
+ }
+
+ /**
+ * Use this method to get a map with the properties that start with a question
+ * mark. These are supposed to go at the end of a URL, and it is very useful for
+ * components that generate URLs, specially with direct actions.
+ *
+ * @param c The component where the values of the properties have to be
+ * retrieved from.
+ */
+ Map urlFields(WOComponent c) {
+ HashMap map = new HashMap(associations.count());
+ Enumeration enumeration = associations.keyEnumerator();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (key.charAt(0) == '?') {
+ map.put(key.substring(1), valueForProperty(key, c));
+ }
+ }
+ return map;
+ }
+
+ /** Convenience method for getting the value of an association. */
+ Object valueForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ if (a != null)
+ return a.valueInComponent(c);
+ return null;
+ }
+
+ /** Convenience method for getting the string value of an association. */
+ String stringForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ Object result = null;
+ if (a != null)
+ result = a.valueInComponent(c);
+ if (result == null)
+ return null;
+ return result.toString();
+ }
+
+ /** Convenience method for getting the string value of an association. */
+ boolean booleanForProperty(String key, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ Object result = null;
+ if (a != null)
+ result = a.valueInComponent(c);
+ if (result == null)
+ return false;
+ if (result.toString().toLowerCase().equals("true"))
+ return true;
+ return Boolean.TRUE.equals(result);
}
- /**
- * This method is called on all objects and elements of the
- * application until a non-null value is returned.
- * WOElements should first check to see if they are the
- * target of an action by checking the WOContext's senderID
- * to see if it matches this element's elementID.
- * If this element is the target, it should perform an
- * appropriate action on the context's current WOComponent,
- * usually the action specified in the binding, and return
- * the result of that action. This implementation returns null.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return null;
- }
-
- /**
- * This method is called on all elements of the content tree
- * to build a response to a user request. The message should
- * be forwarded to any child elements so that the entire tree
- * is traversed. This implementation does nothing.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- // does nothing
- }
-
- public WOResponse generateResponse()
- {
- return null;
- }
+ /** Convenience method for setting the value of an association. */
+ void setValueForProperty(String key, Object value, WOComponent c) {
+ WOAssociation a = (WOAssociation) associations.objectForKey(key);
+ if (a != null && a.isValueSettable())
+ a.setValue(value, c);
+ }
+
+ /**
+ * this method composes a String suitable for inclusion inside a HTML tag. It
+ * includes the key-value pairs of all the associations not mentioned in the
+ * standardProperties parameter. This is very useful for including extra
+ * properties in tags without having to worry if the HTML specification has
+ * changed or if non-standard tags are being used.
+ *
+ * @param c The component where the associations' values should
+ * be retrieved from.
+ * @param standardProperties An array of Strings with all the associations that
+ * should be excluded from the resulting string.
+ */
+ String additionalHTMLProperties(WOComponent c, NSArray standardProperties) {
+ Enumeration enumeration = associations.keyEnumerator();
+ StringBuffer buf = new StringBuffer();
+ while (enumeration.hasMoreElements()) {
+ String key = (String) enumeration.nextElement();
+ if (!(standardProperties.containsObject(key) || key.charAt(0) == '?')) {
+ buf.append(' ');
+ buf.append(key);
+ buf.append("=\"");
+ buf.append(valueForProperty(key, c));
+ buf.append('\"');
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * This method is called to retrieve user-entered data from the request.
+ * WOElements should retrieve data from the request based on their elementID and
+ * set values in the context's current WOComponent, typically those values that
+ * are associated with the element in the binding. This implementation does
+ * nothing.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+
+ }
+
+ /**
+ * This method is called on all objects and elements of the application until a
+ * non-null value is returned. WOElements should first check to see if they are
+ * the target of an action by checking the WOContext's senderID to see if it
+ * matches this element's elementID. If this element is the target, it should
+ * perform an appropriate action on the context's current WOComponent, usually
+ * the action specified in the binding, and return the result of that action.
+ * This implementation returns null.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return null;
+ }
+
+ /**
+ * This method is called on all elements of the content tree to build a response
+ * to a user request. The message should be forwarded to any child elements so
+ * that the entire tree is traversed. This implementation does nothing.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ // does nothing
+ }
+
+ public WOResponse generateResponse() {
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
index 11944d3..184eeea 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOElement.java
@@ -23,75 +23,62 @@ import java.io.Serializable;
import net.wotonomy.foundation.NSDictionary;
/**
-* This class represents a static or dynamic portion of the
-* content returned to a request. Each request walks a tree
-* of WOElements to generate a response.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WOElement implements WOActionResults, Serializable
-{
+ * This class represents a static or dynamic portion of the content returned to
+ * a request. Each request walks a tree of WOElements to generate a response.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WOElement implements WOActionResults, Serializable {
NSDictionary associations;
-
+
+ /**
+ * Default constructor. Performs necessary initialization.
+ */
+ public WOElement() {
+ }
+
/**
- * Default constructor. Performs necessary initialization.
- */
- public WOElement()
- {
+ * This method is called to retrieve user-entered data from the request.
+ * WOElements should retrieve data from the request based on their elementID and
+ * set values in the context's current WOComponent, typically those values that
+ * are associated with the element in the binding. This implementation does
+ * nothing.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ // does nothing
}
/**
- * This method is called to retrieve user-entered data from
- * the request. WOElements should retrieve data from the
- * request based on their elementID and set values in the
- * context's current WOComponent, typically those values that
- * are associated with the element in the binding. This
- * implementation does nothing.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- // does nothing
- }
+ * This method is called on all objects and elements of the application until a
+ * non-null value is returned. WOElements should first check to see if they are
+ * the target of an action by checking the WOContext's senderID to see if it
+ * matches this element's elementID. If this element is the target, it should
+ * perform an appropriate action on the context's current WOComponent, usually
+ * the action specified in the binding, and return the result of that action.
+ * This implementation returns null.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return null;
+ }
- /**
- * This method is called on all objects and elements of the
- * application until a non-null value is returned.
- * WOElements should first check to see if they are the
- * target of an action by checking the WOContext's senderID
- * to see if it matches this element's elementID.
- * If this element is the target, it should perform an
- * appropriate action on the context's current WOComponent,
- * usually the action specified in the binding, and return
- * the result of that action. This implementation returns null.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return null;
- }
-
- /**
- * This method is called on all elements of the content tree
- * to build a response to a user request. The message should
- * be forwarded to any child elements so that the entire tree
- * is traversed. This implementation does nothing.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- // does nothing
- }
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- // does nothing
- }
+ /**
+ * This method is called on all elements of the content tree to build a response
+ * to a user request. The message should be forwarded to any child elements so
+ * that the entire tree is traversed. This implementation does nothing.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ // does nothing
+ }
+
+ /**
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ // does nothing
+ }
-
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
index 887d1a3..b4dca91 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOForm.java
@@ -21,104 +21,101 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
-/**
-* Implements a FORM element with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+/**
+ * Implements a FORM element with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOForm extends WODynamicElement {
- public WOForm() {
- super();
- }
-
- public WOForm(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
-
- public String href(WOContext c) {
- return (String)valueForProperty("href", c.component());
- }
-
- public String directActionName(WOContext c) {
- return (String)valueForProperty("directAction", c.component());
- }
-
- public String directActionClass(WOContext c) {
- return (String)valueForProperty("actionClass", c.component());
- }
-
- public boolean multipleSubmit(WOContext c) {
- return booleanForProperty("multipleSubmit", c.component());
- }
-
- public void takeValuesFromRequest (
- WORequest aRequest, WOContext aContext)
- {
- if ( rootElement != null )
- {
- rootElement.takeValuesFromRequest( aRequest, aContext );
- }
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- //Append the opening tag
- r.appendContentString("<FORM");
- String link = href(c);
- //Append the href, if present
- if (link != null) {
- r.appendContentString(" HREF=\"");
- r.appendContentString(link);
- r.appendContentString("\"");
- link = null;
- } else {
- link = directActionName(c);
- }
-
- //otherwise, append Direct Action
- if (link != null) {
- r.appendContentString(" HREF=\"");
- if (directActionClass(c) != null)
- link = directActionClass(c) + "/" + link;
- r.appendContentString(c.directActionURLForActionNamed(link, urlFields(c.component())));
- r.appendContentString("\"");
- link = null;
+ public WOForm() {
+ super();
+ }
+
+ public WOForm(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
+
+ public String href(WOContext c) {
+ return (String) valueForProperty("href", c.component());
+ }
+
+ public String directActionName(WOContext c) {
+ return (String) valueForProperty("directAction", c.component());
+ }
+
+ public String directActionClass(WOContext c) {
+ return (String) valueForProperty("actionClass", c.component());
+ }
+
+ public boolean multipleSubmit(WOContext c) {
+ return booleanForProperty("multipleSubmit", c.component());
+ }
+
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ if (rootElement != null) {
+ rootElement.takeValuesFromRequest(aRequest, aContext);
+ }
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ // Append the opening tag
+ r.appendContentString("<FORM");
+ String link = href(c);
+ // Append the href, if present
+ if (link != null) {
+ r.appendContentString(" HREF=\"");
+ r.appendContentString(link);
+ r.appendContentString("\"");
+ link = null;
+ } else {
+ link = directActionName(c);
+ }
+
+ // otherwise, append Direct Action
+ if (link != null) {
+ r.appendContentString(" HREF=\"");
+ if (directActionClass(c) != null)
+ link = directActionClass(c) + "/" + link;
+ r.appendContentString(c.directActionURLForActionNamed(link, urlFields(c.component())));
+ r.appendContentString("\"");
+ link = null;
// } else if (associations.objectForKey("action") != null) {
- } else {
- //finally, append action
- r.appendContentString(" action=\"");
- r.appendContentString(c.componentActionURL());
- r.appendContentString("\"");
- } //else
+ } else {
+ // finally, append action
+ r.appendContentString(" action=\"");
+ r.appendContentString(c.componentActionURL());
+ r.appendContentString("\"");
+ } // else
// now defaulting to action if not specified(?): WOBuilder does generate WOForms without any bindings(!)
// throw new IllegalArgumentException("You must use one of directActionName, action, or href.");
- //Append any additional properties
- link = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "href", "action", "directActionName", "actionClass", "multipleSubmit" }));
- if (link.length() > 0)
- r.appendContentString(link);
- r.appendContentString(">");
- //Notify that we're inside a form now
- c.setInForm(true);
- //Append the inner template
- rootElement.appendToResponse(r, c);
- //Close the tag
- r.appendContentString("</FORM>");
+ // Append any additional properties
+ link = additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "href", "action", "directActionName", "actionClass", "multipleSubmit" }));
+ if (link.length() > 0)
+ r.appendContentString(link);
+ r.appendContentString(">");
+ // Notify that we're inside a form now
+ c.setInForm(true);
+ // Append the inner template
+ rootElement.appendToResponse(r, c);
+ // Close the tag
+ r.appendContentString("</FORM>");
// c.deleteLastElementIDComponent();
- c.setInForm(false);
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- //We only process the request if it's not a multipleSubmit (otherwise we leave it to the buttons)
- if (!multipleSubmit(c)
- && c.elementID().equals(c.senderID())
- && associations.objectForKey("action") != null ) {
- return (WOActionResults)valueForProperty("action", c.component());
- }
- WOActionResults res = rootElement.invokeAction(r, c);
- return res;
- }
+ c.setInForm(false);
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ // We only process the request if it's not a multipleSubmit (otherwise we leave
+ // it to the buttons)
+ if (!multipleSubmit(c) && c.elementID().equals(c.senderID()) && associations.objectForKey("action") != null) {
+ return (WOActionResults) valueForProperty("action", c.component());
+ }
+ WOActionResults res = rootElement.invokeAction(r, c);
+ return res;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
index 30dd4bc..06f4b7f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOFrame.java
@@ -6,55 +6,54 @@ import net.wotonomy.foundation.NSDictionary;
public class WOFrame extends WODynamicElement {
- public WOFrame() {
- super();
- }
-
- public WOFrame(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- public String frameName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- public String url(WOContext c) {
- //Check if the href property is set
- String href = stringForProperty("href", c.component());
- if (href != null)
- return href;
- href = stringForProperty("pageName", c.component());
- if (href != null || associations.objectForKey("action") != null) { //write this component's URL
- return c.componentActionURL();
- }
- href = stringForProperty("directActionName", c.component());
- if (href != null) { //compose the direct action URL
- String fullActionName = stringForProperty("actionClass", c.component());
- if (fullActionName != null)
- fullActionName = fullActionName + "/" + href;
- else
- fullActionName = href;
- return c.directActionURLForActionNamed(fullActionName,
- urlFields(c.component()));
- }
- //Coded needed here to support filename/framework and data/mimeType.
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<FRAME NAME=\"");
- r.appendContentString(frameName(c));
- r.appendContentString("\" SRC=\"");
- r.appendContentString(url(c));
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "href", "pageName", "directActionName", "actionClass" }));
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString(">");
- }
+ public WOFrame() {
+ super();
+ }
+
+ public WOFrame(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ public String frameName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ public String url(WOContext c) {
+ // Check if the href property is set
+ String href = stringForProperty("href", c.component());
+ if (href != null)
+ return href;
+ href = stringForProperty("pageName", c.component());
+ if (href != null || associations.objectForKey("action") != null) { // write this component's URL
+ return c.componentActionURL();
+ }
+ href = stringForProperty("directActionName", c.component());
+ if (href != null) { // compose the direct action URL
+ String fullActionName = stringForProperty("actionClass", c.component());
+ if (fullActionName != null)
+ fullActionName = fullActionName + "/" + href;
+ else
+ fullActionName = href;
+ return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
+ }
+ // Coded needed here to support filename/framework and data/mimeType.
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<FRAME NAME=\"");
+ r.appendContentString(frameName(c));
+ r.appendContentString("\" SRC=\"");
+ r.appendContentString(url(c));
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "name", "href", "pageName", "directActionName", "actionClass" }));
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString(">");
+ }
} \ No newline at end of file
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
index 9af5460..b883b0f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericContainer.java
@@ -21,41 +21,42 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to dynamically generate HTML containers (elements with opening and closing tags and something in between).
+ * Used to dynamically generate HTML containers (elements with opening and
+ * closing tags and something in between).
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOGenericContainer extends WOGenericElement {
- public WOGenericContainer() {
- super();
- }
-
- public WOGenericContainer(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- super.appendToResponse(r, c);
- rootElement.appendToResponse(r, c);
- r.appendContentString("</");
- r.appendContentString(elementName(c));
- r.appendContentString(">");
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- super.takeValuesFromRequest( r, c );
- rootElement.takeValuesFromRequest(r, c);
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- WOActionResults result = super.invokeAction( r, c );
- if ( result == null )
- {
- result = rootElement.invokeAction(r, c);
- }
- return result;
- }
+ public WOGenericContainer() {
+ super();
+ }
+
+ public WOGenericContainer(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ super.appendToResponse(r, c);
+ rootElement.appendToResponse(r, c);
+ r.appendContentString("</");
+ r.appendContentString(elementName(c));
+ r.appendContentString(">");
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ super.takeValuesFromRequest(r, c);
+ rootElement.takeValuesFromRequest(r, c);
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = super.invokeAction(r, c);
+ if (result == null) {
+ result = rootElement.invokeAction(r, c);
+ }
+ return result;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
index 8894428..92d1b42 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOGenericElement.java
@@ -22,74 +22,70 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
- * Used to generate any HTML element dynamically. It only creates the opening tag without a closing tag.
- * To generate HTML elements that have opening and closing tags, as well as some content in between,
- * use WOGenericContainer instead.
+ * Used to generate any HTML element dynamically. It only creates the opening
+ * tag without a closing tag. To generate HTML elements that have opening and
+ * closing tags, as well as some content in between, use WOGenericContainer
+ * instead.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOGenericElement extends WODynamicElement {
- static NSArray bindings = new NSArray( new Object[]
- { "elementName", "omitTags", "elementID", "otherTagString",
- "formValue", "formValues", "invokeAction" } );
-
- public WOGenericElement() {
- super();
- }
+ static NSArray bindings = new NSArray(new Object[] { "elementName", "omitTags", "elementID", "otherTagString",
+ "formValue", "formValues", "invokeAction" });
- public WOGenericElement(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOGenericElement() {
+ super();
+ }
- public String elementName(WOContext c) {
- String x = (String)valueForProperty("elementName", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
+ public WOGenericElement(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if ( c.elementID().equals( c.senderID() ) )
- {
- Object value;
- value = r.formValueForKey( c.elementID() );
- setValueForProperty( "formValue", value, c.component() );
- value = r.formValuesForKey( c.elementID() );
- setValueForProperty( "formValues", value, c.component() );
- }
- }
+ public String elementName(WOContext c) {
+ String x = (String) valueForProperty("elementName", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c)
- {
- WOActionResults result = null;
- String action = stringForProperty( "invokeAction", c.component() );
- if ( action != null && c.elementID().equals( c.senderID() ) )
- {
- result = c.component().performAction( action );
- }
- return result;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- WOComponent component = c.component();
- if ( !booleanForProperty( "omitTags", component ) )
- {
- r.appendContentString("<");
- r.appendContentString(elementName(c));
- String other = stringForProperty( "otherTagString", component );
- if ( other != null )
- {
- r.appendContentString( " " );
- r.appendContentString( other );
- }
- String add = additionalHTMLProperties(component, bindings);
- if (add.length() > 0)
- r.appendContentString(add);
- r.appendContentString(">");
- }
- setValueForProperty( "elementID", c.elementID(), component );
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (c.elementID().equals(c.senderID())) {
+ Object value;
+ value = r.formValueForKey(c.elementID());
+ setValueForProperty("formValue", value, c.component());
+ value = r.formValuesForKey(c.elementID());
+ setValueForProperty("formValues", value, c.component());
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = null;
+ String action = stringForProperty("invokeAction", c.component());
+ if (action != null && c.elementID().equals(c.senderID())) {
+ result = c.component().performAction(action);
+ }
+ return result;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ WOComponent component = c.component();
+ if (!booleanForProperty("omitTags", component)) {
+ r.appendContentString("<");
+ r.appendContentString(elementName(c));
+ String other = stringForProperty("otherTagString", component);
+ if (other != null) {
+ r.appendContentString(" ");
+ r.appendContentString(other);
+ }
+ String add = additionalHTMLProperties(component, bindings);
+ if (add.length() > 0)
+ r.appendContentString(add);
+ r.appendContentString(">");
+ }
+ setValueForProperty("elementID", c.elementID(), component);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
index c5d5711..ca4e6c2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHiddenField.java
@@ -21,22 +21,23 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* Used to dynamically generate a hidden field within a form.
+ * Used to dynamically generate a hidden field within a form.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOHiddenField extends WOTextField {
- public WOHiddenField() {
- super();
- }
+ public WOHiddenField() {
+ super();
+ }
- public WOHiddenField(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOHiddenField(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
index d0f3ff7..e2041d5 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOHyperlink.java
@@ -25,26 +25,30 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOHyperlink renders a dynamically generated hyperlink in the output.
- * Bindings are:
+ * WOHyperlink renders a dynamically generated hyperlink in the output. Bindings
+ * are:
* <ul>
- * <li>string: a string to be included between the hyperlink tags (optional).</li>
+ * <li>string: a string to be included between the hyperlink tags
+ * (optional).</li>
* <li>escapeHTML: a property returning a value convertable to a Boolean
- * indicating whether the any html characters in the output should be
- * escaped so they are shown as html characters rather than interpreted
- * as html.</li>
+ * indicating whether the any html characters in the output should be escaped so
+ * they are shown as html characters rather than interpreted as html.</li>
* <li>href: The URL that the hyperlink should point to.</li>
- * <li>pageName: The name of the WOComponent that the hyperlink should point to.</li>
- * <li>directActionName: The name of the direct action to call when the link is activated.</li>
- * <li>actionClass: The name of the WODirectAction subclass where the direct action resides.</li>
+ * <li>pageName: The name of the WOComponent that the hyperlink should point
+ * to.</li>
+ * <li>directActionName: The name of the direct action to call when the link is
+ * activated.</li>
+ * <li>actionClass: The name of the WODirectAction subclass where the direct
+ * action resides.</li>
* <li>anchorName: The name of the link, for anchor tags.</li>
- * <li>action: A pointer to a method on the component that contains this element. If the link is activated,
- * the method will be called.
+ * <li>action: A pointer to a method on the component that contains this
+ * element. If the link is activated, the method will be called.
* <li>ref: The name of the anchor to go to inside the resulting page.</li>
* </ul>
*
- * The href, pageName and directActionName/actionClass and name properties are mutually exclusive and you should
- * only use at most one of them simultaneously.
+ * The href, pageName and directActionName/actionClass and name properties are
+ * mutually exclusive and you should only use at most one of them
+ * simultaneously.
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -52,198 +56,202 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOHyperlink extends WODynamicElement {
- protected String string;
- protected String href;
- protected String pageName;
- protected String directActionName;
- protected String actionClass;
- protected String action;
- protected boolean escapeHTML;
- protected String anchorName;
- protected String ref;
-
- protected WOHyperlink() {
- super();
- }
-
- public WOHyperlink(String aName, NSDictionary aMap, WOElement aRootElement) {
- super(aName, aMap, aRootElement);
- escapeHTML = true;
- }
-
- public void setString(String value) {
- string = value;
- }
- public String string() {
- return string;
- }
-
- public void setHref(String value) {
- href = value;
- }
- public String href() {
- return href;
- }
-
- public void setAnchorName(String value) {
- anchorName = value;
- }
- public String anchorName() {
- return anchorName;
- }
-
- public void setPageName(String value) {
- pageName = value;
- }
- public String pageName() {
- return pageName;
- }
-
- public void setDirectActionName(String value) {
- directActionName = value;
- }
- public String directActionName() {
- return directActionName;
- }
-
- public void setActionClass(String value) {
- actionClass = value;
- }
- public String actionClass() {
- return actionClass;
- }
-
- /** Sets the escapeHTML property. */
- public void setEscapeHTML(boolean escape) {
- escapeHTML = escape;
- }
-
- /** If true, inserts escape codes in to the <B>string</B> string so
- * that HTML special characters (greater-than, less-than, etc.)
- * appear correctly. If false, those characters will get
- * interpreted by the browser. Defaults to true.
- */
- public boolean escapeHTML() {
- return escapeHTML;
- }
-
- public String actionURL(WOContext c) {
- //Check if the href property is set
- if (href() != null) {
- return href();
- } else if (pageName() != null || associations.objectForKey("action") != null) { //write this component's URL
- StringBuffer retval = new StringBuffer(c.componentActionURL());
- Map addFields = urlFields(c.component());
- if (addFields.size() > 0) {
- Iterator enumeration = addFields.keySet().iterator();
- retval.append('?');
- while (enumeration.hasNext()) {
- String encoding = c.response() != null ? c.response().contentEncoding() : c.request().contentEncoding();
- String key = (String)enumeration.next();
- try {
+ protected String string;
+ protected String href;
+ protected String pageName;
+ protected String directActionName;
+ protected String actionClass;
+ protected String action;
+ protected boolean escapeHTML;
+ protected String anchorName;
+ protected String ref;
+
+ protected WOHyperlink() {
+ super();
+ }
+
+ public WOHyperlink(String aName, NSDictionary aMap, WOElement aRootElement) {
+ super(aName, aMap, aRootElement);
+ escapeHTML = true;
+ }
+
+ public void setString(String value) {
+ string = value;
+ }
+
+ public String string() {
+ return string;
+ }
+
+ public void setHref(String value) {
+ href = value;
+ }
+
+ public String href() {
+ return href;
+ }
+
+ public void setAnchorName(String value) {
+ anchorName = value;
+ }
+
+ public String anchorName() {
+ return anchorName;
+ }
+
+ public void setPageName(String value) {
+ pageName = value;
+ }
+
+ public String pageName() {
+ return pageName;
+ }
+
+ public void setDirectActionName(String value) {
+ directActionName = value;
+ }
+
+ public String directActionName() {
+ return directActionName;
+ }
+
+ public void setActionClass(String value) {
+ actionClass = value;
+ }
+
+ public String actionClass() {
+ return actionClass;
+ }
+
+ /** Sets the escapeHTML property. */
+ public void setEscapeHTML(boolean escape) {
+ escapeHTML = escape;
+ }
+
+ /**
+ * If true, inserts escape codes in to the <B>string</B> string so that HTML
+ * special characters (greater-than, less-than, etc.) appear correctly. If
+ * false, those characters will get interpreted by the browser. Defaults to
+ * true.
+ */
+ public boolean escapeHTML() {
+ return escapeHTML;
+ }
+
+ public String actionURL(WOContext c) {
+ // Check if the href property is set
+ if (href() != null) {
+ return href();
+ } else if (pageName() != null || associations.objectForKey("action") != null) { // write this component's URL
+ StringBuffer retval = new StringBuffer(c.componentActionURL());
+ Map addFields = urlFields(c.component());
+ if (addFields.size() > 0) {
+ Iterator enumeration = addFields.keySet().iterator();
+ retval.append('?');
+ while (enumeration.hasNext()) {
+ String encoding = c.response() != null ? c.response().contentEncoding()
+ : c.request().contentEncoding();
+ String key = (String) enumeration.next();
+ try {
retval.append(java.net.URLEncoder.encode(key, encoding));
- } catch (java.io.UnsupportedEncodingException ex) {
- retval.append(key);
- }
- retval.append("=");
+ } catch (java.io.UnsupportedEncodingException ex) {
+ retval.append(key);
+ }
+ retval.append("=");
try {
retval.append(java.net.URLEncoder.encode(addFields.get(key).toString(), encoding));
} catch (java.io.UnsupportedEncodingException e) {
retval.append(addFields.get(key).toString());
}
- if (enumeration.hasNext())
- retval.append('&');
- }
- }
- return retval.toString();
- } else if (directActionName() != null) { //compose the direct action URL
- String fullActionName = null;
- if (actionClass() != null )
- fullActionName = actionClass() + "/" + directActionName();
- else
- fullActionName = directActionName();
- return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
- }
- return null;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- string = stringForProperty("string", c);
- href = stringForProperty("href", c);
- pageName = stringForProperty("pageName", c);
- directActionName = stringForProperty("directActionName", c);
- actionClass = stringForProperty("actionClass", c);
- //action = stringForProperty("action", c);
- escapeHTML = booleanForProperty("escapeHTML", c);
- anchorName = stringForProperty("anchorName", c);
- ref = stringForProperty("ref", c);
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- pullValuesFromParent( c.component() );
- r.appendContentString("<A");
- boolean closeQuotes = false;
- //Check if the href property is set
- String _href = actionURL(c);
- if (_href != null) {
- closeQuotes = true;
- r.appendContentString(" HREF=\"");
- r.appendContentString(_href);
- } else if (anchorName() != null) {
- r.appendContentString(" NAME=\"");
- r.appendContentString(anchorName());
- closeQuotes = true;
- }
- if (ref != null) {
- if (!closeQuotes) {
- r.appendContentString(" HREF=\"#");
- closeQuotes = true;
- } else
- r.appendContentString("#");
- r.appendContentString(ref);
- }
- if (closeQuotes)
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "href", "pageName", "action", "directActionName", "actionClass", "anchorName",
- "escapeHTML", "string" })));
- r.appendContentString(">");
- //Append the string if present
- if (string() != null) {
- if (escapeHTML())
- r.appendContentHTMLString(string());
- else
- r.appendContentString(string());
- }
- //If there is a template, call appendToResponse on it
- if (rootElement != null) {
- rootElement.appendToResponse(r, c);
- }
- //Close the tag
- r.appendContentString("</A>");
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- System.out.println("invoke action with elementID=" + c.elementID() + " senderID=" + c.senderID());
- //Check if this element is the target
- if (c.senderID().equals(c.elementID())) {
- if (pageName() != null)
- {
- return WOApplication.application().pageWithName(pageName(), r);
- }
- else
- {
- WOAssociation ass = (WOAssociation) associations.objectForKey("action");
- if ( ass != null && ass.path != null ) //??
- return (WOActionResults)c.component().performAction( ass.path );
- }
- }
- return null;
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- System.out.println("takeValuesFromRequest elementID=" + c.elementID() + " senderID=" + c.senderID());
- super.takeValuesFromRequest(r, c);
- }
+ if (enumeration.hasNext())
+ retval.append('&');
+ }
+ }
+ return retval.toString();
+ } else if (directActionName() != null) { // compose the direct action URL
+ String fullActionName = null;
+ if (actionClass() != null)
+ fullActionName = actionClass() + "/" + directActionName();
+ else
+ fullActionName = directActionName();
+ return c.directActionURLForActionNamed(fullActionName, urlFields(c.component()));
+ }
+ return null;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ string = stringForProperty("string", c);
+ href = stringForProperty("href", c);
+ pageName = stringForProperty("pageName", c);
+ directActionName = stringForProperty("directActionName", c);
+ actionClass = stringForProperty("actionClass", c);
+ // action = stringForProperty("action", c);
+ escapeHTML = booleanForProperty("escapeHTML", c);
+ anchorName = stringForProperty("anchorName", c);
+ ref = stringForProperty("ref", c);
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ pullValuesFromParent(c.component());
+ r.appendContentString("<A");
+ boolean closeQuotes = false;
+ // Check if the href property is set
+ String _href = actionURL(c);
+ if (_href != null) {
+ closeQuotes = true;
+ r.appendContentString(" HREF=\"");
+ r.appendContentString(_href);
+ } else if (anchorName() != null) {
+ r.appendContentString(" NAME=\"");
+ r.appendContentString(anchorName());
+ closeQuotes = true;
+ }
+ if (ref != null) {
+ if (!closeQuotes) {
+ r.appendContentString(" HREF=\"#");
+ closeQuotes = true;
+ } else
+ r.appendContentString("#");
+ r.appendContentString(ref);
+ }
+ if (closeQuotes)
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[] { "name", "href",
+ "pageName", "action", "directActionName", "actionClass", "anchorName", "escapeHTML", "string" })));
+ r.appendContentString(">");
+ // Append the string if present
+ if (string() != null) {
+ if (escapeHTML())
+ r.appendContentHTMLString(string());
+ else
+ r.appendContentString(string());
+ }
+ // If there is a template, call appendToResponse on it
+ if (rootElement != null) {
+ rootElement.appendToResponse(r, c);
+ }
+ // Close the tag
+ r.appendContentString("</A>");
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ System.out.println("invoke action with elementID=" + c.elementID() + " senderID=" + c.senderID());
+ // Check if this element is the target
+ if (c.senderID().equals(c.elementID())) {
+ if (pageName() != null) {
+ return WOApplication.application().pageWithName(pageName(), r);
+ } else {
+ WOAssociation ass = (WOAssociation) associations.objectForKey("action");
+ if (ass != null && ass.path != null) // ??
+ return (WOActionResults) c.component().performAction(ass.path);
+ }
+ }
+ return null;
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ System.out.println("takeValuesFromRequest elementID=" + c.elementID() + " senderID=" + c.senderID());
+ super.takeValuesFromRequest(r, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
index 2673cd1..3f830b0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImage.java
@@ -6,145 +6,146 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSDictionary;
/**
-* WOImage renders a dynamically generated IMG tag. The URL for the image SRC can be
-* static, or it can be generated dynamically to return a NSData object (with a mime-type)
-* or even return the contents of a file (not implemented yet).
-*
-* Bindings are:
-* <UL><LI>src: A static URL for the image source.</li>
-* <li>data: A NSData object with the image content. Must be used with mimeType.</li>
-* <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
-* <li>filename: The path to a file containing an image.</li>
-* <li>framework: The optional framework from whence the image should be retrieved (used in conjunction with filename).</li>
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * WOImage renders a dynamically generated IMG tag. The URL for the image SRC
+ * can be static, or it can be generated dynamically to return a NSData object
+ * (with a mime-type) or even return the contents of a file (not implemented
+ * yet).
+ *
+ * Bindings are:
+ * <UL>
+ * <LI>src: A static URL for the image source.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
+ * <li>filename: The path to a file containing an image.</li>
+ * <li>framework: The optional framework from whence the image should be
+ * retrieved (used in conjunction with filename).</li>
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOImage extends WODynamicElement {
- protected String src;
- protected String filename;
- protected String framework;
- protected NSData data;
- protected String mimeType;
-
- protected WOImage() {
- super();
- }
-
- public WOImage(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setSrc(String value) {
- src = value;
- }
- public String src() {
- return src;
- }
-
- public void setFilename(String value) {
- filename = value;
- }
-
- public String filename() {
- return filename;
- }
-
- public void setFramework(String value) {
- framework = value;
- }
- public String framework() {
- return framework;
- }
-
- public void setData(NSData value) {
- data = value;
- }
- public NSData data() {
- return data;
- }
-
- public void setMimeType(String value) {
- mimeType = value;
- }
- public String mimeType() {
- return mimeType();
- }
-
- public String sourceURL(WOContext c) {
- if (associations.objectForKey("src") != null)
- return (String)valueForProperty("src", c.component());
- if (associations.objectForKey("data") != null) {
- return c.componentActionURL();
- }
- if (associations.objectForKey("filename") != null) {
- WOComponent component = c.component();
-
- String framework = stringForProperty("framework", component);
- String filename = stringForProperty( "filename", component );
- if ( filename != null && framework == null )
- {
- if ( filename.startsWith("/" ) )
- {
- int i = filename.lastIndexOf( "/" );
- if ( i > 0 )
- {
- framework = filename.substring( 0, i );
- if ( i < filename.length() )
- {
- filename = filename.substring( i+1 );
- }
- }
- }
- else
- {
- // just until we figure out how we're handling bundles/localization
- framework = component.frameworkName();
- if ( framework != null )
- {
- framework = framework + '/' + component.name() + ".wo";
- }
- else
- {
- framework = '/' + component.name() + ".wo";
- }
- }
- }
- return WOApplication.application().resourceManager().urlForResourceNamed(
- filename, framework, c.request().browserLanguages(), c.request() );
- }
- return "NO SOURCE";
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<IMG SRC=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- if (c.senderID().equals(c.elementID())) {
- Object data = valueForProperty("data", c.component());
- if (data instanceof byte[]) data = new NSData( (byte[]) data );
- if (data instanceof NSData) {
- String mt = stringForProperty("mimeType", c.component());
- if (mt == null)
- throw new IllegalArgumentException("WOImage: No mimeType specified for data.");
- WOResponse img = new WOResponse();
- img.setContent((NSData)data);
- img.setHeader(mt, "content-type");
- return img;
- } else if (filename() != null) {
- //will this thing use frameworks, or regular JAR files with resources?
- // mp: both/either, depending on which resource manager implementation
- }
- }
- return null;
- }
+ protected String src;
+ protected String filename;
+ protected String framework;
+ protected NSData data;
+ protected String mimeType;
+
+ protected WOImage() {
+ super();
+ }
+
+ public WOImage(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setSrc(String value) {
+ src = value;
+ }
+
+ public String src() {
+ return src;
+ }
+
+ public void setFilename(String value) {
+ filename = value;
+ }
+
+ public String filename() {
+ return filename;
+ }
+
+ public void setFramework(String value) {
+ framework = value;
+ }
+
+ public String framework() {
+ return framework;
+ }
+
+ public void setData(NSData value) {
+ data = value;
+ }
+
+ public NSData data() {
+ return data;
+ }
+
+ public void setMimeType(String value) {
+ mimeType = value;
+ }
+
+ public String mimeType() {
+ return mimeType();
+ }
+
+ public String sourceURL(WOContext c) {
+ if (associations.objectForKey("src") != null)
+ return (String) valueForProperty("src", c.component());
+ if (associations.objectForKey("data") != null) {
+ return c.componentActionURL();
+ }
+ if (associations.objectForKey("filename") != null) {
+ WOComponent component = c.component();
+
+ String framework = stringForProperty("framework", component);
+ String filename = stringForProperty("filename", component);
+ if (filename != null && framework == null) {
+ if (filename.startsWith("/")) {
+ int i = filename.lastIndexOf("/");
+ if (i > 0) {
+ framework = filename.substring(0, i);
+ if (i < filename.length()) {
+ filename = filename.substring(i + 1);
+ }
+ }
+ } else {
+ // just until we figure out how we're handling bundles/localization
+ framework = component.frameworkName();
+ if (framework != null) {
+ framework = framework + '/' + component.name() + ".wo";
+ } else {
+ framework = '/' + component.name() + ".wo";
+ }
+ }
+ }
+ return WOApplication.application().resourceManager().urlForResourceNamed(filename, framework,
+ c.request().browserLanguages(), c.request());
+ }
+ return "NO SOURCE";
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<IMG SRC=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(),
+ new NSArray(new Object[] { "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ if (c.senderID().equals(c.elementID())) {
+ Object data = valueForProperty("data", c.component());
+ if (data instanceof byte[])
+ data = new NSData((byte[]) data);
+ if (data instanceof NSData) {
+ String mt = stringForProperty("mimeType", c.component());
+ if (mt == null)
+ throw new IllegalArgumentException("WOImage: No mimeType specified for data.");
+ WOResponse img = new WOResponse();
+ img.setContent((NSData) data);
+ img.setHeader(mt, "content-type");
+ return img;
+ } else if (filename() != null) {
+ // will this thing use frameworks, or regular JAR files with resources?
+ // mp: both/either, depending on which resource manager implementation
+ }
+ }
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
index 7c9f22e..ebb9ae1 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOImageButton.java
@@ -5,17 +5,21 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
- * WOImageButton renders a dynamically generated IMG tag or an INPUT tag, depending on whether the
- * element is inside a WOForm (in which case an INPUT of type IMAGE is generated) or not (in which
- * case the equivalent of a WOActiveImage)
+ * WOImageButton renders a dynamically generated IMG tag or an INPUT tag,
+ * depending on whether the element is inside a WOForm (in which case an INPUT
+ * of type IMAGE is generated) or not (in which case the equivalent of a
+ * WOActiveImage)
*
* Bindings are:
* <UL>
* <LI>src: A static URL for the image source.</li>
- * <li>data: A NSData object with the image content. Must be used with mimeType.</li>
- * <li>mimeType: The MIME type for the image data. Can be used with filename or data bindings.</li>
+ * <li>data: A NSData object with the image content. Must be used with
+ * mimeType.</li>
+ * <li>mimeType: The MIME type for the image data. Can be used with filename or
+ * data bindings.</li>
* <li>filename: The path to a file containing an image.</li>
- * <li>framework: The framework where the image should be retrieved from (used in conjunction with filename).</li>
+ * <li>framework: The framework where the image should be retrieved from (used
+ * in conjunction with filename).</li>
*
* @author ezamudio@nasoft.com
* @author $Author: cgruber $
@@ -23,36 +27,36 @@ import net.wotonomy.foundation.NSDictionary;
*/
public class WOImageButton extends WOImage {
- protected WOImageButton() {
- super();
- }
-
- public WOImageButton(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public String buttonName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- if (c.isInForm()) {
- //generate an INPUT
- r.appendContentString("<INPUT TYPE=IMAGE NAME=\"");
- r.appendContentString(buttonName(c));
- r.appendContentString("\" SRC=\"");
- r.appendContentString(sourceURL(c));
- r.appendContentString("\"");
- r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "action", "src", "filename", "framework", "data", "mimeType" })));
- r.appendContentString(">");
- } else {
- //generate a WOActiveImage
- new WOActiveImage(name, associations, rootElement).appendToResponse(r, c);
- }
- }
+ protected WOImageButton() {
+ super();
+ }
+
+ public WOImageButton(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public String buttonName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ if (c.isInForm()) {
+ // generate an INPUT
+ r.appendContentString("<INPUT TYPE=IMAGE NAME=\"");
+ r.appendContentString(buttonName(c));
+ r.appendContentString("\" SRC=\"");
+ r.appendContentString(sourceURL(c));
+ r.appendContentString("\"");
+ r.appendContentString(additionalHTMLProperties(c.component(), new NSArray(
+ new Object[] { "name", "action", "src", "filename", "framework", "data", "mimeType" })));
+ r.appendContentString(">");
+ } else {
+ // generate a WOActiveImage
+ new WOActiveImage(name, associations, rootElement).appendToResponse(r, c);
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
index a8c7daa..ddcdb9e 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOInput.java
@@ -10,74 +10,75 @@ import net.wotonomy.foundation.NSMutableArray;
public abstract class WOInput extends WODynamicElement {
- public WOInput() {
- super();
- }
-
- public WOInput(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected abstract String inputType();
- protected abstract Object value(WOContext c);
-
- protected NSMutableArray additionalAttributes() {
- return new NSMutableArray(new Object[]{
- "disabled", "type", "value", "name"
- });
- }
-
- public String inputName(WOContext c) {
- String x = (String)valueForProperty("name", c.component());
- if (x != null)
- return x;
- return c.elementID();
- }
-
- protected boolean disabled(WOContext c) {
- return booleanForProperty("disabled", c.component());
- }
-
- protected void appendExtras(WOResponse r, WOContext c) {
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<INPUT TYPE=\"");
- r.appendContentString(inputType());
- r.appendContentString("\" NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\" VALUE=\"");
- r.appendContentString(value(c).toString());
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), additionalAttributes());
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- appendExtras(r, c);
- if (disabled(c)) {
- r.appendContentString(" DISABLED");
- }
- r.appendContentString(">");
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- if (disabled(c))
- return;
- Object val = r.formValueForKey(inputName(c));
- WOAssociation va = (WOAssociation)associations.objectForKey("value");
- if (val != null && va != null && va.isValueSettable())
- setValueForProperty("value", val, c.component());
- }
-
- /** Formats a value as a date or number. Checks for
- * numberformat or dateformat associations; if one of them
- * exists, the value is formatter using the specified pattern.
+ public WOInput() {
+ super();
+ }
+
+ public WOInput(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected abstract String inputType();
+
+ protected abstract Object value(WOContext c);
+
+ protected NSMutableArray additionalAttributes() {
+ return new NSMutableArray(new Object[] { "disabled", "type", "value", "name" });
+ }
+
+ public String inputName(WOContext c) {
+ String x = (String) valueForProperty("name", c.component());
+ if (x != null)
+ return x;
+ return c.elementID();
+ }
+
+ protected boolean disabled(WOContext c) {
+ return booleanForProperty("disabled", c.component());
+ }
+
+ protected void appendExtras(WOResponse r, WOContext c) {
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<INPUT TYPE=\"");
+ r.appendContentString(inputType());
+ r.appendContentString("\" NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\" VALUE=\"");
+ r.appendContentString(value(c).toString());
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(), additionalAttributes());
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ appendExtras(r, c);
+ if (disabled(c)) {
+ r.appendContentString(" DISABLED");
+ }
+ r.appendContentString(">");
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ if (disabled(c))
+ return;
+ Object val = r.formValueForKey(inputName(c));
+ WOAssociation va = (WOAssociation) associations.objectForKey("value");
+ if (val != null && va != null && va.isValueSettable())
+ setValueForProperty("value", val, c.component());
+ }
+
+ /**
+ * Formats a value as a date or number. Checks for numberformat or dateformat
+ * associations; if one of them exists, the value is formatter using the
+ * specified pattern.
+ *
* @param value The value to format.
- * @return The original object, or a date or number if the
- * receiver has a numberformat or dateformat association.
+ * @return The original object, or a date or number if the receiver has a
+ * numberformat or dateformat association.
*/
protected Object formattedValue(Object value, WOComponent c) {
- //Format the value in case of number
- String pattern = (String)valueForProperty("numberformat", c);
+ // Format the value in case of number
+ String pattern = (String) valueForProperty("numberformat", c);
if (pattern != null) {
DecimalFormat fmt = new DecimalFormat(pattern);
try {
@@ -86,8 +87,8 @@ public abstract class WOInput extends WODynamicElement {
return value;
}
}
- //Format the value in case of date
- pattern = (String)valueForProperty("dateformat", c);
+ // Format the value in case of date
+ pattern = (String) valueForProperty("dateformat", c);
if (pattern != null) {
SimpleDateFormat fmt = new SimpleDateFormat(pattern);
try {
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
index eccc489..69939f9 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMailDelivery.java
@@ -21,34 +21,30 @@ package net.wotonomy.web;
import java.util.List;
/**
-* A pure java implementation of WOMailDelivery.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WOMailDelivery
-{
+ * A pure java implementation of WOMailDelivery.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WOMailDelivery {
private static WOMailDelivery sharedInstance;
-
- protected WOMailDelivery ()
- {
- }
-
- public static WOMailDelivery sharedInstance ()
- {
- if ( sharedInstance == null )
- {
+
+ protected WOMailDelivery() {
+ }
+
+ public static WOMailDelivery sharedInstance() {
+ if (sharedInstance == null) {
// sharedInstance = new WOMailDelivery();
- }
- return sharedInstance;
- }
-
- public abstract String composePlainTextEmail (
- String aSender, List aToList, List aCcList,
- String aSubject, String aMessage, boolean sendImmediately );
- public abstract String composeComponentEmail (
- String aSender, List aToList, List aCcList,
- String aSubject, WOComponent aComponent, boolean sendImmediately );
- public abstract void sendEmail (String aMailMessage);
+ }
+ return sharedInstance;
+ }
+
+ public abstract String composePlainTextEmail(String aSender, List aToList, List aCcList, String aSubject,
+ String aMessage, boolean sendImmediately);
+
+ public abstract String composeComponentEmail(String aSender, List aToList, List aCcList, String aSubject,
+ WOComponent aComponent, boolean sendImmediately);
+
+ public abstract void sendEmail(String aMailMessage);
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
index be76be1..f2310c2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOMessage.java
@@ -24,12 +24,12 @@ import net.wotonomy.foundation.NSMutableData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WOResponse.
-*
-* @author ezamudio@nasoft.com
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * A pure java implementation of WOResponse.
+ *
+ * @author ezamudio@nasoft.com
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOMessage {
protected String _contentEncoding = "ISO8859_1";
@@ -43,291 +43,233 @@ public class WOMessage {
}
/**
- * Sets the content encoding for the response.
- */
- public void setContentEncoding (String encoding)
- {
+ * Sets the content encoding for the response.
+ */
+ public void setContentEncoding(String encoding) {
_contentEncoding = encoding;
}
/**
- * Gets the current content encoding for the response.
- */
- public String contentEncoding () {
+ * Gets the current content encoding for the response.
+ */
+ public String contentEncoding() {
return _contentEncoding;
- }
+ }
/**
- * Sets the specified array of values as headers under
- * the specified key.
- */
- public void setHeaders (NSArray headerArray, String aKey) {
- _headers.setObjectForKey( headerArray, aKey );
+ * Sets the specified array of values as headers under the specified key.
+ */
+ public void setHeaders(NSArray headerArray, String aKey) {
+ _headers.setObjectForKey(headerArray, aKey);
}
/**
- * Sets the specified header value for the specified key.
- */
- public void setHeader (String aValue, String aKey) {
- _headers.setObjectForKey( new NSArray( aValue ), aKey );
+ * Sets the specified header value for the specified key.
+ */
+ public void setHeader(String aValue, String aKey) {
+ _headers.setObjectForKey(new NSArray(aValue), aKey);
}
/**
- * Returns an array of all the header keys that have been
- * set in the response.
- */
- public NSArray headerKeys () {
+ * Returns an array of all the header keys that have been set in the response.
+ */
+ public NSArray headerKeys() {
return _headers.allKeys();
}
/**
- * Returns an array of all the header values for the specified key,
- * or null if the key does not exist.
- */
- public NSArray headersForKey (String aKey) {
- return (NSArray)_headers.objectForKey( aKey );
+ * Returns an array of all the header values for the specified key, or null if
+ * the key does not exist.
+ */
+ public NSArray headersForKey(String aKey) {
+ return (NSArray) _headers.objectForKey(aKey);
}
/**
- * Returns one header value for the specified key.
- * Provided as a convenience, since most header keys
- * will have a single value.
- */
- public String headerForKey (String aKey) {
- NSArray values = (NSArray)_headers.objectForKey( aKey );
- if ( values != null && values.count() > 0 ) {
- return values.objectAtIndex( 0 ).toString();
+ * Returns one header value for the specified key. Provided as a convenience,
+ * since most header keys will have a single value.
+ */
+ public String headerForKey(String aKey) {
+ NSArray values = (NSArray) _headers.objectForKey(aKey);
+ if (values != null && values.count() > 0) {
+ return values.objectAtIndex(0).toString();
}
return null;
}
/**
- * Sets the content of the response to the bytes represented
- * by the specified data object.
- */
+ * Sets the content of the response to the bytes represented by the specified
+ * data object.
+ */
public void setContent(NSData aData) {
- _contentData.setData( aData );
+ _contentData.setData(aData);
setHeader(Integer.toString(aData.length()), "content-length");
}
/**
- * Retrieves the current content of the response.
- */
+ * Retrieves the current content of the response.
+ */
public NSData content() {
return _contentData;
}
/**
- * Sets the current user info dictionary. These values
- * are for application-specific uses and are available to
- * other actions and components in the request-response cycle.
- */
- public void setUserInfo (NSDictionary aDict) {
- _userInfo = new NSMutableDictionary( aDict );
+ * Sets the current user info dictionary. These values are for
+ * application-specific uses and are available to other actions and components
+ * in the request-response cycle.
+ */
+ public void setUserInfo(NSDictionary aDict) {
+ _userInfo = new NSMutableDictionary(aDict);
}
/**
- * Gets the current user info dictionary. These values
- * are for application-specific uses are are available to
- * other actions and components in the request-response cycle.
- */
- public NSDictionary userInfo () {
+ * Gets the current user info dictionary. These values are for
+ * application-specific uses are are available to other actions and components
+ * in the request-response cycle.
+ */
+ public NSDictionary userInfo() {
return new NSDictionary(_userInfo);
}
/**
- * Appends the bytes in the specified data object to the response.
- */
- public void appendContentData (NSData aData)
- {
- _contentData.appendData( aData );
+ * Appends the bytes in the specified data object to the response.
+ */
+ public void appendContentData(NSData aData) {
+ _contentData.appendData(aData);
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified byte to the response.
- */
- public void appendContentCharacter (char character) {
- _contentData.appendByte((byte)character);
+ * Appends the specified byte to the response.
+ */
+ public void appendContentCharacter(char character) {
+ _contentData.appendByte((byte) character);
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string to the response.
- * Any special characters will not be escaped.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentString (String aString)
- {
- _contentData.appendData( new NSData( aString.getBytes() ) );
+ * Appends the specified string to the response. Any special characters will not
+ * be escaped. The string will be encoded in the current content encoding.
+ */
+ public void appendContentString(String aString) {
+ _contentData.appendData(new NSData(aString.getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string containing HTML to the response.
- * Any special characters will be escaped appropriately.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentHTMLString (String aString)
- {
- _contentData.appendData(
- new NSData( stringByEscapingHTMLString(
- aString ).getBytes() ) );
+ * Appends the specified string containing HTML to the response. Any special
+ * characters will be escaped appropriately. The string will be encoded in the
+ * current content encoding.
+ */
+ public void appendContentHTMLString(String aString) {
+ _contentData.appendData(new NSData(stringByEscapingHTMLString(aString).getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Appends the specified string containing HTML to the response.
- * Any special characters will be escaped appropriately.
- * This method escapes tabs and new-line characters as well.
- * The string will be encoded in the current content encoding.
- */
- public void appendContentHTMLAttributeValue (String aString)
- {
- _contentData.appendData (
- new NSData( stringByEscapingHTMLAttributeValue(
- aString ).getBytes() ) );
+ * Appends the specified string containing HTML to the response. Any special
+ * characters will be escaped appropriately. This method escapes tabs and
+ * new-line characters as well. The string will be encoded in the current
+ * content encoding.
+ */
+ public void appendContentHTMLAttributeValue(String aString) {
+ _contentData.appendData(new NSData(stringByEscapingHTMLAttributeValue(aString).getBytes()));
setHeader(Integer.toString(_contentData.length()), "content-length");
}
/**
- * Adds the specified cookie to the response.
- */
- public void addCookie (WOCookie aCookie)
- {
- _cookies.setObjectForKey( aCookie, aCookie.name() );
+ * Adds the specified cookie to the response.
+ */
+ public void addCookie(WOCookie aCookie) {
+ _cookies.setObjectForKey(aCookie, aCookie.name());
}
/**
- * Removes the specified cookie from the response.
- */
- public void removeCookie (WOCookie aCookie)
- {
- _cookies.removeObjectForKey( aCookie.name() );
+ * Removes the specified cookie from the response.
+ */
+ public void removeCookie(WOCookie aCookie) {
+ _cookies.removeObjectForKey(aCookie.name());
}
/**
- * Returns an array of cookies currently being sent with the response.
- * Contains whatever cookies have previously been set in this response.
- */
- public NSArray cookies ()
- {
- return _cookies.allValues();
+ * Returns an array of cookies currently being sent with the response. Contains
+ * whatever cookies have previously been set in this response.
+ */
+ public NSArray cookies() {
+ return _cookies.allValues();
}
/**
- * Sets the HTTP version header in the response.
- */
- public void setHTTPVersion (String aString)
- {
- setHeader( aString, "Protocol");
+ * Sets the HTTP version header in the response.
+ */
+ public void setHTTPVersion(String aString) {
+ setHeader(aString, "Protocol");
}
/**
- * Gets the current HTTP version header for the response.
- * Because servlet responses do not allow read access
- * to headers, this method returns null if setHTTPVersion
- * has not been called.
- */
- public String httpVersion ()
- {
- return headerForKey( "Protocol" );
+ * Gets the current HTTP version header for the response. Because servlet
+ * responses do not allow read access to headers, this method returns null if
+ * setHTTPVersion has not been called.
+ */
+ public String httpVersion() {
+ return headerForKey("Protocol");
}
/**
- * Returns a sting containing the contents of the specified
- * string after escaping all special HTML characters.
- */
- public static String stringByEscapingHTMLString
- (String aString)
- {
+ * Returns a sting containing the contents of the specified string after
+ * escaping all special HTML characters.
+ */
+ public static String stringByEscapingHTMLString(String aString) {
int len = aString.length();
StringBuffer result = new StringBuffer();
- char[] buf = new char[ len ];
- aString.getChars( 0, len, buf, 0 );
- for ( int i = 0; i < len; i++ )
- {
- if ( buf[i] == '&' )
- {
- result.append( "&amp;" );
- }
- else
- if ( buf[i] == '\\' )
- {
- result.append( "&quot;" );
- }
- else
- if ( buf[i] == '<' )
- {
- result.append( "&lt;" );
+ char[] buf = new char[len];
+ aString.getChars(0, len, buf, 0);
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == '&') {
+ result.append("&amp;");
+ } else if (buf[i] == '\\') {
+ result.append("&quot;");
+ } else if (buf[i] == '<') {
+ result.append("&lt;");
+ } else if (buf[i] == '>') {
+ result.append("&gt;");
+ } else {
+ result.append(buf[i]);
}
- else
- if ( buf[i] == '>' )
- {
- result.append( "&gt;" );
- }
- else
- {
- result.append( buf[i] );
- }
- }
- return result.toString();
+ }
+ return result.toString();
}
-
+
/**
- * Returns a sting containing the contents of the specified
- * string after escaping all special HTML characters.
- * This method escapes tabs and new-line characters as well.
- */
- public static String stringByEscapingHTMLAttributeValue
- (String aString)
- {
+ * Returns a sting containing the contents of the specified string after
+ * escaping all special HTML characters. This method escapes tabs and new-line
+ * characters as well.
+ */
+ public static String stringByEscapingHTMLAttributeValue(String aString) {
int len = aString.length();
StringBuffer result = new StringBuffer();
- char[] buf = new char[ len ];
- aString.getChars( 0, len, buf, 0 );
- for ( int i = 0; i < len; i++ )
- {
- if ( buf[i] == '&' )
- {
- result.append( "&amp;" );
+ char[] buf = new char[len];
+ aString.getChars(0, len, buf, 0);
+ for (int i = 0; i < len; i++) {
+ if (buf[i] == '&') {
+ result.append("&amp;");
+ } else if (buf[i] == '\\') {
+ result.append("&quot;");
+ } else if (buf[i] == '<') {
+ result.append("&lt;");
+ } else if (buf[i] == '>') {
+ result.append("&gt;");
+ } else if (buf[i] == '\t') {
+ result.append("&#9;");
+ } else if (buf[i] == '\n') {
+ result.append("&#10;");
+ } else if (buf[i] == '\r') {
+ result.append("&#13;");
+ } else {
+ result.append(buf[i]);
}
- else
- if ( buf[i] == '\\' )
- {
- result.append( "&quot;" );
- }
- else
- if ( buf[i] == '<' )
- {
- result.append( "&lt;" );
- }
- else
- if ( buf[i] == '>' )
- {
- result.append( "&gt;" );
- }
- else
- if ( buf[i] == '\t' )
- {
- result.append( "&#9;" );
- }
- else
- if ( buf[i] == '\n' )
- {
- result.append( "&#10;" );
- }
- else
- if ( buf[i] == '\r' )
- {
- result.append( "&#13;" );
- }
- else
- {
- result.append( buf[i] );
- }
- }
- return result.toString();
+ }
+ return result.toString();
}
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
index 40ee618..cf84b17 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOParentElement.java
@@ -24,155 +24,137 @@ import java.util.List;
import net.wotonomy.foundation.NSMutableArray;
/**
-* This class represents a parent node in an element tree.
-* It has no content in itself, and exists only to forward
-* messages to each of its children, in turn.
-* Package access only, as it is not in the specification.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-class WOParentElement extends WOElement
-{
+ * This class represents a parent node in an element tree. It has no content in
+ * itself, and exists only to forward messages to each of its children, in turn.
+ * Package access only, as it is not in the specification.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+class WOParentElement extends WOElement {
NSMutableArray children;
/**
- * Default constructor.
- */
- public WOParentElement()
- {
+ * Default constructor.
+ */
+ public WOParentElement() {
children = new NSMutableArray();
}
-
+
/**
- * Returns an element with the specified children.
- */
- public WOParentElement( List childElements )
- {
+ * Returns an element with the specified children.
+ */
+ public WOParentElement(List childElements) {
this();
- children.addAll( childElements );
+ children.addAll(childElements);
}
-
- /**
- * Package access only. Called to initialize the component with
- * the proper context before the start of the request-response cycle.
- * If the context has a current component, that component becomes
- * this component's parent.
- */
- void ensureAwakeInContext (WOContext aContext)
- {
- WOElement element;
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- element.ensureAwakeInContext( aContext );
- aContext.popElement();
- }
- }
/**
- * Forwards this message to all child elements.
- */
- public void takeValuesFromRequest (
- WORequest aRequest, WOContext aContext)
- {
- WOElement element;
-
+ * Package access only. Called to initialize the component with the proper
+ * context before the start of the request-response cycle. If the context has a
+ * current component, that component becomes this component's parent.
+ */
+ void ensureAwakeInContext(WOContext aContext) {
+ WOElement element;
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ element.ensureAwakeInContext(aContext);
+ aContext.popElement();
+ }
+ }
+
+ /**
+ * Forwards this message to all child elements.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
- element.takeValuesFromRequest( aRequest, aContext );
- aContext.popElement();
- }
-
- aContext.deleteLastElementIDComponent();
- }
-
- /**
- * Forwards this message to all child elements,
- * returning the first non-null result.
- */
- public WOActionResults invokeAction (
- WORequest aRequest, WOContext aContext)
- {
- WOElement element;
-
+ aContext.appendZeroElementIDComponent();
+
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+ element.takeValuesFromRequest(aRequest, aContext);
+ aContext.popElement();
+ }
+
+ aContext.deleteLastElementIDComponent();
+ }
+
+ /**
+ * Forwards this message to all child elements, returning the first non-null
+ * result.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- WOActionResults result = null;
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
- result = element.invokeAction( aRequest, aContext );
- aContext.popElement();
- if ( result != null ) break;
- }
-
- aContext.deleteLastElementIDComponent();
- return result;
- }
-
- /**
- * Forwards this message to all child elements.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- WOElement element;
-
+ aContext.appendZeroElementIDComponent();
+
+ WOActionResults result = null;
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+ result = element.invokeAction(aRequest, aContext);
+ aContext.popElement();
+ if (result != null)
+ break;
+ }
+
+ aContext.deleteLastElementIDComponent();
+ return result;
+ }
+
+ /**
+ * Forwards this message to all child elements.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ WOElement element;
+
// aContext.incrementLastElementIDComponent();
- aContext.appendZeroElementIDComponent();
-
- // for each child element
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- element = (WOElement) it.next();
- aContext.pushElement( element );
- aContext.incrementLastElementIDComponent();
-
- // forward the message
- element.appendToResponse(
- aResponse, aContext );
-
- aContext.popElement();
-
- }
- aContext.deleteLastElementIDComponent();
- }
-
- public WOResponse generateResponse()
- {
- WOResponse r = new WOResponse();
- return r;
- }
-
- public String toString()
- {
- StringBuffer result = new StringBuffer();
- result.append( "[WOParentElement: " );
- // for each child element
- Iterator it = children.iterator();
- while ( it.hasNext() )
- {
- result.append( "[ " );
- result.append( it.next().toString() );
- result.append( " ]" );
- }
- result.append( " ]" );
- return result.toString();
- }
-
+ aContext.appendZeroElementIDComponent();
+
+ // for each child element
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ element = (WOElement) it.next();
+ aContext.pushElement(element);
+ aContext.incrementLastElementIDComponent();
+
+ // forward the message
+ element.appendToResponse(aResponse, aContext);
+
+ aContext.popElement();
+
+ }
+ aContext.deleteLastElementIDComponent();
+ }
+
+ public WOResponse generateResponse() {
+ WOResponse r = new WOResponse();
+ return r;
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append("[WOParentElement: ");
+ // for each child element
+ Iterator it = children.iterator();
+ while (it.hasNext()) {
+ result.append("[ ");
+ result.append(it.next().toString());
+ result.append(" ]");
+ }
+ result.append(" ]");
+ return result.toString();
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
index 2d4f16e..4d81fe0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPasswordField.java
@@ -5,16 +5,16 @@ import net.wotonomy.foundation.NSDictionary;
public class WOPasswordField extends WOTextField {
- public WOPasswordField() {
- super();
- }
+ public WOPasswordField() {
+ super();
+ }
- public WOPasswordField(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOPasswordField(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "PASSWORD";
- }
+ protected String inputType() {
+ return "PASSWORD";
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
index a73636c..a40c828 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOPopUpButton.java
@@ -7,129 +7,132 @@ import net.wotonomy.foundation.NSKeyValueCodingAdditions;
public class WOPopUpButton extends WOInput {
- public WOPopUpButton() {
- super();
- }
-
- public WOPopUpButton(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected String inputType() {
- return "SELECT";
- }
-
- protected int inputSize() {
- return 1;
- }
-
- protected NSArray list(WOContext c) {
- NSArray l = (NSArray)valueForProperty("list", c.component());
- if (l == null)
- l = NSArray.EmptyArray;
- return l;
- }
-
- protected void setItem(Object v, WOContext c) {
- if (associations.objectForKey("item") == null)
- return;
- setValueForProperty("item", v, c.component());
- }
- protected Object item(WOContext c) {
- return valueForProperty("item", c.component());
- }
-
- protected void setSelection(Object v, WOContext c) {
- if (associations.objectForKey("selection") == null)
- return;
- setValueForProperty("selection", v, c.component());
- }
- protected Object selection(WOContext c) {
- return valueForProperty("selection", c.component());
- }
-
- public Object value(WOContext c) {
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<SELECT NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\" SIZE=");
- r.appendContentString(Integer.toString(inputSize()));
- r.appendContentString(">");
- java.util.Enumeration numerador = list(c).objectEnumerator();
- String displayKey = stringForProperty("displayString", c.component());
- String valueKey = stringForProperty("value", c.component());
- Object sel = selection(c);
- if (sel == null)
- sel = item(c);
- int pos = 0;
- while (numerador.hasMoreElements()) {
- Object item = numerador.nextElement();
- setItem(item, c);
- r.appendContentString("<OPTION ");
- //Append the "SELECTED" attribute if it's the selected item
- if (sel != null && item.equals(sel))
- r.appendContentString("SELECTED ");
- r.appendContentString("VALUE=\"");
- //Append the value
- if (valueKey != null && item instanceof NSKeyValueCodingAdditions) {
- Object val = ((NSKeyValueCodingAdditions)item).valueForKeyPath(valueKey);
- if (val == null)
- val = "null";
- r.appendContentString(val.toString());
- } else
- r.appendContentString(Integer.toString(pos));
- r.appendContentString("\">");
- //Append display string
- if (displayKey != null && item instanceof NSKeyValueCodingAdditions) {
- Object ds = ((NSKeyValueCodingAdditions)item).valueForKeyPath(displayKey);
- if (ds == null)
- ds = "";
- r.appendContentString(ds.toString());
- } else
- r.appendContentString(item.toString());
- r.appendContentString("\n");
- pos++;
- }
- r.appendContentString("</SELECT>");
- }
-
- protected void select(Object v, WOContext c) {
- if (associations.objectForKey("selection") != null) {
- setSelection(v, c);
- return;
- }
- if (associations.objectForKey("item") != null) {
- setItem(v,c);
- }
- }
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- Object val = r.formValueForKey(inputName(c));
- if (val == null)
- return;
- NSArray list = list(c);
- String valueKey = stringForProperty("value", c.component());
- //If no value binding, just get the index
- if (valueKey == null) {
- int pos = Integer.parseInt(val.toString());
- val = list.objectAtIndex(pos);
- select(val, c);
- return;
- }
- //If value binding is present, lookup the value
- java.util.Enumeration numerador = list.objectEnumerator();
- while (numerador.hasMoreElements()) {
- Object o = numerador.nextElement();
- if (o instanceof NSKeyValueCodingAdditions) {
- Object x = ((NSKeyValueCodingAdditions)o).valueForKeyPath(valueKey);
- if (x != null && x.equals(val)) {
- select(o, c);
- return;
- }
- }
- }
- }
+ public WOPopUpButton() {
+ super();
+ }
+
+ public WOPopUpButton(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected String inputType() {
+ return "SELECT";
+ }
+
+ protected int inputSize() {
+ return 1;
+ }
+
+ protected NSArray list(WOContext c) {
+ NSArray l = (NSArray) valueForProperty("list", c.component());
+ if (l == null)
+ l = NSArray.EmptyArray;
+ return l;
+ }
+
+ protected void setItem(Object v, WOContext c) {
+ if (associations.objectForKey("item") == null)
+ return;
+ setValueForProperty("item", v, c.component());
+ }
+
+ protected Object item(WOContext c) {
+ return valueForProperty("item", c.component());
+ }
+
+ protected void setSelection(Object v, WOContext c) {
+ if (associations.objectForKey("selection") == null)
+ return;
+ setValueForProperty("selection", v, c.component());
+ }
+
+ protected Object selection(WOContext c) {
+ return valueForProperty("selection", c.component());
+ }
+
+ public Object value(WOContext c) {
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<SELECT NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\" SIZE=");
+ r.appendContentString(Integer.toString(inputSize()));
+ r.appendContentString(">");
+ java.util.Enumeration numerador = list(c).objectEnumerator();
+ String displayKey = stringForProperty("displayString", c.component());
+ String valueKey = stringForProperty("value", c.component());
+ Object sel = selection(c);
+ if (sel == null)
+ sel = item(c);
+ int pos = 0;
+ while (numerador.hasMoreElements()) {
+ Object item = numerador.nextElement();
+ setItem(item, c);
+ r.appendContentString("<OPTION ");
+ // Append the "SELECTED" attribute if it's the selected item
+ if (sel != null && item.equals(sel))
+ r.appendContentString("SELECTED ");
+ r.appendContentString("VALUE=\"");
+ // Append the value
+ if (valueKey != null && item instanceof NSKeyValueCodingAdditions) {
+ Object val = ((NSKeyValueCodingAdditions) item).valueForKeyPath(valueKey);
+ if (val == null)
+ val = "null";
+ r.appendContentString(val.toString());
+ } else
+ r.appendContentString(Integer.toString(pos));
+ r.appendContentString("\">");
+ // Append display string
+ if (displayKey != null && item instanceof NSKeyValueCodingAdditions) {
+ Object ds = ((NSKeyValueCodingAdditions) item).valueForKeyPath(displayKey);
+ if (ds == null)
+ ds = "";
+ r.appendContentString(ds.toString());
+ } else
+ r.appendContentString(item.toString());
+ r.appendContentString("\n");
+ pos++;
+ }
+ r.appendContentString("</SELECT>");
+ }
+
+ protected void select(Object v, WOContext c) {
+ if (associations.objectForKey("selection") != null) {
+ setSelection(v, c);
+ return;
+ }
+ if (associations.objectForKey("item") != null) {
+ setItem(v, c);
+ }
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ Object val = r.formValueForKey(inputName(c));
+ if (val == null)
+ return;
+ NSArray list = list(c);
+ String valueKey = stringForProperty("value", c.component());
+ // If no value binding, just get the index
+ if (valueKey == null) {
+ int pos = Integer.parseInt(val.toString());
+ val = list.objectAtIndex(pos);
+ select(val, c);
+ return;
+ }
+ // If value binding is present, lookup the value
+ java.util.Enumeration numerador = list.objectEnumerator();
+ while (numerador.hasMoreElements()) {
+ Object o = numerador.nextElement();
+ if (o instanceof NSKeyValueCodingAdditions) {
+ Object x = ((NSKeyValueCodingAdditions) o).valueForKeyPath(valueKey);
+ if (x != null && x.equals(val)) {
+ select(o, c);
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
index 386218c..b06b052 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORadioButton.java
@@ -5,16 +5,16 @@ import net.wotonomy.foundation.NSDictionary;
public class WORadioButton extends WOCheckBox {
- public WORadioButton() {
- super();
- }
+ public WORadioButton() {
+ super();
+ }
- public WORadioButton(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WORadioButton(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- protected String inputType() {
- return "RADIO";
- }
+ protected String inputType() {
+ return "RADIO";
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
index afa118a..53615a4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORepetition.java
@@ -25,155 +25,150 @@ import net.wotonomy.foundation.NSDictionary;
public class WORepetition extends WODynamicElement {
- protected int count;
- protected int index;
- protected Object item;
- protected Collection list;
- protected Iterator iterator;
-
- protected WORepetition() {
- super();
- }
-
- public WORepetition(String aName, NSDictionary aMap, WOElement template) {
- super(aName, aMap, template);
- }
-
- public void setCount(int value) {
- count = value;
- }
-
- public int count() {
- return count;
- }
-
- public void setIndex(int value) {
- index = value;
- }
- public int index() {
- return index;
- }
-
- public void setItem(Object value) {
- item = value;
- }
- public Object item() {
- return item;
- }
-
- public void setList(Collection value) {
- list = value;
- }
- public Collection list() {
- return list;
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- rootElement.takeValuesFromRequest(r, c);
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null && index >= count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- WOActionResults e = rootElement.invokeAction(r, c);
- if (e != null)
- {
- iterator = null;
- return e;
- }
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null && index >= count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- return null;
- }
-
- public void appendToResponse(WOResponse r, WOContext c) {
- c.appendZeroElementIDComponent();
- pullValuesFromParent(c.component());
- index = 0;
- WOAssociation countAsoc = (WOAssociation)associations.objectForKey("count");
- item = getNextItem();
- while (item != null) {
- pushValuesToParent(c.component());
- rootElement.appendToResponse(r, c);
- index++;
- c.incrementLastElementIDComponent();
- if (countAsoc != null || index < count())
- item = null;
- else
- item = getNextItem();
- }
- iterator = null;
- c.deleteLastElementIDComponent();
- }
-
- protected Object getNextItem() {
- if ( iterator == null )
- {
- if ( list == null ) return null;
- iterator = list.iterator();
- }
- if ( iterator.hasNext() )
- {
- return iterator.next();
- }
- return null;
- }
-
- protected void pullValuesFromParent(WOComponent c) {
- Object value;
-
- value = valueForProperty("count", c);
- if ( value instanceof Number )
- {
- setCount( ((Number)value).intValue() );
- }
- else
- {
- setCount( -1 );
- }
-
- value = valueForProperty("list", c);
- if ( value instanceof Collection )
- {
- setList( (Collection) value );
- }
- else
- {
- setList( null );
- }
- }
-
- protected void pushValuesToParent(WOComponent c) {
- setValueForProperty("index", new Integer(index), c);
- setValueForProperty("item", item, c);
- }
+ protected int count;
+ protected int index;
+ protected Object item;
+ protected Collection list;
+ protected Iterator iterator;
+
+ protected WORepetition() {
+ super();
+ }
+
+ public WORepetition(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ }
+
+ public void setCount(int value) {
+ count = value;
+ }
+
+ public int count() {
+ return count;
+ }
+
+ public void setIndex(int value) {
+ index = value;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public void setItem(Object value) {
+ item = value;
+ }
+
+ public Object item() {
+ return item;
+ }
+
+ public void setList(Collection value) {
+ list = value;
+ }
+
+ public Collection list() {
+ return list;
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ rootElement.takeValuesFromRequest(r, c);
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null && index >= count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ WOActionResults e = rootElement.invokeAction(r, c);
+ if (e != null) {
+ iterator = null;
+ return e;
+ }
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null && index >= count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ return null;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ c.appendZeroElementIDComponent();
+ pullValuesFromParent(c.component());
+ index = 0;
+ WOAssociation countAsoc = (WOAssociation) associations.objectForKey("count");
+ item = getNextItem();
+ while (item != null) {
+ pushValuesToParent(c.component());
+ rootElement.appendToResponse(r, c);
+ index++;
+ c.incrementLastElementIDComponent();
+ if (countAsoc != null || index < count())
+ item = null;
+ else
+ item = getNextItem();
+ }
+ iterator = null;
+ c.deleteLastElementIDComponent();
+ }
+
+ protected Object getNextItem() {
+ if (iterator == null) {
+ if (list == null)
+ return null;
+ iterator = list.iterator();
+ }
+ if (iterator.hasNext()) {
+ return iterator.next();
+ }
+ return null;
+ }
+
+ protected void pullValuesFromParent(WOComponent c) {
+ Object value;
+
+ value = valueForProperty("count", c);
+ if (value instanceof Number) {
+ setCount(((Number) value).intValue());
+ } else {
+ setCount(-1);
+ }
+
+ value = valueForProperty("list", c);
+ if (value instanceof Collection) {
+ setList((Collection) value);
+ } else {
+ setList(null);
+ }
+ }
+
+ protected void pushValuesToParent(WOComponent c) {
+ setValueForProperty("index", new Integer(index), c);
+ setValueForProperty("item", item, c);
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
index 7d71223..34f7414 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequest.java
@@ -33,554 +33,479 @@ import net.wotonomy.foundation.NSMutableData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WORequest.
-* This implementation is backed by an HttpServletRequest,
-* and thus does not support application-specific subclassing.
-* Future implementations may remove this limitation.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WORequest extends WOResponse
-{
- HttpServletRequest request;
- private WOApplication application;
- private NSArray languages;
- private String requestHandlerKey;
- private String requestHandlerPath;
- private String pageName;
- private String contextID;
- private String senderID;
- private String defaultFormValueEncoding;
-
- /**
- * Parameterless constructor which should not be called.
- */
- public WORequest ()
- {
- throw new RuntimeException(
- "This constructor is not yet supported." );
- }
-
- /**
- * Standard constructor. Method and URL are required.
- * HeaderMap is a map of header names to arrays containing
- * one or more values. Data is the content of the request.
- * UserInfo contains application-defined paramters that get
- * passed to all objects involved in dispatching the request.
- */
- public WORequest
- (String aMethod, String aURL, String aProtocolName,
- NSDictionary headerMap, NSData aData, NSDictionary userInfo)
- {
- throw new RuntimeException(
- "This constructor is not yet supported." );
- }
-
- /**
- * The only supported constructor for this implementation.
- * This WORequest will wrap the specified servlet request.
- */
- public WORequest( HttpServletRequest aRequest, WOApplication anApplication )
- {
+ * A pure java implementation of WORequest. This implementation is backed by an
+ * HttpServletRequest, and thus does not support application-specific
+ * subclassing. Future implementations may remove this limitation.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WORequest extends WOResponse {
+ HttpServletRequest request;
+ private WOApplication application;
+ private NSArray languages;
+ private String requestHandlerKey;
+ private String requestHandlerPath;
+ private String pageName;
+ private String contextID;
+ private String senderID;
+ private String defaultFormValueEncoding;
+
+ /**
+ * Parameterless constructor which should not be called.
+ */
+ public WORequest() {
+ throw new RuntimeException("This constructor is not yet supported.");
+ }
+
+ /**
+ * Standard constructor. Method and URL are required. HeaderMap is a map of
+ * header names to arrays containing one or more values. Data is the content of
+ * the request. UserInfo contains application-defined paramters that get passed
+ * to all objects involved in dispatching the request.
+ */
+ public WORequest(String aMethod, String aURL, String aProtocolName, NSDictionary headerMap, NSData aData,
+ NSDictionary userInfo) {
+ throw new RuntimeException("This constructor is not yet supported.");
+ }
+
+ /**
+ * The only supported constructor for this implementation. This WORequest will
+ * wrap the specified servlet request.
+ */
+ public WORequest(HttpServletRequest aRequest, WOApplication anApplication) {
request = aRequest;
- application = anApplication;
-
- languages = null;
- senderID = null;
- pageName = null;
- contextID = null;
- defaultFormValueEncoding = "ISO8859_1";
- requestHandlerKey = WOApplication.directActionRequestHandlerKey();
- requestHandlerPath = request.getServletPath(); // request.getPathInfo();
- String remainder = requestHandlerPath;
- if ( requestHandlerPath == null ) requestHandlerPath = "";
- if ( requestHandlerPath.length() > 0 )
- {
- int i;
-
- // get request handler key
- i = requestHandlerPath.indexOf( "/", 1 );
- if ( i != -1 )
- {
- requestHandlerKey = requestHandlerPath.substring( 1, i );
- requestHandlerPath = requestHandlerPath.substring( i );
- }
-
- Enumeration e = requestHandlerPathArray().objectEnumerator();
- // skipping session ID for now
- if ( e.hasMoreElements() )
- {
- pageName = e.nextElement().toString();
- }
- if ( e.hasMoreElements() )
- {
- contextID = e.nextElement().toString();
- }
- if ( e.hasMoreElements() )
- {
- senderID = e.nextElement().toString();
- }
- }
- }
-
- /**
- * Returns the HTTP method of the request: "GET" or "POST",
- * or possibly "PUT".
- */
- public String method ()
- {
- return request.getMethod();
- }
-
- /**
- * Returns the Uniform Resource Identifier, which is the part
- * of the request URL after the protocol name (after the port
- * number) and before the query parameters (before the question mark).
- */
- public String uri ()
- {
- return request.getRequestURI();
- }
-
- /**
- * Returns the name of the protocol (presumably HTTP) and the
- * version used by the client as sent in the request headers.
- */
- public String httpVersion ()
- {
- return request.getProtocol();
- }
-
- /**
- * Returns an array of the header names in this request
- * in no particular order.
- */
- public NSArray headerKeys ()
- {
- return arrayFromEnumeration( request.getHeaderNames() );
- }
-
- /**
- * Returns an array of the header values for the specified key
- * in no particular order.
- */
- public NSArray headersForKey (String aString)
- {
- return arrayFromEnumeration( request.getHeaders( aString ) );
- }
-
- /**
- * Returns one value for the specified header key.
- * Provided as a convenience since most headers have
- * only one value. Returns null if not found.
- */
- public String headerForKey (String aKey)
- {
- return request.getHeader( aKey );
- }
-
- /**
- * Returns the content of the request, or null if no content.
- * The type of the content is determined by the "content-type" header.
- * On error, null is returned.
- */
- public NSData content ()
- {
- //TODO: This is broken!
- NSMutableData data = new NSMutableData();
- try
- {
- byte[] buf = new byte[ request.getContentLength() ];
- InputStream is = request.getInputStream();
-
+ application = anApplication;
+
+ languages = null;
+ senderID = null;
+ pageName = null;
+ contextID = null;
+ defaultFormValueEncoding = "ISO8859_1";
+ requestHandlerKey = WOApplication.directActionRequestHandlerKey();
+ requestHandlerPath = request.getServletPath(); // request.getPathInfo();
+ String remainder = requestHandlerPath;
+ if (requestHandlerPath == null)
+ requestHandlerPath = "";
+ if (requestHandlerPath.length() > 0) {
+ int i;
+
+ // get request handler key
+ i = requestHandlerPath.indexOf("/", 1);
+ if (i != -1) {
+ requestHandlerKey = requestHandlerPath.substring(1, i);
+ requestHandlerPath = requestHandlerPath.substring(i);
+ }
+
+ Enumeration e = requestHandlerPathArray().objectEnumerator();
+ // skipping session ID for now
+ if (e.hasMoreElements()) {
+ pageName = e.nextElement().toString();
+ }
+ if (e.hasMoreElements()) {
+ contextID = e.nextElement().toString();
+ }
+ if (e.hasMoreElements()) {
+ senderID = e.nextElement().toString();
+ }
+ }
+ }
+
+ /**
+ * Returns the HTTP method of the request: "GET" or "POST", or possibly "PUT".
+ */
+ public String method() {
+ return request.getMethod();
+ }
+
+ /**
+ * Returns the Uniform Resource Identifier, which is the part of the request URL
+ * after the protocol name (after the port number) and before the query
+ * parameters (before the question mark).
+ */
+ public String uri() {
+ return request.getRequestURI();
+ }
+
+ /**
+ * Returns the name of the protocol (presumably HTTP) and the version used by
+ * the client as sent in the request headers.
+ */
+ public String httpVersion() {
+ return request.getProtocol();
+ }
+
+ /**
+ * Returns an array of the header names in this request in no particular order.
+ */
+ public NSArray headerKeys() {
+ return arrayFromEnumeration(request.getHeaderNames());
+ }
+
+ /**
+ * Returns an array of the header values for the specified key in no particular
+ * order.
+ */
+ public NSArray headersForKey(String aString) {
+ return arrayFromEnumeration(request.getHeaders(aString));
+ }
+
+ /**
+ * Returns one value for the specified header key. Provided as a convenience
+ * since most headers have only one value. Returns null if not found.
+ */
+ public String headerForKey(String aKey) {
+ return request.getHeader(aKey);
+ }
+
+ /**
+ * Returns the content of the request, or null if no content. The type of the
+ * content is determined by the "content-type" header. On error, null is
+ * returned.
+ */
+ public NSData content() {
+ // TODO: This is broken!
+ NSMutableData data = new NSMutableData();
+ try {
+ byte[] buf = new byte[request.getContentLength()];
+ InputStream is = request.getInputStream();
+
// this is so very not efficient
int len;
- while ( ( len = is.read( buf ) ) > -1 )
- {
- // copies data twice...
- data.appendData( new NSData( buf, 0, len ) );
- }
- }
- catch ( Exception exc )
- {
+ while ((len = is.read(buf)) > -1) {
+ // copies data twice...
+ data.appendData(new NSData(buf, 0, len));
+ }
+ } catch (Exception exc) {
return null;
}
return data;
- }
-
- /**
- * Returns the application-specific userInfo dictionary.
- * This implementation returns the servlet attribute map.
- */
- public NSDictionary userInfo ()
- {
- //TODO: Test this logic.
- Object key, value;
- NSMutableDictionary info = new NSMutableDictionary();
- java.util.Enumeration e = request.getAttributeNames();
- while ( e.hasMoreElements() )
- {
- key = e.nextElement();
- value = request.getAttribute( e.nextElement().toString() );
- if ( value != null )
- {
- info.setObjectForKey( value, key );
- }
- }
- return info;
- }
-
- /**
- * Returns the items in the request handler path parsed
- * by the "/" delimiter and put into an array.
- */
- public NSArray requestHandlerPathArray ()
- {
- return NSArray.componentsSeparatedByString( requestHandlerPath(), "/" );
- }
-
- /**
- * Returns the client's preferred languages in decreasing
- * order of preference. The strings are returned in java
- * Locale format, meaning dashes (-) are converted to
- * underbars (_): see java.util.Locale.toString().
- */
- public NSArray browserLanguages ()
- {
- if ( languages == null )
- {
- languages = arrayFromEnumeration( request.getLocales() );
- }
- return languages;
- }
-
- /**
- * Returns the portion of the URI specifying the engine within which
- * this web application is running. This is important for generating
- * URLs to be used in the content of the response.
- */
- public String adaptorPrefix ()
- {
- //TODO: Test this logic.
- String name = request.getServletPath();
- return name;
-
+ }
+
+ /**
+ * Returns the application-specific userInfo dictionary. This implementation
+ * returns the servlet attribute map.
+ */
+ public NSDictionary userInfo() {
+ // TODO: Test this logic.
+ Object key, value;
+ NSMutableDictionary info = new NSMutableDictionary();
+ java.util.Enumeration e = request.getAttributeNames();
+ while (e.hasMoreElements()) {
+ key = e.nextElement();
+ value = request.getAttribute(e.nextElement().toString());
+ if (value != null) {
+ info.setObjectForKey(value, key);
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Returns the items in the request handler path parsed by the "/" delimiter and
+ * put into an array.
+ */
+ public NSArray requestHandlerPathArray() {
+ return NSArray.componentsSeparatedByString(requestHandlerPath(), "/");
+ }
+
+ /**
+ * Returns the client's preferred languages in decreasing order of preference.
+ * The strings are returned in java Locale format, meaning dashes (-) are
+ * converted to underbars (_): see java.util.Locale.toString().
+ */
+ public NSArray browserLanguages() {
+ if (languages == null) {
+ languages = arrayFromEnumeration(request.getLocales());
+ }
+ return languages;
+ }
+
+ /**
+ * Returns the portion of the URI specifying the engine within which this web
+ * application is running. This is important for generating URLs to be used in
+ * the content of the response.
+ */
+ public String adaptorPrefix() {
+ // TODO: Test this logic.
+ String name = request.getServletPath();
+ return name;
+
// String uri = request.getRequestURI();
// int end = uri.indexOf( request.getPathInfo() );
// return uri.substring( request.getContextPath().length(), end );
- }
-
- /**
- * Returns the application name as specified in the request URI.
- * Note that wotonomy web applications do not typically have a .woa
- * extension, but the extension will be included for those that do.
- */
- public String applicationName ()
- {
- return request.getContextPath();
- }
-
- /**
- * Returns the id of the application instance that is needed to
- * service this request. -1 indicates that the request is not
- * specific to a particular instance of the application.
- * This implementation currently returns -1.
- */
- public int applicationNumber ()
- {
+ }
+
+ /**
+ * Returns the application name as specified in the request URI. Note that
+ * wotonomy web applications do not typically have a .woa extension, but the
+ * extension will be included for those that do.
+ */
+ public String applicationName() {
+ return request.getContextPath();
+ }
+
+ /**
+ * Returns the id of the application instance that is needed to service this
+ * request. -1 indicates that the request is not specific to a particular
+ * instance of the application. This implementation currently returns -1.
+ */
+ public int applicationNumber() {
return -1;
- }
-
- /**
- * Returns the portion of the URI that specifies which request handler
- * should handle the request.
- */
- public String requestHandlerKey ()
- {
- return requestHandlerKey;
- }
-
- /**
- * Returns the portion of the URI that specifies path information
- * for the request, not including the query string.
- */
- public String requestHandlerPath ()
- {
- return requestHandlerPath;
- }
-
- /**
- * Returns the unique identifier for the sessions associated with
- * this request, or null if no session is found.
- */
- public String sessionID ()
- {
- HttpSession session = request.getSession( false );
- if ( session == null ) return null;
- return session.getId();
- }
-
- /**
- * Returns an array containing all the form keys in the request.
- */
- public NSArray formValueKeys ()
- {
- return arrayFromEnumeration( request.getParameterNames() );
- }
-
- /**
- * Returns an array of the values for the specified key in
- * no particular order.
- */
- public NSArray formValuesForKey (String aKey)
- {
- NSMutableArray result = new NSMutableArray();
- String[] values = request.getParameterValues( aKey );
- if ( values != null )
- {
- for ( int i = 0; i < values.length; i++ )
- {
- result.addObject( values[i] );
- }
- }
- return result;
- }
-
- /**
- * Returns one value for the specified key.
- * Provided as a convenience since most keys have
- * only one value. Returns null if not found.
- */
- public Object formValueForKey (String aKey)
- {
- return request.getParameter( aKey );
- }
-
- /**
- * Returns the value for the specified key, as a String.
- */
- public String stringFormValueForKey(String key) {
- Object x = formValueForKey(key);
- if (x != null)
- return x.toString();
- return null;
- }
-
- /**
- * Returns a dictionary containing all the key-value
- * mappings in the request.
- */
- public NSDictionary formValues ()
- {
- NSMutableDictionary result = new NSMutableDictionary ();
- java.util.Enumeration e = request.getParameterNames();
- String key;
- while ( e.hasMoreElements() )
- {
- key = e.nextElement().toString();
- result.setObjectForKey( formValuesForKey( key ), key );
- }
- return result;
- }
-
- /**
- * Returns whether the request is from a java-based client component.
- * This implementation returns false.
- */
- public boolean isFromClientComponent ()
- {
- return false;
- }
-
- /**
- * Returns an array of cookie values for the specified key in
- * no particular order.
- */
- public NSArray cookieValuesForKey (String aKey)
- {
- // TODO: Test this logic.
- NSMutableArray result = new NSMutableArray();
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return result;
-
- for ( int i = 0; i < cookies.length; i++ )
- {
- if ( cookies[i].getName().equals( aKey ) )
- {
- result.addObject( cookies[i].getValue() );
- }
- }
-
- return result;
- }
-
- /**
- * Returns one value for the specified cookie key.
- * Provided as a convenience since most cookies have
- * only one value. Returns null if not found.
- */
- public String cookieValueForKey (String aKey)
- {
- // TODO: Test this logic.
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return null;
-
- for ( int i = 0; i < cookies.length; i++ )
- {
- if ( cookies[i].getName().equals( aKey ) )
- {
- return cookies[i].getValue();
- }
- }
-
- return null;
- }
-
- /**
- * Returns a dictionary of cookie key-value mappings.
- */
- public NSDictionary cookieValues ()
- {
- // TODO: Test this logic.
- NSMutableDictionary result = new NSMutableDictionary();
- Cookie[] cookies = request.getCookies();
- if ( cookies == null ) return result;
-
- NSMutableArray value;
- for ( int i = 0; i < cookies.length; i++ )
- {
- value = (NSMutableArray) result.objectForKey(
- cookies[i].getName() );
- if ( value == null )
- {
- value = new NSMutableArray();
- result.setObjectForKey(
- cookies[i].getValue(), cookies[i].getName() );
+ }
+
+ /**
+ * Returns the portion of the URI that specifies which request handler should
+ * handle the request.
+ */
+ public String requestHandlerKey() {
+ return requestHandlerKey;
+ }
+
+ /**
+ * Returns the portion of the URI that specifies path information for the
+ * request, not including the query string.
+ */
+ public String requestHandlerPath() {
+ return requestHandlerPath;
+ }
+
+ /**
+ * Returns the unique identifier for the sessions associated with this request,
+ * or null if no session is found.
+ */
+ public String sessionID() {
+ HttpSession session = request.getSession(false);
+ if (session == null)
+ return null;
+ return session.getId();
+ }
+
+ /**
+ * Returns an array containing all the form keys in the request.
+ */
+ public NSArray formValueKeys() {
+ return arrayFromEnumeration(request.getParameterNames());
+ }
+
+ /**
+ * Returns an array of the values for the specified key in no particular order.
+ */
+ public NSArray formValuesForKey(String aKey) {
+ NSMutableArray result = new NSMutableArray();
+ String[] values = request.getParameterValues(aKey);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ result.addObject(values[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns one value for the specified key. Provided as a convenience since most
+ * keys have only one value. Returns null if not found.
+ */
+ public Object formValueForKey(String aKey) {
+ return request.getParameter(aKey);
+ }
+
+ /**
+ * Returns the value for the specified key, as a String.
+ */
+ public String stringFormValueForKey(String key) {
+ Object x = formValueForKey(key);
+ if (x != null)
+ return x.toString();
+ return null;
+ }
+
+ /**
+ * Returns a dictionary containing all the key-value mappings in the request.
+ */
+ public NSDictionary formValues() {
+ NSMutableDictionary result = new NSMutableDictionary();
+ java.util.Enumeration e = request.getParameterNames();
+ String key;
+ while (e.hasMoreElements()) {
+ key = e.nextElement().toString();
+ result.setObjectForKey(formValuesForKey(key), key);
+ }
+ return result;
+ }
+
+ /**
+ * Returns whether the request is from a java-based client component. This
+ * implementation returns false.
+ */
+ public boolean isFromClientComponent() {
+ return false;
+ }
+
+ /**
+ * Returns an array of cookie values for the specified key in no particular
+ * order.
+ */
+ public NSArray cookieValuesForKey(String aKey) {
+ // TODO: Test this logic.
+ NSMutableArray result = new NSMutableArray();
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return result;
+
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(aKey)) {
+ result.addObject(cookies[i].getValue());
}
- value.addObject( cookies[i].getValue() );
- }
-
- return result;
- }
-
- /**
- * Sets the default character encoding.
- */
- public void setDefaultFormValueEncoding (String encoding)
- {
- defaultFormValueEncoding = encoding;
- }
-
- /**
- * Returns the default form value encoding ("ISO8859_1").
- */
- public String defaultFormValueEncoding ()
- {
- return defaultFormValueEncoding;
- }
-
- /**
- * Sets whether the appropriate encoding scheme for decoding
- * the form values will be automatically determined.
- */
- public void setFormValueEncodingDetectionEnabled (boolean enabled)
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Gets whether the appropriate encoding scheme for decoding
- * the form values is currently automatically determined.
- */
- public boolean isFormValueEncodingDetectionEnabled ()
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Gets the current method used for decoding form values.
- */
- public int formValueEncoding ()
- {
- throw new RuntimeException( "Not yet implemented." );
- }
-
- /**
- * Returns the host name of the server that is the target of this request.
- * NOTE: This method is not published in the WORequest specification.
- */
- String applicationHost ()
- {
- // FIXME: this should call WOApplication.hostname();
- return request.getServerName();
- }
-
- /**
- * Returns the port of the server that is the target of this request.
- * NOTE: This method is not published in the WORequest specification.
- */
- int port()
- {
- // FIXME: this should call WOApplication.port();
- return request.getServerPort();
- }
-
- /**
- * Returns the backing HttpServletRequest.
- */
- HttpServletRequest servletRequest ()
- {
- return request;
- }
-
- /**
- * Returns the application that was the target of this request.
- * This method is not published in the WORequest specification.
- */
- WOApplication application ()
- {
- return application;
- }
-
- /**
- * This method is not published in the WORequest specification.
- * This sender id from the URI, which is the id of the element
- * that generated this request.
- */
- String senderID ()
- {
- return senderID;
- }
-
- /**
- * This method is not published in the WORequest specification.
- * This returns the context id from the URI.
- */
- String contextID ()
- {
- return contextID;
- }
-
- /**
- * This method is not published in the WORequest specification.
- */
- String pageName ()
- {
- return pageName;
- }
-
- /**
- * Convenience method to populate an NSArray from an Enumeration.
- */
- private static NSArray arrayFromEnumeration( java.util.Enumeration e )
- {
- NSMutableArray result = new NSMutableArray();
- while ( e.hasMoreElements() )
- {
- result.addObject( e.nextElement() );
- }
- return result;
- }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns one value for the specified cookie key. Provided as a convenience
+ * since most cookies have only one value. Returns null if not found.
+ */
+ public String cookieValueForKey(String aKey) {
+ // TODO: Test this logic.
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return null;
+
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(aKey)) {
+ return cookies[i].getValue();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a dictionary of cookie key-value mappings.
+ */
+ public NSDictionary cookieValues() {
+ // TODO: Test this logic.
+ NSMutableDictionary result = new NSMutableDictionary();
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null)
+ return result;
+
+ NSMutableArray value;
+ for (int i = 0; i < cookies.length; i++) {
+ value = (NSMutableArray) result.objectForKey(cookies[i].getName());
+ if (value == null) {
+ value = new NSMutableArray();
+ result.setObjectForKey(cookies[i].getValue(), cookies[i].getName());
+ }
+ value.addObject(cookies[i].getValue());
+ }
+
+ return result;
+ }
+
+ /**
+ * Sets the default character encoding.
+ */
+ public void setDefaultFormValueEncoding(String encoding) {
+ defaultFormValueEncoding = encoding;
+ }
+
+ /**
+ * Returns the default form value encoding ("ISO8859_1").
+ */
+ public String defaultFormValueEncoding() {
+ return defaultFormValueEncoding;
+ }
+
+ /**
+ * Sets whether the appropriate encoding scheme for decoding the form values
+ * will be automatically determined.
+ */
+ public void setFormValueEncodingDetectionEnabled(boolean enabled) {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Gets whether the appropriate encoding scheme for decoding the form values is
+ * currently automatically determined.
+ */
+ public boolean isFormValueEncodingDetectionEnabled() {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Gets the current method used for decoding form values.
+ */
+ public int formValueEncoding() {
+ throw new RuntimeException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the host name of the server that is the target of this request. NOTE:
+ * This method is not published in the WORequest specification.
+ */
+ String applicationHost() {
+ // FIXME: this should call WOApplication.hostname();
+ return request.getServerName();
+ }
+
+ /**
+ * Returns the port of the server that is the target of this request. NOTE: This
+ * method is not published in the WORequest specification.
+ */
+ int port() {
+ // FIXME: this should call WOApplication.port();
+ return request.getServerPort();
+ }
+
+ /**
+ * Returns the backing HttpServletRequest.
+ */
+ HttpServletRequest servletRequest() {
+ return request;
+ }
+
+ /**
+ * Returns the application that was the target of this request. This method is
+ * not published in the WORequest specification.
+ */
+ WOApplication application() {
+ return application;
+ }
+
+ /**
+ * This method is not published in the WORequest specification. This sender id
+ * from the URI, which is the id of the element that generated this request.
+ */
+ String senderID() {
+ return senderID;
+ }
+
+ /**
+ * This method is not published in the WORequest specification. This returns the
+ * context id from the URI.
+ */
+ String contextID() {
+ return contextID;
+ }
+
+ /**
+ * This method is not published in the WORequest specification.
+ */
+ String pageName() {
+ return pageName;
+ }
+
+ /**
+ * Convenience method to populate an NSArray from an Enumeration.
+ */
+ private static NSArray arrayFromEnumeration(java.util.Enumeration e) {
+ NSMutableArray result = new NSMutableArray();
+ while (e.hasMoreElements()) {
+ result.addObject(e.nextElement());
+ }
+ return result;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
index 957cf25..7e3c624 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WORequestHandler.java
@@ -21,44 +21,37 @@ package net.wotonomy.web;
import net.wotonomy.foundation.internal.NetworkClassLoader;
/**
-* A pure java implementation that corresponds
-* to the abstract class WORequestHandler.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public abstract class WORequestHandler
-{
+ * A pure java implementation that corresponds to the abstract class
+ * WORequestHandler.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public abstract class WORequestHandler {
private NetworkClassLoader loader;
-
+
/**
- * Default constructor.
- */
- public WORequestHandler()
- {
- loader = new NetworkClassLoader( WOApplication.application().getClass().getClassLoader() );
+ * Default constructor.
+ */
+ public WORequestHandler() {
+ loader = new NetworkClassLoader(WOApplication.application().getClass().getClassLoader());
}
-
+
/**
- * Dispatches the request and returns the response.
- */
- abstract public WOResponse handleRequest (WORequest aRequest);
-
+ * Dispatches the request and returns the response.
+ */
+ abstract public WOResponse handleRequest(WORequest aRequest);
+
/**
- * Gets the specified class, loading it if it has not already been
- * loaded or if it has been modified. Returns null if not found.
- * Because this method is not in the specification, it has only
- * package access.
- */
- Class loadClass( String aName )
- {
- try
- {
- return loader.loadClass( aName, true );
- }
- catch ( ClassNotFoundException cnfe )
- {
+ * Gets the specified class, loading it if it has not already been loaded or if
+ * it has been modified. Returns null if not found. Because this method is not
+ * in the specification, it has only package access.
+ */
+ Class loadClass(String aName) {
+ try {
+ return loader.loadClass(aName, true);
+ } catch (ClassNotFoundException cnfe) {
return null;
}
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
index 8428681..f4fb49f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResetButton.java
@@ -21,30 +21,31 @@ package net.wotonomy.web;
import net.wotonomy.foundation.NSDictionary;
/**
-* Implements a reset button with dynamic bindings.
+ * Implements a reset button with dynamic bindings.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOResetButton extends WOInput {
- public WOResetButton() {
- super();
- }
+ public WOResetButton() {
+ super();
+ }
- public WOResetButton(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOResetButton(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- protected String inputType() {
- return "RESET";
- }
+ protected String inputType() {
+ return "RESET";
+ }
- protected Object value(WOContext c) {
- Object v = valueForProperty("value", c.component());
- if (v == null)
- return "Reset";
- return v;
- }
+ protected Object value(WOContext c) {
+ Object v = valueForProperty("value", c.component());
+ if (v == null)
+ return "Reset";
+ return v;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
index c69c9db..5941ad2 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceManager.java
@@ -37,453 +37,353 @@ import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.foundation.internal.PropertyListParser;
/**
-* Manages all resources vended by the application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResourceManager
-{
- private NSMutableDictionary resourceCache;
- private NSMutableDictionary dynamicDataCache;
- private NSMutableDictionary stringTableCache;
- private Map localeCache; // used for wo-style i18n
- private Locale californiaLocale; // used for wo-style i18n
-
- /**
- * Constructor is only accessible to subclasses.
- */
- protected WOResourceManager()
- {
- resourceCache = new NSMutableDictionary();
- dynamicDataCache = new NSMutableDictionary();
- stringTableCache = new NSMutableDictionary();
- localeCache = new HashMap();
- californiaLocale = new Locale( "en", "US" );
- localeCache.put( "en", californiaLocale );
- }
-
- /**
- * Returns the raw data corresponding to the specified resource.
- * Any data retrieved by this method will be placed in the
- * resource manager's global cache.
- */
- public byte[] bytesForResourceNamed(String aFileName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- String mash = aFileName + aFrameworkName;
- if ( aLanguagesList != null )
- {
- mash = mash + aLanguagesList.componentsJoinedByString(":");
- }
-
- byte[] result = (byte[]) resourceCache.objectForKey( mash );
- if ( result == null )
- {
- InputStream input = inputStreamForResourceNamed(
- aFileName, aFrameworkName, aLanguagesList );
- if ( input != null )
- {
- try
- {
- int c;
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- while ( ( c = input.read() ) != -1 )
- {
- output.write( c );
- }
- output.flush();
- input.close();
- output.close();
- result = output.toByteArray();
- synchronized ( resourceCache )
- {
- resourceCache.setObjectForKey( result, mash );
- }
- }
- catch ( Throwable t )
- {
- System.err.println( "WOResourceManager: Error reading bytes: " + aFileName );
- t.printStackTrace();
- }
- }
- }
- return result;
- }
-
- /**
- * Returns the content type corresponding to the specified resource.
- * This implementation recognizes gif, jpg, png, html, and xml extensions.
- * Otherwise, "text/plain" is returned.
- */
- public String contentTypeForResourceNamed(String aResourcePath)
- {
- if ( aResourcePath.endsWith( ".gif" ) ) return "image/gif";
- if ( aResourcePath.endsWith( ".jpg" ) ) return "image/jpeg";
- if ( aResourcePath.endsWith( ".png" ) ) return "image/png";
- if ( aResourcePath.endsWith( ".html" ) ) return "text/html";
- if ( aResourcePath.endsWith( ".xml" ) ) return "text/xml";
- return "text/plain";
- }
-
- /**
- * Returns a url to be used when errors occur while retrieving a resource.
- */
- public String errorMessageUrlForResourceNamed(String aResourceName,
- String aFrameworkName)
- {
- if ( aResourceName == null ) aResourceName = "null";
- if ( aFrameworkName == null )
- {
- return "/ERROR/NOT_FOUND/app=" +
- WOApplication.application().name() +
- "/filename=" + aResourceName;
- }
- else
- {
- return "/ERROR/NOT_FOUND/framework=" +
- aFrameworkName + "/filename=" + aResourceName;
- }
-
- }
-
- /**
- * Clears all cached system-wide resource data.
- */
- public void flushDataCache()
- {
- synchronized ( resourceCache )
- {
- resourceCache.removeAllObjects();
- }
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.removeAllObjects();
- }
- synchronized ( stringTableCache )
- {
- stringTableCache.removeAllObjects();
- }
- }
-
- /**
- * Returns the file-system path for the specified resource.
- * Deprecated and not implemented.
- * @deprecated Use inputStreamForResourceNamed instead.
- */
- public String pathForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- throw new RuntimeException( "ResourceManager.pathForResourceNamed: deprecated" );
- }
-
- /**
- * Removes the data from the dynamic data cache for the specified session.
- * If aSession is null, the data is removed from the application-wide
- * data cache.
- */
- public void removeDataForKey(String aKey,
- WOSession aSession)
- {
- if ( aSession != null )
- {
- if ( aSession.dynamicDataCache != null )
- {
- aSession.dynamicDataCache.removeObjectForKey( aKey );
- }
- }
- else
- {
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.removeObjectForKey( aKey );
- }
- }
- }
-
- /**
- * Sets the data in the dynamic data cache for the specified session.
- * If aSession is null, the data is placed in the application-wide
- * data cache. If the key is a system-generated key, the data will
- * be removed by calling removeData() the next time it is requested.
- */
- public void setData(NSData someData,
- String key,
- String type,
- WOSession aSession)
- {
- if ( aSession != null )
- {
- if ( aSession.dynamicDataCache != null )
- {
- aSession.dynamicDataCache.setObjectForKey(
- new TypedData( type, someData ), key );
- }
- }
- else
- {
- synchronized ( dynamicDataCache )
- {
- dynamicDataCache.setObjectForKey(
- new TypedData( type, someData ), key );
- }
- }
- }
-
- /**
- * Returns a localized string from a property list for
- * a given key. If the key doesn't exist, aDefaultValue
- * is returned.
- */
- public String stringForKey(String aKey,
- String aFileName,
- String aDefaultValue,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
-
- String mash = aFileName + aFrameworkName;
- if ( aLanguagesList != null )
- {
- mash = mash + aLanguagesList.componentsJoinedByString(":");
- }
-
- Object table = stringTableCache.objectForKey( mash );
- if ( table == null )
- {
- try
- {
- InputStream input = (InputStream) inputStreamForResourceNamed(
- aFileName, aFrameworkName, aLanguagesList);
- if ( input != null )
- {
- Reader reader =
- new BufferedReader(new InputStreamReader(input));
- table = PropertyListParser.propertyListFromReader( reader );
- synchronized ( stringTableCache )
- {
- stringTableCache.setObjectForKey( table, mash );
- }
- }
- }
- catch ( IOException ioe )
- {
- System.err.println( "WOResourceManager: error reading: " + aFileName );
- ioe.printStackTrace();
- }
- catch ( Throwable t )
- {
- // could not parse
- System.err.println( "WOResourceManager: could not parse: " + aFileName );
- System.err.println( t );
- }
- }
-
- Object result = null;
- if ( table != null )
- {
- result = NSKeyValueCoding.DefaultImplementation.valueForKey( table, aKey );
- }
- if ( result == null )
- {
- result = aDefaultValue;
- }
- else
- {
- result = result.toString();
- }
-
- return (String) result;
- }
-
- /**
- * Returns a url that invokes the resource manager for the
- * specified resource.
- */
- public String urlForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList,
- WORequest aRequest)
- {
- StringBuffer buffer = new StringBuffer();
- if ( aFrameworkName == null )
- {
- aFrameworkName = "application";
- }
- buffer.append( aRequest.applicationName() );
- buffer.append( '/' );
- buffer.append( WOApplication.resourceRequestHandlerKey() );
- if ( !aFrameworkName.startsWith("/") )
- {
- buffer.append( '/' );
- }
- buffer.append( aFrameworkName );
- buffer.append( '/' );
- buffer.append( aResourceName );
- return buffer.toString();
- }
-
- /**
- * Returns an input for the raw resource. Data returned by
- * this method will not be put in the resource manager's global cache.
- */
- public InputStream inputStreamForResourceNamed(String aResourceName,
- String aFrameworkName,
- NSArray aLanguagesList)
- {
- if ( aResourceName == null ) return null;
- InputStream result = null;
-
- StringBuffer path = new StringBuffer();
- path.append( '/' );
- if ( aFrameworkName != null )
- {
- path.append( aFrameworkName ).append( '/' );
- }
-
- int i = aResourceName.lastIndexOf( "." );
- if ( i != -1 )
- path.append( aResourceName.substring( 0, i ) );
- else
- path.append( aResourceName );
-
- String location = path.toString();
- if ( aLanguagesList != null )
- {
- String language;
- Locale locale;
- HashSet tried = new HashSet(5);
- Enumeration e = aLanguagesList.objectEnumerator();
- while ( e.hasMoreElements() && result == null )
- {
- language = e.nextElement().toString();
-
- // look for java-style localization
- if ( i != -1 )
- {
- result = getStream( location + '_'
- + language + aResourceName.substring( i ) );
- }
- else // no dot extension
- {
- result = getStream( location + '_' + language );
- }
-
- // look for wo-style localization
- if ( result == null )
- {
- locale = (Locale) localeCache.get( language );
- if ( locale == null )
- {
- if ( language.length() == 5 )
- {
- locale = new Locale(
- language.substring( 0, 2 ),
- language.substring( 3, 5 ) );
- }
- else
- {
- locale = new Locale( language, "" );
- }
- synchronized ( localeCache )
- {
- localeCache.put( language, locale );
- }
- }
-
- language = '/'+locale.getDisplayLanguage( californiaLocale )+".lproj";
- if ( !tried.contains( language ) )
- {
- if ( aFrameworkName != null )
- {
- int j = aFrameworkName.length()+1;
- path.insert( j, language );
- result = getStream( path.toString() + aResourceName.substring( i ) );
- path.delete( j, j+language.length() );
- }
- else
- {
- result = getStream( language + path.toString() + aResourceName.substring( i ) );
- }
- tried.add( language );
- }
- }
- }
- }
-
- // look for file in package
- if ( result == null )
- {
- if ( i != -1 )
- {
- result = getStream( path.append(
- aResourceName.substring( i ) ).toString() );
- }
- else // no dot extension
- {
- result = getStream( location );
- }
- }
-
- return result;
- }
-
- private static final InputStream getStream( String path )
- { //System.out.println( "getStream: " + path );
- InputStream input =
- WOApplication.application().getClass().getResourceAsStream( path );
- if ( input == null )
- {
- // in case the local class loader doesn't delegate to its parent
- input = ClassLoader.getSystemResourceAsStream( path );
- }
- return input;
- }
-
- private static final class TypedData
- {
- String type;
- NSData data;
-
- public TypedData( String aType, NSData aData )
- {
- type = aType;
- data = aData;
- }
- }
+ * Manages all resources vended by the application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResourceManager {
+ private NSMutableDictionary resourceCache;
+ private NSMutableDictionary dynamicDataCache;
+ private NSMutableDictionary stringTableCache;
+ private Map localeCache; // used for wo-style i18n
+ private Locale californiaLocale; // used for wo-style i18n
+
+ /**
+ * Constructor is only accessible to subclasses.
+ */
+ protected WOResourceManager() {
+ resourceCache = new NSMutableDictionary();
+ dynamicDataCache = new NSMutableDictionary();
+ stringTableCache = new NSMutableDictionary();
+ localeCache = new HashMap();
+ californiaLocale = new Locale("en", "US");
+ localeCache.put("en", californiaLocale);
+ }
+
+ /**
+ * Returns the raw data corresponding to the specified resource. Any data
+ * retrieved by this method will be placed in the resource manager's global
+ * cache.
+ */
+ public byte[] bytesForResourceNamed(String aFileName, String aFrameworkName, NSArray aLanguagesList) {
+ String mash = aFileName + aFrameworkName;
+ if (aLanguagesList != null) {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ byte[] result = (byte[]) resourceCache.objectForKey(mash);
+ if (result == null) {
+ InputStream input = inputStreamForResourceNamed(aFileName, aFrameworkName, aLanguagesList);
+ if (input != null) {
+ try {
+ int c;
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ while ((c = input.read()) != -1) {
+ output.write(c);
+ }
+ output.flush();
+ input.close();
+ output.close();
+ result = output.toByteArray();
+ synchronized (resourceCache) {
+ resourceCache.setObjectForKey(result, mash);
+ }
+ } catch (Throwable t) {
+ System.err.println("WOResourceManager: Error reading bytes: " + aFileName);
+ t.printStackTrace();
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the content type corresponding to the specified resource. This
+ * implementation recognizes gif, jpg, png, html, and xml extensions. Otherwise,
+ * "text/plain" is returned.
+ */
+ public String contentTypeForResourceNamed(String aResourcePath) {
+ if (aResourcePath.endsWith(".gif"))
+ return "image/gif";
+ if (aResourcePath.endsWith(".jpg"))
+ return "image/jpeg";
+ if (aResourcePath.endsWith(".png"))
+ return "image/png";
+ if (aResourcePath.endsWith(".html"))
+ return "text/html";
+ if (aResourcePath.endsWith(".xml"))
+ return "text/xml";
+ return "text/plain";
+ }
+
+ /**
+ * Returns a url to be used when errors occur while retrieving a resource.
+ */
+ public String errorMessageUrlForResourceNamed(String aResourceName, String aFrameworkName) {
+ if (aResourceName == null)
+ aResourceName = "null";
+ if (aFrameworkName == null) {
+ return "/ERROR/NOT_FOUND/app=" + WOApplication.application().name() + "/filename=" + aResourceName;
+ } else {
+ return "/ERROR/NOT_FOUND/framework=" + aFrameworkName + "/filename=" + aResourceName;
+ }
+
+ }
+
+ /**
+ * Clears all cached system-wide resource data.
+ */
+ public void flushDataCache() {
+ synchronized (resourceCache) {
+ resourceCache.removeAllObjects();
+ }
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.removeAllObjects();
+ }
+ synchronized (stringTableCache) {
+ stringTableCache.removeAllObjects();
+ }
+ }
+
+ /**
+ * Returns the file-system path for the specified resource. Deprecated and not
+ * implemented.
+ *
+ * @deprecated Use inputStreamForResourceNamed instead.
+ */
+ public String pathForResourceNamed(String aResourceName, String aFrameworkName, NSArray aLanguagesList) {
+ throw new RuntimeException("ResourceManager.pathForResourceNamed: deprecated");
+ }
+
+ /**
+ * Removes the data from the dynamic data cache for the specified session. If
+ * aSession is null, the data is removed from the application-wide data cache.
+ */
+ public void removeDataForKey(String aKey, WOSession aSession) {
+ if (aSession != null) {
+ if (aSession.dynamicDataCache != null) {
+ aSession.dynamicDataCache.removeObjectForKey(aKey);
+ }
+ } else {
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.removeObjectForKey(aKey);
+ }
+ }
+ }
+
+ /**
+ * Sets the data in the dynamic data cache for the specified session. If
+ * aSession is null, the data is placed in the application-wide data cache. If
+ * the key is a system-generated key, the data will be removed by calling
+ * removeData() the next time it is requested.
+ */
+ public void setData(NSData someData, String key, String type, WOSession aSession) {
+ if (aSession != null) {
+ if (aSession.dynamicDataCache != null) {
+ aSession.dynamicDataCache.setObjectForKey(new TypedData(type, someData), key);
+ }
+ } else {
+ synchronized (dynamicDataCache) {
+ dynamicDataCache.setObjectForKey(new TypedData(type, someData), key);
+ }
+ }
+ }
+
+ /**
+ * Returns a localized string from a property list for a given key. If the key
+ * doesn't exist, aDefaultValue is returned.
+ */
+ public String stringForKey(String aKey, String aFileName, String aDefaultValue, String aFrameworkName,
+ NSArray aLanguagesList) {
+
+ String mash = aFileName + aFrameworkName;
+ if (aLanguagesList != null) {
+ mash = mash + aLanguagesList.componentsJoinedByString(":");
+ }
+
+ Object table = stringTableCache.objectForKey(mash);
+ if (table == null) {
+ try {
+ InputStream input = (InputStream) inputStreamForResourceNamed(aFileName, aFrameworkName,
+ aLanguagesList);
+ if (input != null) {
+ Reader reader = new BufferedReader(new InputStreamReader(input));
+ table = PropertyListParser.propertyListFromReader(reader);
+ synchronized (stringTableCache) {
+ stringTableCache.setObjectForKey(table, mash);
+ }
+ }
+ } catch (IOException ioe) {
+ System.err.println("WOResourceManager: error reading: " + aFileName);
+ ioe.printStackTrace();
+ } catch (Throwable t) {
+ // could not parse
+ System.err.println("WOResourceManager: could not parse: " + aFileName);
+ System.err.println(t);
+ }
+ }
+
+ Object result = null;
+ if (table != null) {
+ result = NSKeyValueCoding.DefaultImplementation.valueForKey(table, aKey);
+ }
+ if (result == null) {
+ result = aDefaultValue;
+ } else {
+ result = result.toString();
+ }
+
+ return (String) result;
+ }
+
+ /**
+ * Returns a url that invokes the resource manager for the specified resource.
+ */
+ public String urlForResourceNamed(String aResourceName, String aFrameworkName, NSArray aLanguagesList,
+ WORequest aRequest) {
+ StringBuffer buffer = new StringBuffer();
+ if (aFrameworkName == null) {
+ aFrameworkName = "application";
+ }
+ buffer.append(aRequest.applicationName());
+ buffer.append('/');
+ buffer.append(WOApplication.resourceRequestHandlerKey());
+ if (!aFrameworkName.startsWith("/")) {
+ buffer.append('/');
+ }
+ buffer.append(aFrameworkName);
+ buffer.append('/');
+ buffer.append(aResourceName);
+ return buffer.toString();
+ }
+
+ /**
+ * Returns an input for the raw resource. Data returned by this method will not
+ * be put in the resource manager's global cache.
+ */
+ public InputStream inputStreamForResourceNamed(String aResourceName, String aFrameworkName,
+ NSArray aLanguagesList) {
+ if (aResourceName == null)
+ return null;
+ InputStream result = null;
+
+ StringBuffer path = new StringBuffer();
+ path.append('/');
+ if (aFrameworkName != null) {
+ path.append(aFrameworkName).append('/');
+ }
+
+ int i = aResourceName.lastIndexOf(".");
+ if (i != -1)
+ path.append(aResourceName.substring(0, i));
+ else
+ path.append(aResourceName);
+
+ String location = path.toString();
+ if (aLanguagesList != null) {
+ String language;
+ Locale locale;
+ HashSet tried = new HashSet(5);
+ Enumeration e = aLanguagesList.objectEnumerator();
+ while (e.hasMoreElements() && result == null) {
+ language = e.nextElement().toString();
+
+ // look for java-style localization
+ if (i != -1) {
+ result = getStream(location + '_' + language + aResourceName.substring(i));
+ } else // no dot extension
+ {
+ result = getStream(location + '_' + language);
+ }
+
+ // look for wo-style localization
+ if (result == null) {
+ locale = (Locale) localeCache.get(language);
+ if (locale == null) {
+ if (language.length() == 5) {
+ locale = new Locale(language.substring(0, 2), language.substring(3, 5));
+ } else {
+ locale = new Locale(language, "");
+ }
+ synchronized (localeCache) {
+ localeCache.put(language, locale);
+ }
+ }
+
+ language = '/' + locale.getDisplayLanguage(californiaLocale) + ".lproj";
+ if (!tried.contains(language)) {
+ if (aFrameworkName != null) {
+ int j = aFrameworkName.length() + 1;
+ path.insert(j, language);
+ result = getStream(path.toString() + aResourceName.substring(i));
+ path.delete(j, j + language.length());
+ } else {
+ result = getStream(language + path.toString() + aResourceName.substring(i));
+ }
+ tried.add(language);
+ }
+ }
+ }
+ }
+
+ // look for file in package
+ if (result == null) {
+ if (i != -1) {
+ result = getStream(path.append(aResourceName.substring(i)).toString());
+ } else // no dot extension
+ {
+ result = getStream(location);
+ }
+ }
+
+ return result;
+ }
+
+ private static final InputStream getStream(String path) { // System.out.println( "getStream: " + path );
+ InputStream input = WOApplication.application().getClass().getResourceAsStream(path);
+ if (input == null) {
+ // in case the local class loader doesn't delegate to its parent
+ input = ClassLoader.getSystemResourceAsStream(path);
+ }
+ return input;
+ }
+
+ private static final class TypedData {
+ String type;
+ NSData data;
+
+ public TypedData(String aType, NSData aData) {
+ type = aType;
+ data = aData;
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.5 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.5 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.4 2003/02/28 22:58:57 mpowers
- * Added support for wo-style localization (*.lproj).
+ * Revision 1.4 2003/02/28 22:58:57 mpowers Added support for wo-style
+ * localization (*.lproj).
*
- * Revision 1.3 2003/02/21 16:40:24 mpowers
- * Now reading port and smtp host from system properties.
- * Implemented WOApplication.main.
+ * Revision 1.3 2003/02/21 16:40:24 mpowers Now reading port and smtp host from
+ * system properties. Implemented WOApplication.main.
*
- * Revision 1.2 2003/01/28 19:33:52 mpowers
- * Implemented the rest of WOResourceManager.
- * Implemented support for java-style i18n.
- * Components now use the resource manager to load templates.
+ * Revision 1.2 2003/01/28 19:33:52 mpowers Implemented the rest of
+ * WOResourceManager. Implemented support for java-style i18n. Components now
+ * use the resource manager to load templates.
*
- * Revision 1.1 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.1 2003/01/27 15:08:00 mpowers Implemented WOResourceManager, using
+ * java resources for now.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
index 4d25128..f611149 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceRequestHandler.java
@@ -24,99 +24,81 @@ import net.wotonomy.foundation.NSData;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* An implementation of WORequestHandler that
-* retrieves resources from the deployed application.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResourceRequestHandler
- extends WORequestHandler
-{
- private NSMutableDictionary resourceCache;
- private WOResourceManager resourceManager;
-
- public WOResourceRequestHandler()
- {
- //TODO: should probably have some kind of limit on the cache
- resourceCache = new NSMutableDictionary();
- resourceManager = WOApplication.application().resourceManager();
- }
-
- public WOResponse handleRequest( WORequest aRequest )
- {
- WOResponse response = new WOResponse();
-
- StringBuffer buf = new StringBuffer();
-
- //TODO: this is just to get things working...
- String framework = null;
- Enumeration e = aRequest.requestHandlerPathArray().objectEnumerator();
- if ( e.hasMoreElements() )
- {
- framework = e.nextElement().toString();
- if ( framework.equals( "application" ) )
- {
- buf.append('/').append( framework );
- framework = null;
- }
- }
- if ( e.hasMoreElements() )
- {
- buf.append( e.nextElement() );
- }
- while ( e.hasMoreElements() )
- {
- buf.append('/').append( e.nextElement() );
- }
-
- String resource;
- if ( buf.length() > 0 )
- {
- resource = buf.toString();
- byte[] data = resourceManager.bytesForResourceNamed(
- resource, framework, aRequest.browserLanguages() );
- if ( data != null )
- {
- response.setHeader(
- resourceManager.contentTypeForResourceNamed( resource ),
- "Content-Type" );
- response.setContent( new NSData( data ) );
- return response;
- }
- }
- response.setStatus( 404 ); // not found
- return response;
- }
+ * An implementation of WORequestHandler that retrieves resources from the
+ * deployed application.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResourceRequestHandler extends WORequestHandler {
+ private NSMutableDictionary resourceCache;
+ private WOResourceManager resourceManager;
+
+ public WOResourceRequestHandler() {
+ // TODO: should probably have some kind of limit on the cache
+ resourceCache = new NSMutableDictionary();
+ resourceManager = WOApplication.application().resourceManager();
+ }
+
+ public WOResponse handleRequest(WORequest aRequest) {
+ WOResponse response = new WOResponse();
+
+ StringBuffer buf = new StringBuffer();
+
+ // TODO: this is just to get things working...
+ String framework = null;
+ Enumeration e = aRequest.requestHandlerPathArray().objectEnumerator();
+ if (e.hasMoreElements()) {
+ framework = e.nextElement().toString();
+ if (framework.equals("application")) {
+ buf.append('/').append(framework);
+ framework = null;
+ }
+ }
+ if (e.hasMoreElements()) {
+ buf.append(e.nextElement());
+ }
+ while (e.hasMoreElements()) {
+ buf.append('/').append(e.nextElement());
+ }
+
+ String resource;
+ if (buf.length() > 0) {
+ resource = buf.toString();
+ byte[] data = resourceManager.bytesForResourceNamed(resource, framework, aRequest.browserLanguages());
+ if (data != null) {
+ response.setHeader(resourceManager.contentTypeForResourceNamed(resource), "Content-Type");
+ response.setContent(new NSData(data));
+ return response;
+ }
+ }
+ response.setStatus(404); // not found
+ return response;
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.6 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.5 2003/01/27 15:08:00 mpowers
- * Implemented WOResourceManager, using java resources for now.
+ * Revision 1.5 2003/01/27 15:08:00 mpowers Implemented WOResourceManager, using
+ * java resources for now.
*
- * Revision 1.4 2003/01/22 23:01:36 mpowers
- * Better handling for request handler path.
- * Better support for resources with absolute path.
+ * Revision 1.4 2003/01/22 23:01:36 mpowers Better handling for request handler
+ * path. Better support for resources with absolute path.
*
- * Revision 1.3 2003/01/20 16:18:22 mpowers
- * Fixed class loading issues with resource retrieval.
+ * Revision 1.3 2003/01/20 16:18:22 mpowers Fixed class loading issues with
+ * resource retrieval.
*
- * Revision 1.2 2003/01/17 20:58:20 mpowers
- * Fixed up WOHyperlink.
+ * Revision 1.2 2003/01/17 20:58:20 mpowers Fixed up WOHyperlink.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
index 862c6dc..14c1c87 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResourceURL.java
@@ -6,26 +6,26 @@ import net.wotonomy.foundation.NSDictionary;
public class WOResourceURL extends WODynamicElement {
- public WOResourceURL() {
- super();
- }
+ public WOResourceURL() {
+ super();
+ }
- public WOResourceURL(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
+ public WOResourceURL(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- String fname = stringForProperty("filename", c.component());
- if (fname != null) {
- String fwk = stringForProperty("framework", c.component());
- return;
- }
- NSData data = (NSData)valueForProperty("data", c.component());
- if (data != null) {
- String mime = stringForProperty("mimeType", c.component());
- String key = stringForProperty("key", c.component());
- return;
- }
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ String fname = stringForProperty("filename", c.component());
+ if (fname != null) {
+ String fwk = stringForProperty("framework", c.component());
+ return;
+ }
+ NSData data = (NSData) valueForProperty("data", c.component());
+ if (data != null) {
+ String mime = stringForProperty("mimeType", c.component());
+ String key = stringForProperty("key", c.component());
+ return;
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
index d9fbade..6362a03 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOResponse.java
@@ -25,160 +25,133 @@ import java.util.TimeZone;
import net.wotonomy.foundation.NSArray;
/**
-* A pure java implementation of WOResponse.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOResponse extends WOMessage
- implements WOActionResults
-{
+ * A pure java implementation of WOResponse.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOResponse extends WOMessage implements WOActionResults {
protected static String defaultEncoding;
- private static SimpleDateFormat htmlDateFormat;
- static
- {
- defaultEncoding = "ISO8859_1";
- htmlDateFormat = new SimpleDateFormat(
- "EEE, dd MMM yyyy HH:mm:ss z" );
- htmlDateFormat.setTimeZone(
- TimeZone.getTimeZone( "GMT" ) );
- }
+ private static SimpleDateFormat htmlDateFormat;
+ static {
+ defaultEncoding = "ISO8859_1";
+ htmlDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
+ htmlDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
private int status;
/**
- * Parameterless constructor which should not be called.
- */
- public WOResponse ()
- {
+ * Parameterless constructor which should not be called.
+ */
+ public WOResponse() {
status = -1; // -1 indicates not yet set
- }
+ }
+
+ /**
+ * Sets the status code of the response. You should use the constants defined in
+ * HttpServletResponse.
+ */
+ public void setStatus(int code) {
+ status = code;
+ }
/**
- * Sets the status code of the response.
- * You should use the constants defined in HttpServletResponse.
- */
- public void setStatus (int code)
- {
- status = code;
- }
+ * Gets the current status code for the response.
+ */
+ public int status() {
+ return status;
+ }
/**
- * Gets the current status code for the response.
- */
- public int status ()
- {
- return status;
- }
+ * Sets a header in the response to disable client caching. (Whether this works
+ * depends on the client implementation.)
+ */
+ public void disableClientCaching() {
+ String dateString = htmlDateFormat.format(new Date());
+ setHeader(dateString, "Date");
+ setHeader(dateString, "Expires");
+ setHeader("no-cache", "Pragma");
+ setHeaders(new NSArray(new Object[] { "private", "no-cache", "max-age = 0" }), "Cache-Control");
+ // System.out.println( "disableClientCaching: " + dateString );
+ }
/**
- * Sets a header in the response to disable client caching.
- * (Whether this works depends on the client implementation.)
- */
- public void disableClientCaching ()
- {
- String dateString = htmlDateFormat.format( new Date() );
- setHeader( dateString, "Date" );
- setHeader( dateString, "Expires" );
- setHeader( "no-cache", "Pragma" );
- setHeaders( new NSArray( new Object[] {
- "private", "no-cache", "max-age = 0" } ), "Cache-Control" );
- //System.out.println( "disableClientCaching: " + dateString );
- }
-
- /**
- * Returns this object. (Implements the WOActionResults interface.)
- */
- public WOResponse generateResponse()
- {
- return this;
- }
+ * Returns this object. (Implements the WOActionResults interface.)
+ */
+ public WOResponse generateResponse() {
+ return this;
+ }
/**
- * Generates the response using the specified servlet response,
- * but does not flush the buffer. The caller is responsible
- * for sending the response to the client. <br><br>
- * Note that this method is currently responsible for setting
- * the content type to "text/html". As far as I can tell, WORequests
- * have no way to set the content type and therefore must always
- * be of type "text/html".
- */
- void generateServletResponse
- (javax.servlet.http.HttpServletResponse response)
- {
- if ( WOApplication.application().isPageRefreshOnBacktrackEnabled() )
- {
- disableClientCaching();
- }
-
- String key;
- java.util.Enumeration e, f;
-
- // set content type: might be overwritten by headers below
- response.setContentType( "text/html" );
-
- // set status
- if ( status != -1 )
- {
- response.setStatus( status );
+ * Generates the response using the specified servlet response, but does not
+ * flush the buffer. The caller is responsible for sending the response to the
+ * client. <br>
+ * <br>
+ * Note that this method is currently responsible for setting the content type
+ * to "text/html". As far as I can tell, WORequests have no way to set the
+ * content type and therefore must always be of type "text/html".
+ */
+ void generateServletResponse(javax.servlet.http.HttpServletResponse response) {
+ if (WOApplication.application().isPageRefreshOnBacktrackEnabled()) {
+ disableClientCaching();
+ }
+
+ String key;
+ java.util.Enumeration e, f;
+
+ // set content type: might be overwritten by headers below
+ response.setContentType("text/html");
+
+ // set status
+ if (status != -1) {
+ response.setStatus(status);
}
- // set headers
- f = _headers.allKeys().objectEnumerator();
- while ( f.hasMoreElements() )
- {
- key = f.nextElement().toString();
- e = ((NSArray)_headers.objectForKey( key )).objectEnumerator();
- if ( e.hasMoreElements() )
- {
- // overwrite existing header
- response.setHeader( key, e.nextElement().toString() );
- }
- while ( e.hasMoreElements() )
- {
- response.addHeader( key, e.nextElement().toString() );
- }
+ // set headers
+ f = _headers.allKeys().objectEnumerator();
+ while (f.hasMoreElements()) {
+ key = f.nextElement().toString();
+ e = ((NSArray) _headers.objectForKey(key)).objectEnumerator();
+ if (e.hasMoreElements()) {
+ // overwrite existing header
+ response.setHeader(key, e.nextElement().toString());
+ }
+ while (e.hasMoreElements()) {
+ response.addHeader(key, e.nextElement().toString());
+ }
}
- // set cookies
- e = _cookies.allValues().objectEnumerator();
- while ( e.hasMoreElements() )
- {
- response.addCookie( (WOCookie) e.nextElement() );
- }
-
- try
- {
- // write content
- response.getOutputStream().write(_contentData.bytes() );
- if ( status > 299 )
- {
- response.sendError( status );
- }
- }
- catch ( Exception exc )
- {
- throw new RuntimeException(
- "Error writing response: " + exc );
+ // set cookies
+ e = _cookies.allValues().objectEnumerator();
+ while (e.hasMoreElements()) {
+ response.addCookie((WOCookie) e.nextElement());
}
- }
+ try {
+ // write content
+ response.getOutputStream().write(_contentData.bytes());
+ if (status > 299) {
+ response.sendError(status);
+ }
+ } catch (Exception exc) {
+ throw new RuntimeException("Error writing response: " + exc);
+ }
+ }
/**
- * Returns the current default encoding seting.
- */
- public static String defaultEncoding ()
- {
- return defaultEncoding;
- }
+ * Returns the current default encoding seting.
+ */
+ public static String defaultEncoding() {
+ return defaultEncoding;
+ }
/**
- * Sets the default encoding setting.
- */
- public static void setDefaultEncoding (String encoding)
- {
- defaultEncoding = encoding;
- }
+ * Sets the default encoding setting.
+ */
+ public static void setDefaultEncoding(String encoding) {
+ defaultEncoding = encoding;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
index 0f2898c..647346c 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOServletSessionStore.java
@@ -28,161 +28,135 @@ import java.io.ObjectStreamClass;
import javax.servlet.http.HttpSession;
-
/**
-* An implementation of WOSessionStore that stores WOSessions
-* inside of HttpSessions, to take advantage of the servlet
-* containers built-in distribution capabilities.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOServletSessionStore extends WOSessionStore
-{
- private static final String ServletSessionKey = "WOServletSessionStoreKey";
-
- /**
- * This implementation currently does nothing and returns null, as we rely on the
- * servlet container to dispose of the HttpSession which contains our WOSession.
- */
- public WOSession removeSessionWithID(String sessionID)
- {
- return null;
- }
-
- /**
- * Returns the WOSession for the specified ID from the store.
- * The sessionID parameter is ignored, and the session is removed from
- * the store until saveSessionForContext is called.
- */
- public WOSession restoreSessionWithID(String sessionID, WORequest aRequest)
- {
- WOSession result = null;
- HttpSession servletSession = aRequest.servletRequest().getSession();
- if ( servletSession != null )
- {
- try
- {
- result = (WOSession) servletSession.getAttribute( ServletSessionKey );
- if ( result != null )
- {
- // if the servlet's class loader has changed, we need to reload
- if ( result.getClass().getClassLoader() !=
- WOApplication.application().getClass().getClassLoader() )
- {
- throw new ClassCastException( result.getClass().toString() );
- }
- }
- }
- catch ( ClassCastException exc )
- {
- // we're having an issue with the container's class loader:
- // try serializing and deserializing to see if it is reloaded correctly
- try
- {
-
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- ObjectOutputStream output = new ObjectOutputStream( bytes );
- Object o = servletSession.getAttribute( ServletSessionKey );
- output.writeObject( o );
- output.flush();
- output.close();
-
- System.out.println(
- "WOServletSessionStore: reloaded session with size: " +
- bytes.toByteArray().length );
-
- ObjectInputStream input = new CustomObjectInputStream(
- new ByteArrayInputStream( bytes.toByteArray() ),
- WOApplication.application().getClass().getClassLoader() );
-
- o = input.readObject();
- input.close();
-
- // try it again
- result = (WOSession) o;
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- // give up: remove the attribute and allow a new session
- servletSession.removeAttribute( ServletSessionKey );
- }
- }
-
- if ( result != null )
- {
- servletSession.removeAttribute( ServletSessionKey );
- }
- }
- //System.out.println( "restoreSessionWithID: " + sessionID + " : " + result );
- return result;
- }
-
- /**
- * Places the context's session into the store.
- */
- public void saveSessionForContext(WOContext context)
- {
- //System.out.println( "saveSessionForContext: " + context + " : " + context.session() );
- context.request().servletRequest().getSession( true ).setAttribute(
- ServletSessionKey, context.session() );
- }
-
- /**
- * Needed to specify a class loader which may be different that the
- * one used to load the ObjectInputStream class.
- */
- private static class CustomObjectInputStream extends ObjectInputStream
- {
- ClassLoader loader;
-
- public CustomObjectInputStream(
- InputStream anInputStream, ClassLoader aClassLoader )
- throws java.io.IOException, java.io.StreamCorruptedException
- {
- super( anInputStream );
- loader = aClassLoader;
- }
-
- protected Class resolveClass(ObjectStreamClass v)
- throws IOException, ClassNotFoundException
- {
- return loader.loadClass( v.getName() );
- }
- }
+ * An implementation of WOSessionStore that stores WOSessions inside of
+ * HttpSessions, to take advantage of the servlet containers built-in
+ * distribution capabilities.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOServletSessionStore extends WOSessionStore {
+ private static final String ServletSessionKey = "WOServletSessionStoreKey";
+
+ /**
+ * This implementation currently does nothing and returns null, as we rely on
+ * the servlet container to dispose of the HttpSession which contains our
+ * WOSession.
+ */
+ public WOSession removeSessionWithID(String sessionID) {
+ return null;
+ }
+
+ /**
+ * Returns the WOSession for the specified ID from the store. The sessionID
+ * parameter is ignored, and the session is removed from the store until
+ * saveSessionForContext is called.
+ */
+ public WOSession restoreSessionWithID(String sessionID, WORequest aRequest) {
+ WOSession result = null;
+ HttpSession servletSession = aRequest.servletRequest().getSession();
+ if (servletSession != null) {
+ try {
+ result = (WOSession) servletSession.getAttribute(ServletSessionKey);
+ if (result != null) {
+ // if the servlet's class loader has changed, we need to reload
+ if (result.getClass().getClassLoader() != WOApplication.application().getClass().getClassLoader()) {
+ throw new ClassCastException(result.getClass().toString());
+ }
+ }
+ } catch (ClassCastException exc) {
+ // we're having an issue with the container's class loader:
+ // try serializing and deserializing to see if it is reloaded correctly
+ try {
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ ObjectOutputStream output = new ObjectOutputStream(bytes);
+ Object o = servletSession.getAttribute(ServletSessionKey);
+ output.writeObject(o);
+ output.flush();
+ output.close();
+
+ System.out.println(
+ "WOServletSessionStore: reloaded session with size: " + bytes.toByteArray().length);
+
+ ObjectInputStream input = new CustomObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()),
+ WOApplication.application().getClass().getClassLoader());
+
+ o = input.readObject();
+ input.close();
+
+ // try it again
+ result = (WOSession) o;
+ } catch (Exception e) {
+ e.printStackTrace();
+ // give up: remove the attribute and allow a new session
+ servletSession.removeAttribute(ServletSessionKey);
+ }
+ }
+
+ if (result != null) {
+ servletSession.removeAttribute(ServletSessionKey);
+ }
+ }
+ // System.out.println( "restoreSessionWithID: " + sessionID + " : " + result );
+ return result;
+ }
+
+ /**
+ * Places the context's session into the store.
+ */
+ public void saveSessionForContext(WOContext context) {
+ // System.out.println( "saveSessionForContext: " + context + " : " +
+ // context.session() );
+ context.request().servletRequest().getSession(true).setAttribute(ServletSessionKey, context.session());
+ }
+
+ /**
+ * Needed to specify a class loader which may be different that the one used to
+ * load the ObjectInputStream class.
+ */
+ private static class CustomObjectInputStream extends ObjectInputStream {
+ ClassLoader loader;
+
+ public CustomObjectInputStream(InputStream anInputStream, ClassLoader aClassLoader)
+ throws java.io.IOException, java.io.StreamCorruptedException {
+ super(anInputStream);
+ loader = aClassLoader;
+ }
+
+ protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException {
+ return loader.loadClass(v.getName());
+ }
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2003/01/22 23:00:32 mpowers
- * Now keeping the most recent page around.
+ * Revision 1.7 2003/01/22 23:00:32 mpowers Now keeping the most recent page
+ * around.
*
- * Revision 1.6 2003/01/21 17:53:16 mpowers
- * Now handling reloading when wotonomy is on the system class path.
+ * Revision 1.6 2003/01/21 17:53:16 mpowers Now handling reloading when wotonomy
+ * is on the system class path.
*
- * Revision 1.5 2003/01/15 19:50:49 mpowers
- * Fixed issues with WOSession and Serializable.
- * Can now persist sessions between classloaders (hot swap of class impls).
+ * Revision 1.5 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
+ * Serializable. Can now persist sessions between classloaders (hot swap of
+ * class impls).
*
- * Revision 1.3 2003/01/14 16:05:19 mpowers
- * Removed extraneous printlns.
+ * Revision 1.3 2003/01/14 16:05:19 mpowers Removed extraneous printlns.
*
- * Revision 1.2 2003/01/13 22:25:07 mpowers
- * Request-response cycle is working with session and page persistence.
+ * Revision 1.2 2003/01/13 22:25:07 mpowers Request-response cycle is working
+ * with session and page persistence.
*
- * Revision 1.1 2003/01/07 20:48:24 mpowers
- * Implemented WOSessionStore and WOServletSessionStore.
+ * Revision 1.1 2003/01/07 20:48:24 mpowers Implemented WOSessionStore and
+ * WOServletSessionStore.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
index e187567..82df58b 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSession.java
@@ -36,493 +36,433 @@ import net.wotonomy.foundation.NSMutableArray;
import net.wotonomy.foundation.NSMutableDictionary;
/**
-* A pure java implementation of WOSession.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOSession implements Serializable, NSKeyValueCodingAdditions
-{
- //NOTE: need to set this when deserialized and on creation
- transient private HttpSession session;
-
- // the current context
- transient private WOContext context;
-
- // the last requested page: an optimization
- transient private WOComponent currentPage;
- // the last requested page's context id
- transient private String currentContextID;
-
- //FIXME: transient until ec's implement serializable
- private transient EOEditingContext defaultEditingContext;
-
- private NSMutableDictionary state;
- private NSMutableDictionary pages;
- private NSMutableDictionary permanentPages;
- private NSMutableArray stateStack;
- private NSMutableArray pageStack;
- private NSMutableArray permanentPageStack;
- private boolean terminating;
-
- // used by WOResourceManager to cache dynamic resources
- transient NSMutableDictionary dynamicDataCache;
-
- public static final String WOSessionDidTimeOutNotification
- = "WOSessionDidTimeOutNotification";
- public static final String WOSessionDidRestoreNotification
- = "WOSessionDidRestoreNotification";
- public static final String WOSessionDidCreateNotification
- = "WOSessionDidCreateNotification";
-
- /**
- * Default constructor. This is called implicitly by
- * subclasses in all cases.
- */
- public WOSession ()
- {
- session = null;
- state = new NSMutableDictionary();
- pages = new NSMutableDictionary();
- permanentPages = new NSMutableDictionary();
- stateStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- pageStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- permanentPageStack = NSMutableArray.mutableArrayBackedByList( new LinkedList() );
- defaultEditingContext = null;
- terminating = false;
- }
-
- /**
- * Package method to initialize the backing session.
- */
- void setServletSession( HttpSession aSession )
- {
- session = aSession;
- }
-
- /**
- * Package method to set the current context.
- */
- void setContext( WOContext aContext )
- {
- context = aContext;
- }
-
- /**
- * Returns the id of the current session. If no session
- * currently exists, return null.
- */
- public String sessionID ()
- {
- if ( session != null )
- {
- return session.getId();
- }
- return null;
- }
-
- /**
- * Sets whether distribution is currently enabled.
- * This method is not implemented by this implementation
- * as the servlet container manages distribution.
- */
- public void setDistributionEnabled (boolean enabled)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether the session is part of a distributed application.
- * This implementation always returns false.
- */
- public boolean isDistributionEnabled ()
- {
- return false;
- }
-
- /**
- * Sets whether session ids should be stored in cookies.
- * This method is not implemented in this implementation
- * as the servlet container manages sessions with cookies.
- */
- public void setStoresIDsInCookies (boolean cookies)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether session ids are currently stored in cookies.
- * This implementation always returns true.
- */
- public boolean storesIDsInCookies ()
- {
- return true;
- }
-
- /**
- * Returns the current expiration date for cookies that store session ids.
- */
- public NSDate expirationDateForIDCookies ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether session ids should be stored in urls.
- * This method is not implemented in this implementation
- * as the servlet container manages sessions with cookies.
- */
- public void setStoresIDsInURLs (boolean urls)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether session ids are currently stored in urls.
- * This implementation always returns false.
- */
- public boolean storesIDsInURLs ()
- {
- return false;
- }
-
- /**
- * Returns the current domain for cookies containing session ids.
- */
- public String domainForIDCookies ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Terminates this session after the completion of the current response.
- */
- public void terminate ()
- {
- terminating = true;
- session.invalidate();
- }
-
- /**
- * Returns whether the current session will terminate at the completion
- * of the current response.
- */
- public boolean isTerminating ()
- {
- return terminating;
- }
-
- /**
- * Sets the number of seconds after the last request before
- * the session should be terminated.
- */
- public void setTimeOut (double timeout)
- {
- session.setMaxInactiveInterval( (int) timeout );
- }
-
- /**
- * Returns the number of seconds after the last request before
- * the session should be terminated.
- */
- public double timeOut ()
- {
- return session.getMaxInactiveInterval();
- }
-
- /**
- * Sets the languages for which this session has been localized,
- * in order of preference. The application will be responsible for
- * localizing the content based on the languages found in this array.
- */
- public void setLanguages (NSArray anArray)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns the languages for which this session has been localized,
- * in order of preference. The application will be responsible for
- * localizing the content based on the languages found in this array.
- */
- public NSArray languages ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Stores the specified key-value pair in the session.
- */
- public void setObjectForKey (Object anObject, String aKey)
- {
- state.setObjectForKey( anObject, aKey );
- }
-
- /**
- * Returns the session value associated with the specified key.
- */
- public Object objectForKey (String aKey)
- {
- return state.objectForKey( aKey );
- }
-
- /**
- * Removes the session value associated with the specified key.
- */
- public void removeObjectForKey (String aKey)
- {
- state.removeObjectForKey( aKey );
- }
-
- /**
- * Returns the context for the current request.
- */
- public WOContext context ()
- {
- return context;
- }
-
- /**
- * Invoked at the beginning of the request-response cycle.
- * Override to perform any kind of initialization at the
- * start of a request. This implementation does nothing.
- */
- public void awake ()
- {
-
- }
-
- /**
- * Invoked by the Application to extract user-assigned balues
- * and assign them to attributes. This implementation calls
- * takeValuesFromRequest on the top-level component.
- */
- public void takeValuesFromRequest (WORequest aRequest, WOContext aContext)
- {
- context().component().takeValuesFromRequest( aRequest, aContext );
- }
-
- /**
- * Invoked by the Application to determine which component is the
- * intended recipient of the user's action. This implementation calls
- * invokeAction on the top-level component.
- */
- public WOActionResults invokeAction (WORequest aRequest, WOContext aContext)
- {
- return context().component().invokeAction( aRequest, aContext );
- }
-
- /**
- * Invoked by the Application to generate the content of the response.
- * This implementation calls appendToResponse on the top-level component.
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- context().component().appendToResponse( aResponse, aContext );
- }
-
- /**
- * Invoked at the end of the request-response cycle.
- * Override to perform any kind of clean-up at the
- * end of a request. This implementation does nothing.
- */
- public void sleep ()
- {
-
- }
-
- /**
- * Returns a list of pages accessed by this session in order
- * of their access and named by calling WOComponent.descriptionForResponse.
- */
- public NSArray statistics ()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Puts this page in the session's page cache using the current
- * context id as the key.
- */
- public void savePage (WOComponent aComponent)
- {
- currentPage = aComponent;
- currentContextID = context.contextID();
-
- if ( pages.objectForKey( currentContextID ) == null )
- {
- byte[] data = KeyValueCodingUtilities.freeze(
- aComponent, defaultEditingContext(), aComponent, true );
- System.out.println( "WOSession.savePage: " + currentContextID + " : " + data.length );
-
- pages.setObjectForKey( data, currentContextID );
- pageStack.addObject( currentContextID );
- if ( pageStack.count() > context().application().pageCacheSize() )
- {
- String id = pageStack.remove( 0 ).toString(); // removeObjectAtIndex
- System.out.println( "WOSession.savePage: removing from cache: " + id );
- pages.removeObjectForKey( id );
- }
- }
- //System.out.println( "savePage: " + this + " : " + id + " : " + pages );
- }
-
- /**
- * Returns the page in the session's page cache corresponding to
- * the specified context id. Any special permanent caches are
- * searched before the standard page cache.
- */
- public WOComponent restorePageForContextID (String anID)
- {
- if ( anID == null ) return null;
- if ( anID.equals( currentContextID ) ) return currentPage;
-
- WOComponent result = null;
- byte[] data = (byte[]) permanentPages.objectForKey( anID );
- if ( data == null ) data = (byte[]) pages.objectForKey( anID );
- if ( data != null )
- {
- System.out.println( "WOSession.restorePageForContextID: " + anID + " : " + data.length );
- result = (WOComponent) KeyValueCodingUtilities.thaw(
- data, defaultEditingContext(),
- WOApplication.application().getClass().getClassLoader(), true );
- }
- //System.out.println( "restorePageForContextID: " + this + " : " + anID + " : " + result + " : " + pages );
- return result;
- }
-
- /**
- * Puts this page in the special cache is will not get automatically
- * flushed like the session page cache. Use this if the page
- * is likely to be around for a while, specifically pages within
- * frames.
- */
- public void savePageInPermanentCache (WOComponent aComponent)
- {
- currentPage = aComponent;
- currentContextID = context.contextID();
-
- if ( permanentPages.objectForKey( currentContextID ) == null )
- {
- byte[] data = KeyValueCodingUtilities.freeze(
- aComponent, defaultEditingContext(), aComponent, true );
- //System.out.println( "WOSession.savePageInPermanentCache: "
- // + currentContextID + " : " + data.length );
-
- permanentPages.setObjectForKey( data, currentContextID );
- permanentPageStack.addObject( currentContextID );
- if ( permanentPageStack.count() > context().application().pageCacheSize() )
- {
- String id = permanentPageStack.remove( 0 ).toString(); // removeObjectAtIndex
- permanentPages.removeObjectForKey( id );
- }
- }
- }
-
- /**
- * Writes a message to the standard error stream.
- */
- public static void logString (String aString)
- {
- System.err.println( aString );
- }
-
- /**
- * Writes a message to the standard error stream
- * if debugging is activated.
- */
- public static void debugString (String aString)
- {
- // TODO: Check to see if debugging is enabled.
- System.err.println( aString );
- }
-
- /**
- * Returns the default editing context used by this session.
- * Defaults to null.
- */
- public EOEditingContext defaultEditingContext ()
- {
- return defaultEditingContext;
- }
-
- /**
- * Sets the default editing context used by this session.
- */
- public void setDefaultEditingContext (EOEditingContext aContext)
- {
- defaultEditingContext = aContext;
- }
-
- // interface NSKeyValueCodingAdditions
-
- public Object valueForKeyPath (String aPath)
- {
- // currently key value coding support also handles keypaths
- return valueForKey( aPath );
- }
-
- public void takeValueForKeyPath (Object aValue, String aPath)
- {
- // currently key value coding support also handles keypaths
- takeValueForKey( aValue, aPath );
- }
-
- public NSDictionary valuesForKeys (List aKeyList)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public void takeValuesFromDictionary (Map aValueMap)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- public Object valueForKey (String aKey)
- { // System.out.println( "valueForKey: " + aKey + "->" + this );
- Object result = objectForKey( aKey );
- if ( result == null )
- result = NSKeyValueCodingSupport.valueForKey( this, aKey );
- return result;
- }
-
- public void takeValueForKey (Object aValue, String aKey)
- { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this );
- setObjectForKey( aValue, aKey );
- }
-
- public Object storedValueForKey (String aKey)
- {
- Object result = objectForKey( aKey );
- if ( result == null )
- NSKeyValueCodingSupport.storedValueForKey( this, aKey );
- return result;
- }
-
- public void takeStoredValueForKey (Object aValue, String aKey)
- {
- setObjectForKey( aValue, aKey );
- }
-
- public Object handleQueryWithUnboundKey (String aKey)
- {
- return NSKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey );
- }
-
- public void handleTakeValueForUnboundKey (Object aValue, String aKey)
- {
- NSKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey );
- }
-
- public void unableToSetNullForKey (String aKey)
- {
- NSKeyValueCodingSupport.unableToSetNullForKey( this, aKey );
- }
-
- public Object validateTakeValueForKeyPath (Object aValue, String aKey)
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
+ * A pure java implementation of WOSession.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOSession implements Serializable, NSKeyValueCodingAdditions {
+ // NOTE: need to set this when deserialized and on creation
+ transient private HttpSession session;
+
+ // the current context
+ transient private WOContext context;
+
+ // the last requested page: an optimization
+ transient private WOComponent currentPage;
+ // the last requested page's context id
+ transient private String currentContextID;
+
+ // FIXME: transient until ec's implement serializable
+ private transient EOEditingContext defaultEditingContext;
+
+ private NSMutableDictionary state;
+ private NSMutableDictionary pages;
+ private NSMutableDictionary permanentPages;
+ private NSMutableArray stateStack;
+ private NSMutableArray pageStack;
+ private NSMutableArray permanentPageStack;
+ private boolean terminating;
+
+ // used by WOResourceManager to cache dynamic resources
+ transient NSMutableDictionary dynamicDataCache;
+
+ public static final String WOSessionDidTimeOutNotification = "WOSessionDidTimeOutNotification";
+ public static final String WOSessionDidRestoreNotification = "WOSessionDidRestoreNotification";
+ public static final String WOSessionDidCreateNotification = "WOSessionDidCreateNotification";
+
+ /**
+ * Default constructor. This is called implicitly by subclasses in all cases.
+ */
+ public WOSession() {
+ session = null;
+ state = new NSMutableDictionary();
+ pages = new NSMutableDictionary();
+ permanentPages = new NSMutableDictionary();
+ stateStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ pageStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ permanentPageStack = NSMutableArray.mutableArrayBackedByList(new LinkedList());
+ defaultEditingContext = null;
+ terminating = false;
+ }
+
+ /**
+ * Package method to initialize the backing session.
+ */
+ void setServletSession(HttpSession aSession) {
+ session = aSession;
+ }
+
+ /**
+ * Package method to set the current context.
+ */
+ void setContext(WOContext aContext) {
+ context = aContext;
+ }
+
+ /**
+ * Returns the id of the current session. If no session currently exists, return
+ * null.
+ */
+ public String sessionID() {
+ if (session != null) {
+ return session.getId();
+ }
+ return null;
+ }
+
+ /**
+ * Sets whether distribution is currently enabled. This method is not
+ * implemented by this implementation as the servlet container manages
+ * distribution.
+ */
+ public void setDistributionEnabled(boolean enabled) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether the session is part of a distributed application. This
+ * implementation always returns false.
+ */
+ public boolean isDistributionEnabled() {
+ return false;
+ }
+
+ /**
+ * Sets whether session ids should be stored in cookies. This method is not
+ * implemented in this implementation as the servlet container manages sessions
+ * with cookies.
+ */
+ public void setStoresIDsInCookies(boolean cookies) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether session ids are currently stored in cookies. This
+ * implementation always returns true.
+ */
+ public boolean storesIDsInCookies() {
+ return true;
+ }
+
+ /**
+ * Returns the current expiration date for cookies that store session ids.
+ */
+ public NSDate expirationDateForIDCookies() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether session ids should be stored in urls. This method is not
+ * implemented in this implementation as the servlet container manages sessions
+ * with cookies.
+ */
+ public void setStoresIDsInURLs(boolean urls) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether session ids are currently stored in urls. This implementation
+ * always returns false.
+ */
+ public boolean storesIDsInURLs() {
+ return false;
+ }
+
+ /**
+ * Returns the current domain for cookies containing session ids.
+ */
+ public String domainForIDCookies() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Terminates this session after the completion of the current response.
+ */
+ public void terminate() {
+ terminating = true;
+ session.invalidate();
+ }
+
+ /**
+ * Returns whether the current session will terminate at the completion of the
+ * current response.
+ */
+ public boolean isTerminating() {
+ return terminating;
+ }
+
+ /**
+ * Sets the number of seconds after the last request before the session should
+ * be terminated.
+ */
+ public void setTimeOut(double timeout) {
+ session.setMaxInactiveInterval((int) timeout);
+ }
+
+ /**
+ * Returns the number of seconds after the last request before the session
+ * should be terminated.
+ */
+ public double timeOut() {
+ return session.getMaxInactiveInterval();
+ }
+
+ /**
+ * Sets the languages for which this session has been localized, in order of
+ * preference. The application will be responsible for localizing the content
+ * based on the languages found in this array.
+ */
+ public void setLanguages(NSArray anArray) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns the languages for which this session has been localized, in order of
+ * preference. The application will be responsible for localizing the content
+ * based on the languages found in this array.
+ */
+ public NSArray languages() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Stores the specified key-value pair in the session.
+ */
+ public void setObjectForKey(Object anObject, String aKey) {
+ state.setObjectForKey(anObject, aKey);
+ }
+
+ /**
+ * Returns the session value associated with the specified key.
+ */
+ public Object objectForKey(String aKey) {
+ return state.objectForKey(aKey);
+ }
+
+ /**
+ * Removes the session value associated with the specified key.
+ */
+ public void removeObjectForKey(String aKey) {
+ state.removeObjectForKey(aKey);
+ }
+
+ /**
+ * Returns the context for the current request.
+ */
+ public WOContext context() {
+ return context;
+ }
+
+ /**
+ * Invoked at the beginning of the request-response cycle. Override to perform
+ * any kind of initialization at the start of a request. This implementation
+ * does nothing.
+ */
+ public void awake() {
+
+ }
+
+ /**
+ * Invoked by the Application to extract user-assigned balues and assign them to
+ * attributes. This implementation calls takeValuesFromRequest on the top-level
+ * component.
+ */
+ public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
+ context().component().takeValuesFromRequest(aRequest, aContext);
+ }
+
+ /**
+ * Invoked by the Application to determine which component is the intended
+ * recipient of the user's action. This implementation calls invokeAction on the
+ * top-level component.
+ */
+ public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
+ return context().component().invokeAction(aRequest, aContext);
+ }
+
+ /**
+ * Invoked by the Application to generate the content of the response. This
+ * implementation calls appendToResponse on the top-level component.
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ context().component().appendToResponse(aResponse, aContext);
+ }
+
+ /**
+ * Invoked at the end of the request-response cycle. Override to perform any
+ * kind of clean-up at the end of a request. This implementation does nothing.
+ */
+ public void sleep() {
+
+ }
+
+ /**
+ * Returns a list of pages accessed by this session in order of their access and
+ * named by calling WOComponent.descriptionForResponse.
+ */
+ public NSArray statistics() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Puts this page in the session's page cache using the current context id as
+ * the key.
+ */
+ public void savePage(WOComponent aComponent) {
+ currentPage = aComponent;
+ currentContextID = context.contextID();
+
+ if (pages.objectForKey(currentContextID) == null) {
+ byte[] data = KeyValueCodingUtilities.freeze(aComponent, defaultEditingContext(), aComponent, true);
+ System.out.println("WOSession.savePage: " + currentContextID + " : " + data.length);
+
+ pages.setObjectForKey(data, currentContextID);
+ pageStack.addObject(currentContextID);
+ if (pageStack.count() > context().application().pageCacheSize()) {
+ String id = pageStack.remove(0).toString(); // removeObjectAtIndex
+ System.out.println("WOSession.savePage: removing from cache: " + id);
+ pages.removeObjectForKey(id);
+ }
+ }
+ // System.out.println( "savePage: " + this + " : " + id + " : " + pages );
+ }
+
+ /**
+ * Returns the page in the session's page cache corresponding to the specified
+ * context id. Any special permanent caches are searched before the standard
+ * page cache.
+ */
+ public WOComponent restorePageForContextID(String anID) {
+ if (anID == null)
+ return null;
+ if (anID.equals(currentContextID))
+ return currentPage;
+
+ WOComponent result = null;
+ byte[] data = (byte[]) permanentPages.objectForKey(anID);
+ if (data == null)
+ data = (byte[]) pages.objectForKey(anID);
+ if (data != null) {
+ System.out.println("WOSession.restorePageForContextID: " + anID + " : " + data.length);
+ result = (WOComponent) KeyValueCodingUtilities.thaw(data, defaultEditingContext(),
+ WOApplication.application().getClass().getClassLoader(), true);
+ }
+ // System.out.println( "restorePageForContextID: " + this + " : " + anID + " : "
+ // + result + " : " + pages );
+ return result;
+ }
+
+ /**
+ * Puts this page in the special cache is will not get automatically flushed
+ * like the session page cache. Use this if the page is likely to be around for
+ * a while, specifically pages within frames.
+ */
+ public void savePageInPermanentCache(WOComponent aComponent) {
+ currentPage = aComponent;
+ currentContextID = context.contextID();
+
+ if (permanentPages.objectForKey(currentContextID) == null) {
+ byte[] data = KeyValueCodingUtilities.freeze(aComponent, defaultEditingContext(), aComponent, true);
+ // System.out.println( "WOSession.savePageInPermanentCache: "
+ // + currentContextID + " : " + data.length );
+
+ permanentPages.setObjectForKey(data, currentContextID);
+ permanentPageStack.addObject(currentContextID);
+ if (permanentPageStack.count() > context().application().pageCacheSize()) {
+ String id = permanentPageStack.remove(0).toString(); // removeObjectAtIndex
+ permanentPages.removeObjectForKey(id);
+ }
+ }
+ }
+
+ /**
+ * Writes a message to the standard error stream.
+ */
+ public static void logString(String aString) {
+ System.err.println(aString);
+ }
+
+ /**
+ * Writes a message to the standard error stream if debugging is activated.
+ */
+ public static void debugString(String aString) {
+ // TODO: Check to see if debugging is enabled.
+ System.err.println(aString);
+ }
+
+ /**
+ * Returns the default editing context used by this session. Defaults to null.
+ */
+ public EOEditingContext defaultEditingContext() {
+ return defaultEditingContext;
+ }
+
+ /**
+ * Sets the default editing context used by this session.
+ */
+ public void setDefaultEditingContext(EOEditingContext aContext) {
+ defaultEditingContext = aContext;
+ }
+
+ // interface NSKeyValueCodingAdditions
+
+ public Object valueForKeyPath(String aPath) {
+ // currently key value coding support also handles keypaths
+ return valueForKey(aPath);
+ }
+
+ public void takeValueForKeyPath(Object aValue, String aPath) {
+ // currently key value coding support also handles keypaths
+ takeValueForKey(aValue, aPath);
+ }
+
+ public NSDictionary valuesForKeys(List aKeyList) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public void takeValuesFromDictionary(Map aValueMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this );
+ Object result = objectForKey(aKey);
+ if (result == null)
+ result = NSKeyValueCodingSupport.valueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : "
+ // + aValue + "->" + this );
+ setObjectForKey(aValue, aKey);
+ }
+
+ public Object storedValueForKey(String aKey) {
+ Object result = objectForKey(aKey);
+ if (result == null)
+ NSKeyValueCodingSupport.storedValueForKey(this, aKey);
+ return result;
+ }
+
+ public void takeStoredValueForKey(Object aValue, String aKey) {
+ setObjectForKey(aValue, aKey);
+ }
+
+ public Object handleQueryWithUnboundKey(String aKey) {
+ return NSKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey);
+ }
+
+ public void handleTakeValueForUnboundKey(Object aValue, String aKey) {
+ NSKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey);
+ }
+
+ public void unableToSetNullForKey(String aKey) {
+ NSKeyValueCodingSupport.unableToSetNullForKey(this, aKey);
+ }
+
+ public Object validateTakeValueForKeyPath(Object aValue, String aKey) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
index f91a433..3008f21 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSessionStore.java
@@ -19,75 +19,67 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* An abstract class defining the requirements for persisting
-* session state across user transactions. Used by WOApplication
-* to persist sessions between requests.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-public abstract class WOSessionStore
-{
- private static WOSessionStore serverSessionStore = null;
-
- /**
- * Returns the default session store used by WOApplication.
- */
- public static WOSessionStore serverSessionStore()
- {
- if ( serverSessionStore == null )
- {
- serverSessionStore = new WOServletSessionStore();
- }
- return serverSessionStore;
- }
+ * An abstract class defining the requirements for persisting session state
+ * across user transactions. Used by WOApplication to persist sessions between
+ * requests.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+public abstract class WOSessionStore {
+ private static WOSessionStore serverSessionStore = null;
+
+ /**
+ * Returns the default session store used by WOApplication.
+ */
+ public static WOSessionStore serverSessionStore() {
+ if (serverSessionStore == null) {
+ serverSessionStore = new WOServletSessionStore();
+ }
+ return serverSessionStore;
+ }
- /**
- * Called by WOApplication after the request-response cycle has ended.
- * The context's session will again be available for subsequent requests.
- */
- public final void checkInSessionForContext(WOContext aContext)
- {
- saveSessionForContext( aContext );
- }
-
- /**
- * Returns the session with the specified id for the specified request,
- * or null if none exist. Subsequent calls for the same id will return
- * null until the session is checked in again.
- * Called by WOApplication before the request-response cycle starts.
- */
- public final WOSession checkOutSessionWithID(String sessionID, WORequest aRequest)
- {
- return restoreSessionWithID( sessionID, aRequest );
- }
+ /**
+ * Called by WOApplication after the request-response cycle has ended. The
+ * context's session will again be available for subsequent requests.
+ */
+ public final void checkInSessionForContext(WOContext aContext) {
+ saveSessionForContext(aContext);
+ }
- /**
- * Removes the WOSession for the specified ID from the store and returns it.
- */
- public abstract WOSession removeSessionWithID(String sessionID);
-
- /**
- * Returns the WOSession for the specified ID from the store.
- */
- public abstract WOSession restoreSessionWithID(String sessionID,
- WORequest aRequest);
-
- /**
- * Places the context's session into the store.
- */
- public abstract void saveSessionForContext(WOContext context);
+ /**
+ * Returns the session with the specified id for the specified request, or null
+ * if none exist. Subsequent calls for the same id will return null until the
+ * session is checked in again. Called by WOApplication before the
+ * request-response cycle starts.
+ */
+ public final WOSession checkOutSessionWithID(String sessionID, WORequest aRequest) {
+ return restoreSessionWithID(sessionID, aRequest);
+ }
+
+ /**
+ * Removes the WOSession for the specified ID from the store and returns it.
+ */
+ public abstract WOSession removeSessionWithID(String sessionID);
+
+ /**
+ * Returns the WOSession for the specified ID from the store.
+ */
+ public abstract WOSession restoreSessionWithID(String sessionID, WORequest aRequest);
+
+ /**
+ * Places the context's session into the store.
+ */
+ public abstract void saveSessionForContext(WOContext context);
}
/*
- * $Log$
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2003/01/07 20:48:29 mpowers
- * Implemented WOSessionStore and WOServletSessionStore.
+ * Revision 1.1 2003/01/07 20:48:29 mpowers Implemented WOSessionStore and
+ * WOServletSessionStore.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
index 308cd20..29a06c4 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOStaticElement.java
@@ -19,52 +19,44 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web;
/**
-* This class represents a static portion of a web page.
-* Package access only, as it is not in the specification.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 893 $
-*/
-class WOStaticElement extends WOElement
-{
+ * This class represents a static portion of a web page. Package access only, as
+ * it is not in the specification.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 893 $
+ */
+class WOStaticElement extends WOElement {
String content;
/**
- * Default constructor.
- */
- public WOStaticElement()
- {
+ * Default constructor.
+ */
+ public WOStaticElement() {
content = null;
}
-
+
/**
- * Returns a static element representing the specified content.
- */
- public WOStaticElement( String aContentString )
- {
+ * Returns a static element representing the specified content.
+ */
+ public WOStaticElement(String aContentString) {
this();
content = aContentString;
}
- /**
- * Overridden to append the content string..
- */
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- aResponse.appendContentString( content );
- }
-
-
- public WOResponse generateResponse()
- {
- WOResponse r = new WOResponse();
- if (content != null)
- {
- r.appendContentString(content);
- }
- return r;
- }
-
-
+ /**
+ * Overridden to append the content string..
+ */
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ aResponse.appendContentString(content);
+ }
+
+ public WOResponse generateResponse() {
+ WOResponse r = new WOResponse();
+ if (content != null) {
+ r.appendContentString(content);
+ }
+ return r;
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
index ef5b771..0c471d7 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOString.java
@@ -25,112 +25,87 @@ import net.wotonomy.foundation.NSNumberFormatter;
import net.wotonomy.foundation.NSTimestampFormatter;
/**
-* WOString renders a dynamically generated string in the output.
-* Bindings are:
-* <ul>
-* <li>value: a property returning a value which will be rendered as the
-* output. If a formatter is not used, then the value must be convertable
-* to a String with toString().</li>
-* <li>escapeHTML: a property returning a value convertable to a Boolean
-* indicating whether the any html characters in the output should be
-* escaped so they are shown as html characters rather than interpreted
-* as html.</li>
-* <li>formatter: a property returning a Format object that will be
-* used to format the value into a String.</li>
-* <li>dateformat: a property returning a DateFormat object that will be
-* used to format the value into a String.</li>
-* <li>numberformat: a property returning a NumberFormat object that will be
-* used to format the value into a String. Not yet implemented.</li>
-* <li>valueWhenEmpty: a property returning a String that will be used
-* in place of an empty or null value. Not yet implemented.</li>
-* </ul>
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WOString extends WODynamicElement
-{
+ * WOString renders a dynamically generated string in the output. Bindings are:
+ * <ul>
+ * <li>value: a property returning a value which will be rendered as the output.
+ * If a formatter is not used, then the value must be convertable to a String
+ * with toString().</li>
+ * <li>escapeHTML: a property returning a value convertable to a Boolean
+ * indicating whether the any html characters in the output should be escaped so
+ * they are shown as html characters rather than interpreted as html.</li>
+ * <li>formatter: a property returning a Format object that will be used to
+ * format the value into a String.</li>
+ * <li>dateformat: a property returning a DateFormat object that will be used to
+ * format the value into a String.</li>
+ * <li>numberformat: a property returning a NumberFormat object that will be
+ * used to format the value into a String. Not yet implemented.</li>
+ * <li>valueWhenEmpty: a property returning a String that will be used in place
+ * of an empty or null value. Not yet implemented.</li>
+ * </ul>
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WOString extends WODynamicElement {
protected Object value;
protected boolean escapeHTML;
protected Format formatter;
protected String dateformat;
protected String numberformat;
- protected Object valueWhenEmpty;
+ protected Object valueWhenEmpty;
/**
- * The default constructor.
- */
- protected WOString ()
- {
- }
-
- public WOString (
- String aName, NSDictionary anAssociationMap, WOElement aRootElement)
- {
- super( aName, anAssociationMap, aRootElement );
- escapeHTML = true;
- }
+ * The default constructor.
+ */
+ protected WOString() {
+ }
+
+ public WOString(String aName, NSDictionary anAssociationMap, WOElement aRootElement) {
+ super(aName, anAssociationMap, aRootElement);
+ escapeHTML = true;
+ }
+
+ public void appendToResponse(WOResponse aResponse, WOContext aContext) {
+ WOComponent c = aContext.component();
+ numberformat = stringForProperty("numberformat", c);
+ dateformat = stringForProperty("dateformat", c);
+ formatter = (Format) valueForProperty("formatter", c);
+ escapeHTML = booleanForProperty("escapeHTML", c);
+ value = valueForProperty("value", c);
+ valueWhenEmpty = valueForProperty("valueWhenEmpty", c);
- public void appendToResponse (WOResponse aResponse, WOContext aContext)
- {
- WOComponent c = aContext.component();
- numberformat = stringForProperty("numberformat", c );
- dateformat = stringForProperty("dateformat", c );
- formatter = (Format) valueForProperty("formatter", c );
- escapeHTML = booleanForProperty("escapeHTML", c );
- value = valueForProperty("value", c );
- valueWhenEmpty = valueForProperty("valueWhenEmpty", c );
-
- Object result = value;
- if ( result != null )
- {
- if ( formatter != null )
- {
- try
- {
- result = formatter.format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- if ( dateformat != null )
- {
- try
- {
- result = new NSTimestampFormatter( dateformat ).format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- if ( numberformat != null )
- {
- try
- {
- result = new NSNumberFormatter( numberformat ).format( result );
- }
- catch ( IllegalArgumentException exc )
- {
- }
- }
- }
- if ( result == null )
- {
- result = valueWhenEmpty;
- if ( result == null )
- {
- result = "nil";
- }
- }
- if ( escapeHTML )
- {
- aResponse.appendContentHTMLString( result.toString() );
- }
- else
- {
- aResponse.appendContentString( result.toString() );
+ Object result = value;
+ if (result != null) {
+ if (formatter != null) {
+ try {
+ result = formatter.format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ if (dateformat != null) {
+ try {
+ result = new NSTimestampFormatter(dateformat).format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ if (numberformat != null) {
+ try {
+ result = new NSNumberFormatter(numberformat).format(result);
+ } catch (IllegalArgumentException exc) {
+ }
+ }
+ }
+ if (result == null) {
+ result = valueWhenEmpty;
+ if (result == null) {
+ result = "nil";
+ }
+ }
+ if (escapeHTML) {
+ aResponse.appendContentHTMLString(result.toString());
+ } else {
+ aResponse.appendContentString(result.toString());
}
- }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
index 05824f3..a1ef303 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSubmitButton.java
@@ -22,49 +22,52 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
/**
-* Implements a submit button with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * Implements a submit button with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOSubmitButton extends WOInput {
- public WOSubmitButton() {
- super();
- }
+ public WOSubmitButton() {
+ super();
+ }
- public WOSubmitButton(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOSubmitButton(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
- protected String inputType() {
- return "SUBMIT";
- }
+ protected String inputType() {
+ return "SUBMIT";
+ }
- protected Object value(WOContext c) {
- Object v = valueForProperty("value", c.component());
- if (v == null) {
- return "Submit";
- }
- return v;
- }
+ protected Object value(WOContext c) {
+ Object v = valueForProperty("value", c.component());
+ if (v == null) {
+ return "Submit";
+ }
+ return v;
+ }
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.add("action");
- return a;
- }
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.add("action");
+ return a;
+ }
- public WOActionResults invokeAction(WORequest r, WOContext c) {
- if (disabled(c))
- return null;
- //It's useless to check the senderID here because it's going to be for the form always.
- //So we check if the formValues contain the button's name (which means it was pressed)
- if (r.formValueForKey(inputName(c)) != null) {
- if (associations.objectForKey("action") != null)
- return (WOActionResults)valueForProperty("action", c.component());
- }
- return null;
- }
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ if (disabled(c))
+ return null;
+ // It's useless to check the senderID here because it's going to be for the form
+ // always.
+ // So we check if the formValues contain the button's name (which means it was
+ // pressed)
+ if (r.formValueForKey(inputName(c)) != null) {
+ if (associations.objectForKey("action") != null)
+ return (WOActionResults) valueForProperty("action", c.component());
+ }
+ return null;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
index d2e373a..6f42199 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOSwitchComponent.java
@@ -23,90 +23,78 @@ import net.wotonomy.foundation.NSMutableDictionary;
public class WOSwitchComponent extends WODynamicElement {
- private NSMutableDictionary elements;
- private String currentName;
- private WOElement currentElement;
-
- protected WOSwitchComponent()
- {
- super();
- elements = new NSMutableDictionary();
- }
-
- public WOSwitchComponent(String aName, NSDictionary aMap, WOElement template)
- {
- super(aName, aMap, template);
- elements = new NSMutableDictionary();
- }
-
- private WOElement getCurrentElement( WOContext c )
- {
- String name = stringForProperty( "WOComponentName", c.component() );
- if ( name == null ) return null;
-
- if ( currentElement != null && name.equals( currentName ) ) return currentElement;
-
- currentName = name;
- currentElement = (WOElement) elements.objectForKey( name );
- if ( currentElement == null )
- {
- currentElement = WOApplication.application().pageWithName( name, c );
- if ( currentElement != null )
- {
- currentElement.associations = associations;
- elements.setObjectForKey( currentElement, name );
- }
- }
-
- return currentElement;
- }
-
- void ensureAwakeInContext (WOContext aContext)
- {
- if ( aContext != null )
- {
- WOElement element = getCurrentElement( aContext );
- if ( element != null )
- {
- aContext.pushElement( element );
- element.ensureAwakeInContext( aContext );
- aContext.popElement();
- }
- }
- }
-
- public void takeValuesFromRequest(WORequest r, WOContext c)
- {
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- element.takeValuesFromRequest( r, c );
- c.popElement();
- }
- }
-
- public WOActionResults invokeAction(WORequest r, WOContext c)
- {
- WOActionResults result = null;
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- result = element.invokeAction( r, c );
- c.popElement();
- }
- return result;
- }
-
- public void appendToResponse(WOResponse r, WOContext c)
- {
- WOElement element = getCurrentElement( c );
- if ( element != null )
- {
- c.pushElement( element );
- element.appendToResponse( r, c );
- c.popElement();
- }
- }
+ private NSMutableDictionary elements;
+ private String currentName;
+ private WOElement currentElement;
+
+ protected WOSwitchComponent() {
+ super();
+ elements = new NSMutableDictionary();
+ }
+
+ public WOSwitchComponent(String aName, NSDictionary aMap, WOElement template) {
+ super(aName, aMap, template);
+ elements = new NSMutableDictionary();
+ }
+
+ private WOElement getCurrentElement(WOContext c) {
+ String name = stringForProperty("WOComponentName", c.component());
+ if (name == null)
+ return null;
+
+ if (currentElement != null && name.equals(currentName))
+ return currentElement;
+
+ currentName = name;
+ currentElement = (WOElement) elements.objectForKey(name);
+ if (currentElement == null) {
+ currentElement = WOApplication.application().pageWithName(name, c);
+ if (currentElement != null) {
+ currentElement.associations = associations;
+ elements.setObjectForKey(currentElement, name);
+ }
+ }
+
+ return currentElement;
+ }
+
+ void ensureAwakeInContext(WOContext aContext) {
+ if (aContext != null) {
+ WOElement element = getCurrentElement(aContext);
+ if (element != null) {
+ aContext.pushElement(element);
+ element.ensureAwakeInContext(aContext);
+ aContext.popElement();
+ }
+ }
+ }
+
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ element.takeValuesFromRequest(r, c);
+ c.popElement();
+ }
+ }
+
+ public WOActionResults invokeAction(WORequest r, WOContext c) {
+ WOActionResults result = null;
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ result = element.invokeAction(r, c);
+ c.popElement();
+ }
+ return result;
+ }
+
+ public void appendToResponse(WOResponse r, WOContext c) {
+ WOElement element = getCurrentElement(c);
+ if (element != null) {
+ c.pushElement(element);
+ element.appendToResponse(r, c);
+ c.popElement();
+ }
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
index 008fda8..3b5dd1d 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOText.java
@@ -22,20 +22,21 @@ import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
/**
-* Implements a TEXTAREA element, with dynamic bindings.
+ * Implements a TEXTAREA element, with dynamic bindings.
+ *
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOText extends WOInput {
- public WOText() {
- super();
- }
+ public WOText() {
+ super();
+ }
- public WOText(String n, NSDictionary m, WOElement t) {
- super(n, m, t);
- }
+ public WOText(String n, NSDictionary m, WOElement t) {
+ super(n, m, t);
+ }
protected String inputType() {
return "TEXTAREA";
@@ -49,24 +50,23 @@ public class WOText extends WOInput {
return formattedValue(fieldValue, c.component());
}
- public void takeValuesFromRequest(WORequest r, WOContext c) {
- Object val = r.formValueForKey(inputName(c));
- if ( val != null )
- setValueForProperty("value", formattedValue(val, c.component()), c.component());
- }
+ public void takeValuesFromRequest(WORequest r, WOContext c) {
+ Object val = r.formValueForKey(inputName(c));
+ if (val != null)
+ setValueForProperty("value", formattedValue(val, c.component()), c.component());
+ }
- public void appendToResponse(WOResponse r, WOContext c) {
- r.appendContentString("<TEXTAREA NAME=\"");
- r.appendContentString(inputName(c));
- r.appendContentString("\"");
- String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[]{
- "name", "value" }));
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString(">");
- moreFields = value(c).toString();
- if (moreFields != null && moreFields.length() > 0)
- r.appendContentString(moreFields);
- r.appendContentString("</TEXTAREA>");
- }
+ public void appendToResponse(WOResponse r, WOContext c) {
+ r.appendContentString("<TEXTAREA NAME=\"");
+ r.appendContentString(inputName(c));
+ r.appendContentString("\"");
+ String moreFields = additionalHTMLProperties(c.component(), new NSArray(new Object[] { "name", "value" }));
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString(">");
+ moreFields = value(c).toString();
+ if (moreFields != null && moreFields.length() > 0)
+ r.appendContentString(moreFields);
+ r.appendContentString("</TEXTAREA>");
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
index 4233ad4..82f591a 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WOTextField.java
@@ -22,38 +22,39 @@ import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableArray;
/**
-* Implements an INPUT tag of type TEXT, with dynamic bindings.
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
+ * Implements an INPUT tag of type TEXT, with dynamic bindings.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
public class WOTextField extends WOInput {
- public WOTextField() {
- super();
- }
-
- public WOTextField(String aName, NSDictionary assocs, WOElement template) {
- super(aName, assocs, template);
- }
-
- protected String inputType() {
- return "TEXT";
- }
-
- protected Object value(WOContext c) {
- Object fieldValue = valueForProperty("value", c.component());
- if (fieldValue == null) {
- fieldValue = "";
- }
- return formattedValue(fieldValue, c.component());
- }
-
- protected NSMutableArray additionalAttributes() {
- NSMutableArray a = super.additionalAttributes();
- a.addObject("dateformat");
- a.addObject("numberformat");
- return a;
- }
+ public WOTextField() {
+ super();
+ }
+
+ public WOTextField(String aName, NSDictionary assocs, WOElement template) {
+ super(aName, assocs, template);
+ }
+
+ protected String inputType() {
+ return "TEXT";
+ }
+
+ protected Object value(WOContext c) {
+ Object fieldValue = valueForProperty("value", c.component());
+ if (fieldValue == null) {
+ fieldValue = "";
+ }
+ return formattedValue(fieldValue, c.component());
+ }
+
+ protected NSMutableArray additionalAttributes() {
+ NSMutableArray a = super.additionalAttributes();
+ a.addObject("dateformat");
+ a.addObject("numberformat");
+ return a;
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
index 777d4a1..7a6a946 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/util/BrowserLauncher.java
@@ -10,656 +10,644 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-/** <p> BrowserLauncher is a class that provides one static method,
- * openURL, which opens the default web browser for the current user
- * of the system to the given URL. It may support other protocols
- * depending on the system -- mailto, ftp, etc. -- but that has not
- * been rigorously tested and is not guaranteed to work. </p>
+/**
+ * <p>
+ * BrowserLauncher is a class that provides one static method, openURL, which
+ * opens the default web browser for the current user of the system to the given
+ * URL. It may support other protocols depending on the system -- mailto, ftp,
+ * etc. -- but that has not been rigorously tested and is not guaranteed to
+ * work.
+ * </p>
*
- * <p> Yes, this is platform-specific code, and yes, it may rely on
- * classes on certain platforms that are not part of the standard JDK.
- * What we're trying to do, though, is to take something that's
- * frequently desirable but inherently platform-specific -- opening a
- * default browser -- and allow programmers (you, for example) to do
- * so without worrying about dropping into native code or doing
- * anything else similarly evil. </p>
+ * <p>
+ * Yes, this is platform-specific code, and yes, it may rely on classes on
+ * certain platforms that are not part of the standard JDK. What we're trying to
+ * do, though, is to take something that's frequently desirable but inherently
+ * platform-specific -- opening a default browser -- and allow programmers (you,
+ * for example) to do so without worrying about dropping into native code or
+ * doing anything else similarly evil.
+ * </p>
*
- * <p> Anyway, this code is completely in Java and will run on all JDK
- * 1.1-compliant systems without modification or a need for additional
- * libraries. All classes that are required on certain platforms to
- * allow this to run are dynamically loaded at runtime via reflection
- * and, if not found, will not cause this to do anything other than
- * returning an error when opening the browser. </p>
+ * <p>
+ * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant
+ * systems without modification or a need for additional libraries. All classes
+ * that are required on certain platforms to allow this to run are dynamically
+ * loaded at runtime via reflection and, if not found, will not cause this to do
+ * anything other than returning an error when opening the browser.
+ * </p>
*
- * <p> There are certain system requirements for this class, as it's
- * running through Runtime.exec(), which is Java's way of making a
- * native system call. Currently, this requires that a Macintosh have
- * a Finder which supports the GURL event, which is true for Mac OS
- * 8.0 and 8.1 systems that have the Internet Scripting AppleScript
- * dictionary installed in the Scripting Additions folder in the
- * Extensions folder (which is installed by default as far as I know
- * under Mac OS 8.0 and 8.1), and for all Mac OS 8.5 and later
- * systems. On Windows, it only runs under Win32 systems (Windows 95,
- * 98, and NT 4.0, as well as later versions of all). On other
- * systems, this drops back from the inherently platform-sensitive
- * concept of a default browser and simply attempts to launch Netscape
- * via a shell command. </p>
+ * <p>
+ * There are certain system requirements for this class, as it's running through
+ * Runtime.exec(), which is Java's way of making a native system call.
+ * Currently, this requires that a Macintosh have a Finder which supports the
+ * GURL event, which is true for Mac OS 8.0 and 8.1 systems that have the
+ * Internet Scripting AppleScript dictionary installed in the Scripting
+ * Additions folder in the Extensions folder (which is installed by default as
+ * far as I know under Mac OS 8.0 and 8.1), and for all Mac OS 8.5 and later
+ * systems. On Windows, it only runs under Win32 systems (Windows 95, 98, and NT
+ * 4.0, as well as later versions of all). On other systems, this drops back
+ * from the inherently platform-sensitive concept of a default browser and
+ * simply attempts to launch Netscape via a shell command.
+ * </p>
*
- * <p> This code is Copyright 1999-2001 by Eric Albert
- * (ejalbert@cs.stanford.edu) and may be redistributed or modified in
- * any form without restrictions as long as the portion of this
- * comment from this paragraph through the end of the comment is not
- * removed. The author requests that he be notified of any
- * application, applet, or other binary that makes use of this code,
- * but that's more out of curiosity than anything and is not required.
- * This software includes no warranty. The author is not repsonsible
- * for any loss of data or functionality or any adverse or unexpected
- * effects of using this software. </p>
+ * <p>
+ * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu)
+ * and may be redistributed or modified in any form without restrictions as long
+ * as the portion of this comment from this paragraph through the end of the
+ * comment is not removed. The author requests that he be notified of any
+ * application, applet, or other binary that makes use of this code, but that's
+ * more out of curiosity than anything and is not required. This software
+ * includes no warranty. The author is not repsonsible for any loss of data or
+ * functionality or any adverse or unexpected effects of using this software.
+ * </p>
*
- * Credits: <br> Steven Spencer, JavaWorld magazine (<a
- * href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java
- * Tip 66</a>) <br> Thanks also to Ron B. Yeh, Eric Shapiro, Ben
- * Engber, Paul Teitlebaum, Andrea Cantatore, Larry Barowski, Trevor
- * Bedzek, Frank Miedrich, and Ron Rabakukk
+ * Credits: <br>
+ * Steven Spencer, JavaWorld magazine
+ * (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java
+ * Tip 66</a>) <br>
+ * Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea
+ * Cantatore, Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
*
*
- * original author Eric Albert (<a
- * href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
+ * original author Eric Albert
+ * (<a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
* author's version 1.4b1 (Released June 20, 2001)
+ *
* @author Copyright 2001, Intersect Software Corporation
- * @version $Revision: 905 $ $Date: 2006-02-18 20:44:03 -0500 (Sat, 18 Feb 2006) $
+ * @version $Revision: 905 $ $Date: 2006-02-18 20:44:03 -0500 (Sat, 18 Feb 2006)
+ * $
*/
public class BrowserLauncher {
- /** The Java virtual machine that we are running on. Actually, in
- * most cases we only care about the operating system, but some
- * operating systems require us to switch on the VM. */
- private static int jvm;
+ /**
+ * The Java virtual machine that we are running on. Actually, in most cases we
+ * only care about the operating system, but some operating systems require us
+ * to switch on the VM.
+ */
+ private static int jvm;
- /** The browser for the system */
- private static Object browser;
+ /** The browser for the system */
+ private static Object browser;
- /** Caches whether any classes, methods, and fields that are not
- * part of the JDK and need to be dynamically loaded at runtime
- * loaded successfully. <p> Note that if this is
- * <code>false</code>, <code>openURL()</code> will always return
- * an IOException. */
- private static boolean loadedWithoutErrors;
+ /**
+ * Caches whether any classes, methods, and fields that are not part of the JDK
+ * and need to be dynamically loaded at runtime loaded successfully.
+ * <p>
+ * Note that if this is <code>false</code>, <code>openURL()</code> will always
+ * return an IOException.
+ */
+ private static boolean loadedWithoutErrors;
- /** The com.apple.mrj.MRJFileUtils class */
- private static Class mrjFileUtilsClass;
+ /** The com.apple.mrj.MRJFileUtils class */
+ private static Class mrjFileUtilsClass;
- /** The com.apple.mrj.MRJOSType class */
- private static Class mrjOSTypeClass;
+ /** The com.apple.mrj.MRJOSType class */
+ private static Class mrjOSTypeClass;
- /** The com.apple.MacOS.AEDesc class */
- private static Class aeDescClass;
+ /** The com.apple.MacOS.AEDesc class */
+ private static Class aeDescClass;
- /** The <init>(int) method of com.apple.MacOS.AETarget */
- private static Constructor aeTargetConstructor;
+ /** The <init>(int) method of com.apple.MacOS.AETarget */
+ private static Constructor aeTargetConstructor;
- /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
- private static Constructor appleEventConstructor;
+ /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
+ private static Constructor appleEventConstructor;
- /** The <init>(String) method of com.apple.MacOS.AEDesc */
- private static Constructor aeDescConstructor;
+ /** The <init>(String) method of com.apple.MacOS.AEDesc */
+ private static Constructor aeDescConstructor;
- /** The findFolder method of com.apple.mrj.MRJFileUtils */
- private static Method findFolder;
+ /** The findFolder method of com.apple.mrj.MRJFileUtils */
+ private static Method findFolder;
- /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
- private static Method getFileCreator;
+ /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileCreator;
- /** The getFileType method of com.apple.mrj.MRJFileUtils */
- private static Method getFileType;
+ /** The getFileType method of com.apple.mrj.MRJFileUtils */
+ private static Method getFileType;
- /** The openURL method of com.apple.mrj.MRJFileUtils */
- private static Method openURL;
+ /** The openURL method of com.apple.mrj.MRJFileUtils */
+ private static Method openURL;
- /** The makeOSType method of com.apple.MacOS.OSUtils */
- private static Method makeOSType;
-
- /** The putParameter method of com.apple.MacOS.AppleEvent */
- private static Method putParameter;
-
- /** The sendNoReply method of com.apple.MacOS.AppleEvent */
- private static Method sendNoReply;
-
- /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
- private static Object kSystemFolderType;
-
- /** The keyDirectObject AppleEvent parameter type */
- private static Integer keyDirectObject;
-
- /** The kAutoGenerateReturnID AppleEvent code */
- private static Integer kAutoGenerateReturnID;
-
- /** The kAnyTransactionID AppleEvent code */
- private static Integer kAnyTransactionID;
-
- /** The linkage object required for JDirect 3 on Mac OS X. */
- private static Object linkage;
-
- /** The framework to reference on Mac OS X */
- private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
-
- /** JVM constant for MRJ 2.0 */
- private static final int MRJ_2_0 = 0;
-
- /** JVM constant for MRJ 2.1 or later */
- private static final int MRJ_2_1 = 1;
-
- /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
- private static final int MRJ_3_0 = 3;
-
- /** JVM constant for MRJ 3.1 */
- private static final int MRJ_3_1 = 4;
-
- /** JVM constant for any Windows NT JVM */
- private static final int WINDOWS_NT = 5;
-
- /** JVM constant for any Windows 9x JVM */
- private static final int WINDOWS_9x = 6;
-
- /** JVM constant for any other platform */
- private static final int OTHER = -1;
-
- /** The file type of the Finder on a Macintosh. Hardcoding
- * "Finder" would keep non-U.S. English systems from working
- * properly. */
- private static final String FINDER_TYPE = "FNDR";
-
- /** The creator code of the Finder on a Macintosh, which is needed
- * to send AppleEvents to the application. */
- private static final String FINDER_CREATOR = "MACS";
-
- /** The name for the AppleEvent type corresponding to a GetURL event. */
- private static final String GURL_EVENT = "GURL";
-
- /** The first parameter that needs to be passed into
- * Runtime.exec() to open the default web browser on Windows. */
- private static final String FIRST_WINDOWS_PARAMETER = "/c";
-
- /** The second parameter for Runtime.exec() on Windows. */
- private static final String SECOND_WINDOWS_PARAMETER = "start";
-
- /** The third parameter for Runtime.exec() on Windows. This is a
- * "title" parameter that the command line expects. Setting this
- * parameter allows URLs containing spaces to work. */
- private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
-
- /** The shell parameters for Netscape that opens a given URL in an
- * already-open copy of Netscape on many command-line systems. */
- private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
- //private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
- //private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
- private static final String NETSCAPE_OPEN_PARAMETER_START = "openURL(";
- private static final String NETSCAPE_OPEN_PARAMETER_END = ")";
-
- /** The message from any exception thrown throughout the
- * initialization process. */
- private static String errorMessage;
-
- /** An initialization block that determines the operating system
- * and loads the necessary runtime data. */
- static {
- loadedWithoutErrors = true;
- String osName = System.getProperty("os.name");
- if (osName.startsWith("Mac OS")) {
- String mrjVersion = System.getProperty("mrj.version");
- String majorMRJVersion = mrjVersion.substring(0, 3);
- try {
- double version = Double.valueOf(majorMRJVersion).doubleValue();
- if (version == 2) {
- jvm = MRJ_2_0;
- } else if (version >= 2.1 && version < 3) {
- // Assume that all 2.x versions of MRJ work the
- // same. MRJ 2.1 actually works via
- // Runtime.exec() and 2.2 supports that but has an
- // openURL() method as well that we currently
- // ignore.
- jvm = MRJ_2_1;
- } else if (version == 3.0) {
- jvm = MRJ_3_0;
- } else if (version >= 3.1) {
- // Assume that all 3.1 and later versions of MRJ
- // work the same.
- jvm = MRJ_3_1;
- } else {
- loadedWithoutErrors = false;
- errorMessage = "Unsupported MRJ version: " + version;
- }
- } catch (NumberFormatException nfe) {
- loadedWithoutErrors = false;
- errorMessage = "Invalid MRJ version: " + mrjVersion;
- }
- } else if (osName.startsWith("Windows")) {
- if (osName.indexOf("9") != -1) {
- jvm = WINDOWS_9x;
- } else {
- jvm = WINDOWS_NT;
- }
- } else {
- jvm = OTHER;
- }
-
- if (loadedWithoutErrors) { // if we haven't hit any errors yet
- loadedWithoutErrors = loadClasses();
- }
- }
-
- /** This class should be never be instantiated; this just ensures so. */
- private BrowserLauncher() { }
-
- /** Called by a static initializer to load any classes, fields,
- * and methods required at runtime to locate the user's web
- * browser.
- * @return <code>true</code> if all intialization succeeded
- * <code>false</code> if any portion of the initialization failed */
- private static boolean loadClasses() {
- switch (jvm) {
- case MRJ_2_0:
- try {
- Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
- Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
- Class appleEventClass = Class.forName
- ("com.apple.MacOS.AppleEvent");
- Class aeClass = Class.forName("com.apple.MacOS.ae");
- aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
-
- aeTargetConstructor = aeTargetClass.getDeclaredConstructor
- (new Class [] { int.class });
- appleEventConstructor = appleEventClass.getDeclaredConstructor
- (new Class[] { int.class, int.class, aeTargetClass,
- int.class, int.class });
- aeDescConstructor = aeDescClass.getDeclaredConstructor
- (new Class[] { String.class });
-
- makeOSType = osUtilsClass.getDeclaredMethod
- ("makeOSType", new Class [] { String.class });
- putParameter = appleEventClass.getDeclaredMethod
- ("putParameter", new Class[] { int.class, aeDescClass });
- sendNoReply = appleEventClass.getDeclaredMethod
- ("sendNoReply", new Class[] { });
-
- Field keyDirectObjectField = aeClass.getDeclaredField
- ("keyDirectObject");
- keyDirectObject = (Integer) keyDirectObjectField.get(null);
- Field autoGenerateReturnIDField = appleEventClass
- .getDeclaredField("kAutoGenerateReturnID");
- kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField
- .get(null);
- Field anyTransactionIDField = appleEventClass.getDeclaredField
- ("kAnyTransactionID");
- kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_2_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
- Field systemFolderField = mrjFileUtilsClass.getDeclaredField
- ("kSystemFolderType");
- kSystemFolderType = systemFolderField.get(null);
- findFolder = mrjFileUtilsClass.getDeclaredMethod
- ("findFolder", new Class[] { mrjOSTypeClass });
- getFileCreator = mrjFileUtilsClass.getDeclaredMethod
- ("getFileCreator", new Class[] { File.class });
- getFileType = mrjFileUtilsClass.getDeclaredMethod
- ("getFileType", new Class[] { File.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (SecurityException se) {
- errorMessage = se.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_0:
- try {
- Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
- Constructor constructor = linker.getConstructor
- (new Class[]{ Class.class });
- linkage = constructor.newInstance(new Object[]
- { BrowserLauncher.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (InvocationTargetException ite) {
- errorMessage = ite.getMessage();
- return false;
- } catch (InstantiationException ie) {
- errorMessage = ie.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- openURL = mrjFileUtilsClass.getDeclaredMethod
- ("openURL", new Class[] { String.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- }
- break;
- default:
- break;
- }
- return true;
- }
-
- /** Attempts to locate the default web browser on the local
- * system. Caches results so it only locates the browser once *
- * for each use of this class per JVM instance.
- * @return The browser for the system. Note that this may not be
- * what you would consider to be a standard web browser; instead,
- * it's the application that gets called to open the default web
- * browser. In some cases, this will be a non-String object that
- * provides the means of calling the default browser. */
- private static Object locateBrowser() {
- if (browser != null) {
- return browser;
- }
- switch (jvm) {
- case MRJ_2_0:
- try {
- Integer finderCreatorCode = (Integer) makeOSType.invoke
- (null, new Object[] { FINDER_CREATOR });
- Object aeTarget = aeTargetConstructor.newInstance
- (new Object[] { finderCreatorCode });
- Integer gurlType = (Integer) makeOSType.invoke
- (null, new Object[] { GURL_EVENT });
- Object appleEvent = appleEventConstructor.newInstance
- (new Object[] { gurlType, gurlType, aeTarget,
- kAutoGenerateReturnID, kAnyTransactionID });
- // Don't set browser = appleEvent because then the
- // next time we call locateBrowser(), we'll get the
- // same AppleEvent, to which we'll already have added
- // the relevant parameter. Instead, regenerate the
- // AppleEvent every time. There's probably a way to
- // do this better; if any has any ideas, please let me
- // know.
- return appleEvent;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InstantiationException ie) {
- browser = null;
- errorMessage = ie.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getMessage();
- return browser;
- }
- case MRJ_2_1:
- File systemFolder;
- try {
- systemFolder = (File) findFolder.invoke(null, new Object[]
- { kSystemFolderType });
- } catch (IllegalArgumentException iare) {
- browser = null;
- errorMessage = iare.getMessage();
- return browser;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": " +
- ite.getTargetException().getMessage();
- return browser;
- }
- String[] systemFolderFiles = systemFolder.list();
- // Avoid a FilenameFilter because that can't be stopped mid-list
- for(int i = 0; i < systemFolderFiles.length; i++) {
- try {
- File file = new File(systemFolder, systemFolderFiles[i]);
- if (!file.isFile()) {
- continue;
- }
- // We're looking for a file with a creator code of
- // 'MACS' and a type of 'FNDR'. Only requiring
- // the type results in non-Finder applications
- // being picked up on certain Mac OS 9 systems,
- // especially German ones, and sending a GURL
- // event to those applications results in a logout
- // under Multiple Users.
- Object fileType = getFileType.invoke
- (null, new Object[] { file });
- if (FINDER_TYPE.equals(fileType.toString())) {
- Object fileCreator = getFileCreator.invoke
- (null, new Object[] { file });
- if (FINDER_CREATOR.equals(fileCreator.toString())) {
- browser = file.toString(); // Actually the
- // Finder, but that's OK
- return browser;
- }
- }
- } catch (IllegalArgumentException iare) {
- //WTF? browser = browser;
- errorMessage = iare.getMessage();
- return null;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": "
- + ite.getTargetException().getMessage();
- return browser;
- }
- }
- browser = null;
- break;
- case MRJ_3_0:
- case MRJ_3_1:
- browser = ""; // Return something non-null
- break;
- case WINDOWS_NT:
- browser = "cmd.exe";
- break;
- case WINDOWS_9x:
- browser = "command.com";
- break;
- case OTHER:
- default:
- browser = "netscape";
- break;
- }
- return browser;
- }
-
- /** Attempts to open the default web browser to the given URL.
- * @param url The URL to open
- * @throws IOException If the web browser could not be located or
- * does not run */
- public static void openURL(String url) throws IOException {
- if (!loadedWithoutErrors) {
- throw new IOException("Exception in finding browser: "
- + errorMessage);
- }
- Object browser = locateBrowser();
- if (browser == null) {
- throw new IOException("Unable to locate browser: " + errorMessage);
- }
-
- switch (jvm) {
- case MRJ_2_0:
- Object aeDesc = null;
- try {
- aeDesc = aeDescConstructor.newInstance(new Object[] { url });
- putParameter.invoke(browser, new Object[]
- { keyDirectObject, aeDesc });
- sendNoReply.invoke(browser, new Object[] { });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while creating"
- +" AEDesc: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while building "
- + "AppleEvent: " + iae.getMessage());
- } catch (InstantiationException ie) {
- throw new IOException("InstantiationException while creating "
- + "AEDesc: " + ie.getMessage());
- } finally {
- aeDesc = null; // Encourage it to get disposed if it
- // was created
- browser = null; // Ditto
- }
- break;
- case MRJ_2_1:
- Runtime.getRuntime().exec(new String[] { (String) browser, url } );
- break;
- case MRJ_3_0:
- int[] instance = new int[1];
- int result = ICStart(instance, 0);
- if (result == 0) {
- int[] selectionStart = new int[] { 0 };
- byte[] urlBytes = url.getBytes();
- int[] selectionEnd = new int[] { urlBytes.length };
- result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
- urlBytes.length, selectionStart,
- selectionEnd);
- if (result == 0) {
- // Ignore the return value; the URL was launched
- // successfully regardless of what happens here.
- ICStop(instance);
- } else {
- throw new IOException("Unable to launch URL: " + result);
- }
- } else {
- throw new IOException("Unable to create an Internet Config "
- + "instance: " + result);
- }
- break;
- case MRJ_3_1:
- try {
- openURL.invoke(null, new Object[] { url });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while calling "
- + "openURL: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while calling "
- + "openURL: " + iae.getMessage());
- }
- break;
- case WINDOWS_NT:
- // Add quotes around the URL to allow ampersands and other special
- // characters to work.
- Process process = Runtime.getRuntime().exec(new String[]
- { (String) browser, FIRST_WINDOWS_PARAMETER,
- SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER,
- '"' + url + '"' });
- // This avoids a memory leak on some versions of Java on
- // Windows. That's hinted at in
- // <http://developer.java.sun.com/developer/qow/archive/68/>.
- try {
- process.waitFor();
- process.exitValue();
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- case WINDOWS_9x:
- // Add quotes around the URL to allow ampersands and other special
- // characters to work.
- // Note: windows 98 doesn't expect the THIRD_WINDOWS_PARAMETER for
- // its title.
- process = Runtime.getRuntime().exec(new String[]
- { (String) browser, FIRST_WINDOWS_PARAMETER,
- SECOND_WINDOWS_PARAMETER, '"' + url + '"' });
- // This avoids a memory leak on some versions of Java on
- // Windows. That's hinted at in
- // <http://developer.java.sun.com/developer/qow/archive/68/>.
- try {
- process.waitFor();
- process.exitValue();
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- case OTHER:
- // Assume that we're on Unix and that Netscape is installed
-
- // First, attempt to open the URL in a currently running
- // session of Netscape
- process = Runtime.getRuntime().exec(new String[]
- {(String)browser, NETSCAPE_REMOTE_PARAMETER,
- NETSCAPE_OPEN_PARAMETER_START + url +
- NETSCAPE_OPEN_PARAMETER_END });
- try {
- int exitCode = process.waitFor();
- if (exitCode != 0) { // if the command had an error
- Runtime.getRuntime().exec(new String[]
- { (String) browser, url } );
- } else if(process.getErrorStream() != null) {
- // Netscape may not be open, so the command may not have an
- // error, it just wouldn't have a process to attach to...
- BufferedReader reader = new BufferedReader
- (new InputStreamReader(process.getErrorStream()));
- String errorStr = reader.readLine();
-
- if ( errorStr != null ) {
- // Command failed, start up the browser
- process = Runtime.getRuntime().exec(new String[] {
- (String) browser, url });
- }
- }
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching "
- + "browser: " + ie.getMessage());
- }
- break;
- default:
- // This should never occur, but if it does, we'll try the
- // simplest thing possible
- Runtime.getRuntime().exec(new String[] { (String) browser, url });
- break;
- }
- }
-
- /** Methods required for Mac OS X. The presence of native methods
- * does not cause any problems on other platforms. */
- private native static int ICStart(int[] instance, int signature);
- private native static int ICStop(int[] instance);
- private native static int ICLaunchURL
- (int instance, byte[] hint, byte[] data, int len, int[] selectionStart,
- int[] selectionEnd);
+ /** The makeOSType method of com.apple.MacOS.OSUtils */
+ private static Method makeOSType;
+
+ /** The putParameter method of com.apple.MacOS.AppleEvent */
+ private static Method putParameter;
+
+ /** The sendNoReply method of com.apple.MacOS.AppleEvent */
+ private static Method sendNoReply;
+
+ /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
+ private static Object kSystemFolderType;
+
+ /** The keyDirectObject AppleEvent parameter type */
+ private static Integer keyDirectObject;
+
+ /** The kAutoGenerateReturnID AppleEvent code */
+ private static Integer kAutoGenerateReturnID;
+
+ /** The kAnyTransactionID AppleEvent code */
+ private static Integer kAnyTransactionID;
+
+ /** The linkage object required for JDirect 3 on Mac OS X. */
+ private static Object linkage;
+
+ /** The framework to reference on Mac OS X */
+ private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
+
+ /** JVM constant for MRJ 2.0 */
+ private static final int MRJ_2_0 = 0;
+
+ /** JVM constant for MRJ 2.1 or later */
+ private static final int MRJ_2_1 = 1;
+
+ /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
+ private static final int MRJ_3_0 = 3;
+
+ /** JVM constant for MRJ 3.1 */
+ private static final int MRJ_3_1 = 4;
+
+ /** JVM constant for any Windows NT JVM */
+ private static final int WINDOWS_NT = 5;
+
+ /** JVM constant for any Windows 9x JVM */
+ private static final int WINDOWS_9x = 6;
+
+ /** JVM constant for any other platform */
+ private static final int OTHER = -1;
+
+ /**
+ * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep
+ * non-U.S. English systems from working properly.
+ */
+ private static final String FINDER_TYPE = "FNDR";
+
+ /**
+ * The creator code of the Finder on a Macintosh, which is needed to send
+ * AppleEvents to the application.
+ */
+ private static final String FINDER_CREATOR = "MACS";
+
+ /** The name for the AppleEvent type corresponding to a GetURL event. */
+ private static final String GURL_EVENT = "GURL";
+
+ /**
+ * The first parameter that needs to be passed into Runtime.exec() to open the
+ * default web browser on Windows.
+ */
+ private static final String FIRST_WINDOWS_PARAMETER = "/c";
+
+ /** The second parameter for Runtime.exec() on Windows. */
+ private static final String SECOND_WINDOWS_PARAMETER = "start";
+
+ /**
+ * The third parameter for Runtime.exec() on Windows. This is a "title"
+ * parameter that the command line expects. Setting this parameter allows URLs
+ * containing spaces to work.
+ */
+ private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
+
+ /**
+ * The shell parameters for Netscape that opens a given URL in an already-open
+ * copy of Netscape on many command-line systems.
+ */
+ private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
+ // private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
+ // private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
+ private static final String NETSCAPE_OPEN_PARAMETER_START = "openURL(";
+ private static final String NETSCAPE_OPEN_PARAMETER_END = ")";
+
+ /**
+ * The message from any exception thrown throughout the initialization process.
+ */
+ private static String errorMessage;
+
+ /**
+ * An initialization block that determines the operating system and loads the
+ * necessary runtime data.
+ */
+ static {
+ loadedWithoutErrors = true;
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Mac OS")) {
+ String mrjVersion = System.getProperty("mrj.version");
+ String majorMRJVersion = mrjVersion.substring(0, 3);
+ try {
+ double version = Double.valueOf(majorMRJVersion).doubleValue();
+ if (version == 2) {
+ jvm = MRJ_2_0;
+ } else if (version >= 2.1 && version < 3) {
+ // Assume that all 2.x versions of MRJ work the
+ // same. MRJ 2.1 actually works via
+ // Runtime.exec() and 2.2 supports that but has an
+ // openURL() method as well that we currently
+ // ignore.
+ jvm = MRJ_2_1;
+ } else if (version == 3.0) {
+ jvm = MRJ_3_0;
+ } else if (version >= 3.1) {
+ // Assume that all 3.1 and later versions of MRJ
+ // work the same.
+ jvm = MRJ_3_1;
+ } else {
+ loadedWithoutErrors = false;
+ errorMessage = "Unsupported MRJ version: " + version;
+ }
+ } catch (NumberFormatException nfe) {
+ loadedWithoutErrors = false;
+ errorMessage = "Invalid MRJ version: " + mrjVersion;
+ }
+ } else if (osName.startsWith("Windows")) {
+ if (osName.indexOf("9") != -1) {
+ jvm = WINDOWS_9x;
+ } else {
+ jvm = WINDOWS_NT;
+ }
+ } else {
+ jvm = OTHER;
+ }
+
+ if (loadedWithoutErrors) { // if we haven't hit any errors yet
+ loadedWithoutErrors = loadClasses();
+ }
+ }
+
+ /** This class should be never be instantiated; this just ensures so. */
+ private BrowserLauncher() {
+ }
+
+ /**
+ * Called by a static initializer to load any classes, fields, and methods
+ * required at runtime to locate the user's web browser.
+ *
+ * @return <code>true</code> if all intialization succeeded <code>false</code>
+ * if any portion of the initialization failed
+ */
+ private static boolean loadClasses() {
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
+ Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
+ Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
+ Class aeClass = Class.forName("com.apple.MacOS.ae");
+ aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
+
+ aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class[] { int.class });
+ appleEventConstructor = appleEventClass.getDeclaredConstructor(
+ new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
+ aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
+
+ makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class[] { String.class });
+ putParameter = appleEventClass.getDeclaredMethod("putParameter",
+ new Class[] { int.class, aeDescClass });
+ sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] {});
+
+ Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
+ keyDirectObject = (Integer) keyDirectObjectField.get(null);
+ Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
+ kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
+ Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
+ kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_2_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
+ Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
+ kSystemFolderType = systemFolderField.get(null);
+ findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
+ getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
+ getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchFieldException nsfe) {
+ errorMessage = nsfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (SecurityException se) {
+ errorMessage = se.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_0:
+ try {
+ Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
+ Constructor constructor = linker.getConstructor(new Class[] { Class.class });
+ linkage = constructor.newInstance(new Object[] { BrowserLauncher.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ } catch (InvocationTargetException ite) {
+ errorMessage = ite.getMessage();
+ return false;
+ } catch (InstantiationException ie) {
+ errorMessage = ie.getMessage();
+ return false;
+ } catch (IllegalAccessException iae) {
+ errorMessage = iae.getMessage();
+ return false;
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+ openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
+ } catch (ClassNotFoundException cnfe) {
+ errorMessage = cnfe.getMessage();
+ return false;
+ } catch (NoSuchMethodException nsme) {
+ errorMessage = nsme.getMessage();
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Attempts to locate the default web browser on the local system. Caches
+ * results so it only locates the browser once * for each use of this class per
+ * JVM instance.
+ *
+ * @return The browser for the system. Note that this may not be what you would
+ * consider to be a standard web browser; instead, it's the application
+ * that gets called to open the default web browser. In some cases, this
+ * will be a non-String object that provides the means of calling the
+ * default browser.
+ */
+ private static Object locateBrowser() {
+ if (browser != null) {
+ return browser;
+ }
+ switch (jvm) {
+ case MRJ_2_0:
+ try {
+ Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
+ Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
+ Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
+ Object appleEvent = appleEventConstructor.newInstance(
+ new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
+ // Don't set browser = appleEvent because then the
+ // next time we call locateBrowser(), we'll get the
+ // same AppleEvent, to which we'll already have added
+ // the relevant parameter. Instead, regenerate the
+ // AppleEvent every time. There's probably a way to
+ // do this better; if any has any ideas, please let me
+ // know.
+ return appleEvent;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InstantiationException ie) {
+ browser = null;
+ errorMessage = ie.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getMessage();
+ return browser;
+ }
+ case MRJ_2_1:
+ File systemFolder;
+ try {
+ systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
+ } catch (IllegalArgumentException iare) {
+ browser = null;
+ errorMessage = iare.getMessage();
+ return browser;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ String[] systemFolderFiles = systemFolder.list();
+ // Avoid a FilenameFilter because that can't be stopped mid-list
+ for (int i = 0; i < systemFolderFiles.length; i++) {
+ try {
+ File file = new File(systemFolder, systemFolderFiles[i]);
+ if (!file.isFile()) {
+ continue;
+ }
+ // We're looking for a file with a creator code of
+ // 'MACS' and a type of 'FNDR'. Only requiring
+ // the type results in non-Finder applications
+ // being picked up on certain Mac OS 9 systems,
+ // especially German ones, and sending a GURL
+ // event to those applications results in a logout
+ // under Multiple Users.
+ Object fileType = getFileType.invoke(null, new Object[] { file });
+ if (FINDER_TYPE.equals(fileType.toString())) {
+ Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
+ if (FINDER_CREATOR.equals(fileCreator.toString())) {
+ browser = file.toString(); // Actually the
+ // Finder, but that's OK
+ return browser;
+ }
+ }
+ } catch (IllegalArgumentException iare) {
+ // WTF? browser = browser;
+ errorMessage = iare.getMessage();
+ return null;
+ } catch (IllegalAccessException iae) {
+ browser = null;
+ errorMessage = iae.getMessage();
+ return browser;
+ } catch (InvocationTargetException ite) {
+ browser = null;
+ errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+ return browser;
+ }
+ }
+ browser = null;
+ break;
+ case MRJ_3_0:
+ case MRJ_3_1:
+ browser = ""; // Return something non-null
+ break;
+ case WINDOWS_NT:
+ browser = "cmd.exe";
+ break;
+ case WINDOWS_9x:
+ browser = "command.com";
+ break;
+ case OTHER:
+ default:
+ browser = "netscape";
+ break;
+ }
+ return browser;
+ }
+
+ /**
+ * Attempts to open the default web browser to the given URL.
+ *
+ * @param url The URL to open
+ * @throws IOException If the web browser could not be located or does not run
+ */
+ public static void openURL(String url) throws IOException {
+ if (!loadedWithoutErrors) {
+ throw new IOException("Exception in finding browser: " + errorMessage);
+ }
+ Object browser = locateBrowser();
+ if (browser == null) {
+ throw new IOException("Unable to locate browser: " + errorMessage);
+ }
+
+ switch (jvm) {
+ case MRJ_2_0:
+ Object aeDesc = null;
+ try {
+ aeDesc = aeDescConstructor.newInstance(new Object[] { url });
+ putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
+ sendNoReply.invoke(browser, new Object[] {});
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while creating" + " AEDesc: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while building " + "AppleEvent: " + iae.getMessage());
+ } catch (InstantiationException ie) {
+ throw new IOException("InstantiationException while creating " + "AEDesc: " + ie.getMessage());
+ } finally {
+ aeDesc = null; // Encourage it to get disposed if it
+ // was created
+ browser = null; // Ditto
+ }
+ break;
+ case MRJ_2_1:
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ break;
+ case MRJ_3_0:
+ int[] instance = new int[1];
+ int result = ICStart(instance, 0);
+ if (result == 0) {
+ int[] selectionStart = new int[] { 0 };
+ byte[] urlBytes = url.getBytes();
+ int[] selectionEnd = new int[] { urlBytes.length };
+ result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes, urlBytes.length, selectionStart,
+ selectionEnd);
+ if (result == 0) {
+ // Ignore the return value; the URL was launched
+ // successfully regardless of what happens here.
+ ICStop(instance);
+ } else {
+ throw new IOException("Unable to launch URL: " + result);
+ }
+ } else {
+ throw new IOException("Unable to create an Internet Config " + "instance: " + result);
+ }
+ break;
+ case MRJ_3_1:
+ try {
+ openURL.invoke(null, new Object[] { url });
+ } catch (InvocationTargetException ite) {
+ throw new IOException("InvocationTargetException while calling " + "openURL: " + ite.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new IOException("IllegalAccessException while calling " + "openURL: " + iae.getMessage());
+ }
+ break;
+ case WINDOWS_NT:
+ // Add quotes around the URL to allow ampersands and other special
+ // characters to work.
+ Process process = Runtime.getRuntime().exec(new String[] { (String) browser, FIRST_WINDOWS_PARAMETER,
+ SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER, '"' + url + '"' });
+ // This avoids a memory leak on some versions of Java on
+ // Windows. That's hinted at in
+ // <http://developer.java.sun.com/developer/qow/archive/68/>.
+ try {
+ process.waitFor();
+ process.exitValue();
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ case WINDOWS_9x:
+ // Add quotes around the URL to allow ampersands and other special
+ // characters to work.
+ // Note: windows 98 doesn't expect the THIRD_WINDOWS_PARAMETER for
+ // its title.
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, FIRST_WINDOWS_PARAMETER,
+ SECOND_WINDOWS_PARAMETER, '"' + url + '"' });
+ // This avoids a memory leak on some versions of Java on
+ // Windows. That's hinted at in
+ // <http://developer.java.sun.com/developer/qow/archive/68/>.
+ try {
+ process.waitFor();
+ process.exitValue();
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ case OTHER:
+ // Assume that we're on Unix and that Netscape is installed
+
+ // First, attempt to open the URL in a currently running
+ // session of Netscape
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, NETSCAPE_REMOTE_PARAMETER,
+ NETSCAPE_OPEN_PARAMETER_START + url + NETSCAPE_OPEN_PARAMETER_END });
+ try {
+ int exitCode = process.waitFor();
+ if (exitCode != 0) { // if the command had an error
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ } else if (process.getErrorStream() != null) {
+ // Netscape may not be open, so the command may not have an
+ // error, it just wouldn't have a process to attach to...
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String errorStr = reader.readLine();
+
+ if (errorStr != null) {
+ // Command failed, start up the browser
+ process = Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ }
+ }
+ } catch (InterruptedException ie) {
+ throw new IOException("InterruptedException while launching " + "browser: " + ie.getMessage());
+ }
+ break;
+ default:
+ // This should never occur, but if it does, we'll try the
+ // simplest thing possible
+ Runtime.getRuntime().exec(new String[] { (String) browser, url });
+ break;
+ }
+ }
+
+ /**
+ * Methods required for Mac OS X. The presence of native methods does not cause
+ * any problems on other platforms.
+ */
+ private native static int ICStart(int[] instance, int signature);
+
+ private native static int ICStop(int[] instance);
+
+ private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, int[] selectionStart,
+ int[] selectionEnd);
}
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
index 8da71fe..54658c0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoder.java
@@ -32,83 +32,73 @@ import net.wotonomy.foundation.xml.XMLDecoder;
import org.xml.sax.SAXException;
/**
-* An implementation of XMLDecoder that reads objects from
-* XMLRPC format.
-* This implementation is not thread-safe, so a new instances
-* should be created to accomodate multiple threads.
-*/
-public class XMLRPCDecoder implements XMLDecoder
-{
- XMLRPCDecoderHelper helper = new XMLRPCDecoderHelper();
-
- /**
- * Decodes an object in XML-RPC format from the specified input stream.
- * @param anInputStream The input stream from which to read.
- * The stream will be read fully.
- * @param aDescription A description to accompany error messages
- * for the stream, typically a file name.
- * @param aURL A URL against which relative references within the
- * XML will be resolved.
- * @return The object that was constructed from the XML content,
- * or null if no object could be constructed.
- */
- public Object decode(
- InputStream anInputStream, String aDescription, URL aURL )
- {
- Object result = null;
-
- try {
- SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
- sparser.parse(anInputStream,helper,aURL.toExternalForm());
- result = helper.getResult();
- } catch (ParserConfigurationException e) {
- throw new WotonomyException("Problem in parser configuration", e );
- } catch (IOException e) {
- throw new WotonomyException("IOException thrown while parsing", e );
- } catch (SAXException e) {
- throw new WotonomyException("SAXException thrown while parsing", e );
- }
- helper.reset();
- return result;
- }
+ * An implementation of XMLDecoder that reads objects from XMLRPC format. This
+ * implementation is not thread-safe, so a new instances should be created to
+ * accomodate multiple threads.
+ */
+public class XMLRPCDecoder implements XMLDecoder {
+ XMLRPCDecoderHelper helper = new XMLRPCDecoderHelper();
+
+ /**
+ * Decodes an object in XML-RPC format from the specified input stream.
+ *
+ * @param anInputStream The input stream from which to read. The stream will be
+ * read fully.
+ * @param aDescription A description to accompany error messages for the
+ * stream, typically a file name.
+ * @param aURL A URL against which relative references within the XML
+ * will be resolved.
+ * @return The object that was constructed from the XML content, or null if no
+ * object could be constructed.
+ */
+ public Object decode(InputStream anInputStream, String aDescription, URL aURL) {
+ Object result = null;
+
+ try {
+ SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
+ sparser.parse(anInputStream, helper, aURL.toExternalForm());
+ result = helper.getResult();
+ } catch (ParserConfigurationException e) {
+ throw new WotonomyException("Problem in parser configuration", e);
+ } catch (IOException e) {
+ throw new WotonomyException("IOException thrown while parsing", e);
+ } catch (SAXException e) {
+ throw new WotonomyException("SAXException thrown while parsing", e);
+ }
+ helper.reset();
+ return result;
+ }
+
+ /**
+ * Decodes an XML-RPC message from the specified input stream. Stand-alone
+ * values not wrapped in "methodCall" or "param" tags will be treated as a
+ * response.
+ *
+ * @param anInputStream The input stream from which to read. The stream will be
+ * read fully.
+ * @param aReceiver an XMLRPCReceiver that will be invoked with the
+ * appropriate method: request, response, or fault.
+ */
+ public void decode(InputStream anInputStream, XMLRPCReceiver aReceiver) {
+ try {
+ SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
+ sparser.parse(anInputStream, helper);
- /**
- * Decodes an XML-RPC message from the specified input stream.
- * Stand-alone values not wrapped in "methodCall" or "param"
- * tags will be treated as a response.
- * @param anInputStream The input stream from which to read.
- * The stream will be read fully.
- * @param aReceiver an XMLRPCReceiver that will be invoked with
- * the appropriate method: request, response, or fault.
- */
- public void decode(
- InputStream anInputStream, XMLRPCReceiver aReceiver )
- {
- try
- {
- SAXParser sparser = SAXParserFactory.newInstance().newSAXParser();
- sparser.parse(anInputStream,helper);
-
- if ( helper.isRequest() )
- {
- aReceiver.request( helper.getMethodName(), helper.getParameters() );
- }
- else
- if ( helper.isFault() )
- {
- aReceiver.fault( helper.getFaultCode(), helper.getFaultString() );
- }
- else // all else is considered a response
- {
- aReceiver.response( helper.getResult() );
- }
- } catch (ParserConfigurationException e) {
- throw new WotonomyException("Problem in parser configuration", e );
- } catch (IOException e) {
- throw new WotonomyException("IOException thrown while parsing", e );
- } catch (SAXException e) {
- throw new WotonomyException("SAXException thrown while parsing", e );
- }
- helper.reset();
- }
+ if (helper.isRequest()) {
+ aReceiver.request(helper.getMethodName(), helper.getParameters());
+ } else if (helper.isFault()) {
+ aReceiver.fault(helper.getFaultCode(), helper.getFaultString());
+ } else // all else is considered a response
+ {
+ aReceiver.response(helper.getResult());
+ }
+ } catch (ParserConfigurationException e) {
+ throw new WotonomyException("Problem in parser configuration", e);
+ } catch (IOException e) {
+ throw new WotonomyException("IOException thrown while parsing", e);
+ } catch (SAXException e) {
+ throw new WotonomyException("SAXException thrown while parsing", e);
+ }
+ helper.reset();
+ }
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
index 2368672..0806d88 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
@@ -38,77 +38,64 @@ import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
-* Used by XMLDecoder to implement the necessary interfaces
-* required by the jclark xp parser.
-* This class is not thread safe.
-*/
-class XMLRPCDecoderHelper extends DefaultHandler
-{
- protected final Object nilMarker = new Object();
- protected Stack valueStack;
- protected String methodName;
- protected int faultCode;
- protected String faultString;
- protected List parameters;
- protected StringBuffer cdataBuffer;
-
-
-
- public XMLRPCDecoderHelper()
- {
- valueStack = new Stack();
- parameters = new LinkedList();
- cdataBuffer = new StringBuffer();
- reset();
- }
-
- public void reset()
- {
- valueStack.clear();
- parameters.clear();
- cdataBuffer.setLength( 0 );
- methodName = null;
- faultCode = 0;
- faultString = null;
- }
-
- public boolean isRequest()
- {
- return ( methodName != null );
- }
-
- public boolean isResponse()
- {
- return ( methodName == null );
- }
-
- public boolean isFault()
- {
- // faults are responses
- return ( isResponse() ) && ( faultString != null );
- }
-
- public int getFaultCode()
- {
- return faultCode;
- }
-
- public String getFaultString()
- {
- return faultString;
- }
-
- public String getMethodName()
- {
- return methodName;
- }
-
- public Object[] getParameters()
- {
- return parameters.toArray();
- }
-
- public void endDocument() throws SAXException {
+ * Used by XMLDecoder to implement the necessary interfaces required by the
+ * jclark xp parser. This class is not thread safe.
+ */
+class XMLRPCDecoderHelper extends DefaultHandler {
+ protected final Object nilMarker = new Object();
+ protected Stack valueStack;
+ protected String methodName;
+ protected int faultCode;
+ protected String faultString;
+ protected List parameters;
+ protected StringBuffer cdataBuffer;
+
+ public XMLRPCDecoderHelper() {
+ valueStack = new Stack();
+ parameters = new LinkedList();
+ cdataBuffer = new StringBuffer();
+ reset();
+ }
+
+ public void reset() {
+ valueStack.clear();
+ parameters.clear();
+ cdataBuffer.setLength(0);
+ methodName = null;
+ faultCode = 0;
+ faultString = null;
+ }
+
+ public boolean isRequest() {
+ return (methodName != null);
+ }
+
+ public boolean isResponse() {
+ return (methodName == null);
+ }
+
+ public boolean isFault() {
+ // faults are responses
+ return (isResponse()) && (faultString != null);
+ }
+
+ public int getFaultCode() {
+ return faultCode;
+ }
+
+ public String getFaultString() {
+ return faultString;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public Object[] getParameters() {
+ return parameters.toArray();
+ }
+
+ public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
@@ -118,47 +105,40 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.startDocument();
reset();
}
-
- public Object getResult()
- {
- if ( valueStack.empty() ) return null;
- Object result = valueStack.peek();
- if ( result == nilMarker ) result = null;
- return result;
- }
-
-
+
+ public Object getResult() {
+ if (valueStack.empty())
+ return null;
+ Object result = valueStack.peek();
+ if (result == nilMarker)
+ result = null;
+ return result;
+ }
+
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
- if ( XMLRPCEncoder.VALUE.equals( localName ) )
- {
- ValueMarker marker = new ValueMarker();
- String classname = attributes.getValue( uri, XMLRPCEncoder.CLASS );
- if ( classname != null )
- {
- try
- {
- Class c = Class.forName( classname );
- if ( c != null )
- {
- marker.setMarkerClass( c );
- }
- }
- catch ( Exception exc )
- {
- System.out.println( "XMLRPCDecoderHelper.startElement: " +
- "Can't find class: " + classname );
- }
- }
- valueStack.push( marker );
- }
+ if (XMLRPCEncoder.VALUE.equals(localName)) {
+ ValueMarker marker = new ValueMarker();
+ String classname = attributes.getValue(uri, XMLRPCEncoder.CLASS);
+ if (classname != null) {
+ try {
+ Class c = Class.forName(classname);
+ if (c != null) {
+ marker.setMarkerClass(c);
+ }
+ } catch (Exception exc) {
+ System.out.println("XMLRPCDecoderHelper.startElement: " + "Can't find class: " + classname);
+ }
+ }
+ valueStack.push(marker);
+ }
}
-
- public void characters(char[] ch, int start, int length) throws SAXException {
+
+ public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
- char[] someChars = new char[((start+length)<=ch.length) ? length : ch.length-start];
- for (int i = 0; i < someChars.length; i++ ) {
- someChars[i] = ch[start+i];
+ char[] someChars = new char[((start + length) <= ch.length) ? length : ch.length - start];
+ for (int i = 0; i < someChars.length; i++) {
+ someChars[i] = ch[start + i];
}
cdataBuffer.append(someChars);
}
@@ -166,231 +146,140 @@ class XMLRPCDecoderHelper extends DefaultHandler
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
- // if any cdata is buffered or if string value
- if ( ( XMLRPCEncoder.STRING.equals( localName ) )
- || ( cdataBuffer.length() > 0 ) )
- {
- // push value on the stack
- valueStack.push( cdataBuffer.toString() );
- cdataBuffer.setLength( 0 );
- }
-
- if ( XMLRPCEncoder.VALUE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
+ // if any cdata is buffered or if string value
+ if ((XMLRPCEncoder.STRING.equals(localName)) || (cdataBuffer.length() > 0)) {
+ // push value on the stack
+ valueStack.push(cdataBuffer.toString());
+ cdataBuffer.setLength(0);
+ }
+
+ if (XMLRPCEncoder.VALUE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
// ValueMarker marker = (ValueMarker) valueStack.pop();
- ValueMarker marker = null;
- Object markerValue = valueStack.pop();
- if ( markerValue instanceof ValueMarker )
- {
- marker = (ValueMarker) markerValue;
- }
- else
- {
- throw new WotonomyException( "Expected value marker, found"
- + markerValue.getClass() + " : " + markerValue );
- }
-
+ ValueMarker marker = null;
+ Object markerValue = valueStack.pop();
+ if (markerValue instanceof ValueMarker) {
+ marker = (ValueMarker) markerValue;
+ } else {
+ throw new WotonomyException(
+ "Expected value marker, found" + markerValue.getClass() + " : " + markerValue);
+ }
+
//System.out.println( "getMarkerClass: " + marker.getMarkerClass() + " : " + value );
//System.out.println( valueStack );
- if ( marker.getMarkerClass() != null )
- {
- // apply introspection
- if ( value instanceof Map )
- {
- Map map = (Map)value;
- Map.Entry entry;
- value = marker.getMarkerClass().newInstance();
- Iterator it = map.entrySet().iterator();
- Object entryValue;
- while( it.hasNext() )
- {
- entry = (Map.Entry) it.next();
- entryValue = entry.getValue();
- if ( entryValue == nilMarker ) entryValue = null;
- Introspector.set(
- value, entry.getKey().toString(), entryValue );
- }
- }
- if ( ! ( value.getClass().equals( marker.getMarkerClass() ) ) )
- {
- Object converted =
- ValueConverter.convertObjectToClass(
- value, marker.getMarkerClass() );
- if ( converted != null )
- {
- value = converted;
- }
- }
- }
- }
- catch ( Exception exc )
- {
- // fall back on unconverted value
- }
-
- valueStack.push( value );
+ if (marker.getMarkerClass() != null) {
+ // apply introspection
+ if (value instanceof Map) {
+ Map map = (Map) value;
+ Map.Entry entry;
+ value = marker.getMarkerClass().newInstance();
+ Iterator it = map.entrySet().iterator();
+ Object entryValue;
+ while (it.hasNext()) {
+ entry = (Map.Entry) it.next();
+ entryValue = entry.getValue();
+ if (entryValue == nilMarker)
+ entryValue = null;
+ Introspector.set(value, entry.getKey().toString(), entryValue);
+ }
+ }
+ if (!(value.getClass().equals(marker.getMarkerClass()))) {
+ Object converted = ValueConverter.convertObjectToClass(value, marker.getMarkerClass());
+ if (converted != null) {
+ value = converted;
+ }
+ }
+ }
+ } catch (Exception exc) {
+ // fall back on unconverted value
+ }
+
+ valueStack.push(value);
// System.out.println( "convertedValue: " + value + "("+ value.getClass() +")" );
- }
- else
- if ( XMLRPCEncoder.MEMBER.equals( localName ) ) // Map.Entry
- {
- // leave key and value to be handled by struct
- }
- else
- if ( XMLRPCEncoder.STRUCT.equals( localName ) ) // write Entries to map or object
- {
- // write values to array (reverse the order)
- Object value;
- Map map = new HashMap();
- while ( ( ! valueStack.empty() )
- && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
- {
- value = valueStack.pop();
- map.put( valueStack.pop(), value );
- }
- // push the list on the stack
- valueStack.push( map );
- }
- else
- if ( XMLRPCEncoder.ARRAY.equals( localName ) )
- {
+ } else if (XMLRPCEncoder.MEMBER.equals(localName)) // Map.Entry
+ {
+ // leave key and value to be handled by struct
+ } else if (XMLRPCEncoder.STRUCT.equals(localName)) // write Entries to map or object
+ {
+ // write values to array (reverse the order)
+ Object value;
+ Map map = new HashMap();
+ while ((!valueStack.empty()) && (!(valueStack.peek() instanceof ValueMarker))) {
+ value = valueStack.pop();
+ map.put(valueStack.pop(), value);
+ }
+ // push the list on the stack
+ valueStack.push(map);
+ } else if (XMLRPCEncoder.ARRAY.equals(localName)) {
//System.out.println( "ended ARRAY: " + valueStack.size() );
- // write values to array (reverse the order)
- Object value;
- LinkedList list = new LinkedList();
- while ( ( ! valueStack.empty() )
- && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
- {
- value = valueStack.pop();
- if ( value == nilMarker ) value = null;
- list.addFirst( value );
- }
- // push the list on the stack
- valueStack.push( list );
- }
- else
- if ( XMLRPCEncoder.INT.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Integer( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.I4.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Integer( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.NIL.equals( localName ) )
- {
- valueStack.push( nilMarker );
- }
- else
- if ( XMLRPCEncoder.DOUBLE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- new Double( value.toString() ) );
- }
- catch ( NumberFormatException exc )
- {
- throw new WotonomyException(
- "Invalid double format: " + value.toString() );
- }
- }
- else
- if ( XMLRPCEncoder.DATE.equals( localName ) )
- {
- Object value = valueStack.pop();
- try
- {
- valueStack.push(
- XMLRPCEncoder.DATEFORMAT8601.parseObject(
- value.toString() ) );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Invalid date format: " + value );
- }
- }
- else
- if ( XMLRPCEncoder.BOOLEAN.equals( localName ) )
- {
- Object value = valueStack.pop();
- if ( XMLRPCEncoder.TRUE.equals( value ) )
- {
- valueStack.push( Boolean.TRUE );
- }
- else
- if ( XMLRPCEncoder.FALSE.equals( value ) )
- {
- valueStack.push( Boolean.FALSE );
- }
- else
- {
- throw new WotonomyException(
- "Invalid boolean format: " + value );
- }
- }
- else
- if ( XMLRPCEncoder.BASE64.equals( localName ) )
- {
- throw new WotonomyException( "Not implemented yet." );
- }
- else
- if ( XMLRPCEncoder.FAULT.equals( localName ) )
- {
- Map faultMap = (Map) valueStack.pop();
- try
- {
- faultCode = ((Integer)
- faultMap.get( XMLRPCEncoder.FAULTCODE )).intValue();
- faultString = (String) faultMap.get( XMLRPCEncoder.FAULTSTRING );
- }
- catch ( Exception exc )
- {
- throw new WotonomyException(
- "Invalid fault format: " + faultMap );
- }
- }
- else
- if ( XMLRPCEncoder.METHODNAME.equals( localName ) )
- {
- methodName = (String) valueStack.pop();
- }
- else
- if ( XMLRPCEncoder.PARAM.equals( localName ) )
- {
- //NOTE: this leaves the parameter on the stack
- parameters.add( getResult() );
- }
- }
-
-
+ // write values to array (reverse the order)
+ Object value;
+ LinkedList list = new LinkedList();
+ while ((!valueStack.empty()) && (!(valueStack.peek() instanceof ValueMarker))) {
+ value = valueStack.pop();
+ if (value == nilMarker)
+ value = null;
+ list.addFirst(value);
+ }
+ // push the list on the stack
+ valueStack.push(list);
+ } else if (XMLRPCEncoder.INT.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Integer(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.I4.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Integer(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.NIL.equals(localName)) {
+ valueStack.push(nilMarker);
+ } else if (XMLRPCEncoder.DOUBLE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(new Double(value.toString()));
+ } catch (NumberFormatException exc) {
+ throw new WotonomyException("Invalid double format: " + value.toString());
+ }
+ } else if (XMLRPCEncoder.DATE.equals(localName)) {
+ Object value = valueStack.pop();
+ try {
+ valueStack.push(XMLRPCEncoder.DATEFORMAT8601.parseObject(value.toString()));
+ } catch (Exception exc) {
+ throw new WotonomyException("Invalid date format: " + value);
+ }
+ } else if (XMLRPCEncoder.BOOLEAN.equals(localName)) {
+ Object value = valueStack.pop();
+ if (XMLRPCEncoder.TRUE.equals(value)) {
+ valueStack.push(Boolean.TRUE);
+ } else if (XMLRPCEncoder.FALSE.equals(value)) {
+ valueStack.push(Boolean.FALSE);
+ } else {
+ throw new WotonomyException("Invalid boolean format: " + value);
+ }
+ } else if (XMLRPCEncoder.BASE64.equals(localName)) {
+ throw new WotonomyException("Not implemented yet.");
+ } else if (XMLRPCEncoder.FAULT.equals(localName)) {
+ Map faultMap = (Map) valueStack.pop();
+ try {
+ faultCode = ((Integer) faultMap.get(XMLRPCEncoder.FAULTCODE)).intValue();
+ faultString = (String) faultMap.get(XMLRPCEncoder.FAULTSTRING);
+ } catch (Exception exc) {
+ throw new WotonomyException("Invalid fault format: " + faultMap);
+ }
+ } else if (XMLRPCEncoder.METHODNAME.equals(localName)) {
+ methodName = (String) valueStack.pop();
+ } else if (XMLRPCEncoder.PARAM.equals(localName)) {
+ // NOTE: this leaves the parameter on the stack
+ parameters.add(getResult());
+ }
+ }
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
@@ -423,12 +312,14 @@ class XMLRPCDecoderHelper extends DefaultHandler
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
- // NOTE: Sun accepted an incompatible api difference. The (false) should be tossed by hotspot
+ // NOTE: Sun accepted an incompatible api difference. The (false) should be
+ // tossed by hotspot
try {
- if (false) throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
- return super.resolveEntity(publicId, systemId);
+ if (false)
+ throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
+ return super.resolveEntity(publicId, systemId);
} catch (IOException e) {
- throw new SAXException(e.getClass().getName() + " thrown while resolving entity.",e);
+ throw new SAXException(e.getClass().getName() + " thrown while resolving entity.", e);
}
}
@@ -442,14 +333,13 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.skippedEntity(name);
}
-
-
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub
super.startPrefixMapping(prefix, uri);
}
- public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
+ public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)
+ throws SAXException {
// TODO Auto-generated method stub
super.unparsedEntityDecl(name, publicId, systemId, notationName);
}
@@ -459,76 +349,65 @@ class XMLRPCDecoderHelper extends DefaultHandler
super.warning(e);
}
-
- // marker class
-
- private class ValueMarker
- {
- private Class theClass;
-
- public ValueMarker()
- {
- theClass = null;
- }
-
- public void setMarkerClass( Class aClass )
- {
- theClass = aClass;
- }
-
- public Class getMarkerClass()
- {
- return theClass;
- }
-
- public String toString()
- {
- return "[ValueMarker: " + theClass + "]";
- }
- }
-
+ // marker class
+
+ private class ValueMarker {
+ private Class theClass;
+
+ public ValueMarker() {
+ theClass = null;
+ }
+
+ public void setMarkerClass(Class aClass) {
+ theClass = aClass;
+ }
+
+ public Class getMarkerClass() {
+ return theClass;
+ }
+
+ public String toString() {
+ return "[ValueMarker: " + theClass + "]";
+ }
+ }
+
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:03 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:03 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.7 2003/08/06 23:07:53 chochos
- * general code cleanup (mostly, removing unused imports)
+ * Revision 1.7 2003/08/06 23:07:53 chochos general code cleanup (mostly,
+ * removing unused imports)
*
- * Revision 1.6 2001/03/03 15:16:35 mpowers
- * Fixed bug in decoding empty strings: string handler did nothing and
- * empty cdatas were ignored, so no value was placed on the stack.
+ * Revision 1.6 2001/03/03 15:16:35 mpowers Fixed bug in decoding empty strings:
+ * string handler did nothing and empty cdatas were ignored, so no value was
+ * placed on the stack.
*
- * Revision 1.5 2001/02/17 16:52:06 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.5 2001/02/17 16:52:06 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.4 2001/02/09 15:51:39 mpowers
- * Fixed a pernicious bug: I was using the character event entirely
- * incorrectly, but the problem only exhibited itself with large data
- * and even then only randomly. Now using a string buffer.
+ * Revision 1.4 2001/02/09 15:51:39 mpowers Fixed a pernicious bug: I was using
+ * the character event entirely incorrectly, but the problem only exhibited
+ * itself with large data and even then only randomly. Now using a string
+ * buffer.
*
- * Revision 1.3 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.3 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:39 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:39 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:48 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
index 3a63d45..d84f164 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCEncoder.java
@@ -43,484 +43,398 @@ import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
-* An implementation of XMLEncoder that serializes objects
-* into XMLRPC format, which is found at http://xmlrpc.com/spec.
-* We extend that standard only in that we add a "class"
-* attribute to the "value" tag, so that a java-based decoder
-* can more closely reconstruct the original java data structure.
-* The class attribute can be safely ignored by clients.
-* This implementation is not thread-safe, so a new instances
-* should be created to accomodate multiple threads.
-*/
-public class XMLRPCEncoder implements XMLEncoder
-{
- public static final String METHODCALL = "methodCall";
- public static final String METHODNAME = "methodName";
- public static final String METHODRESPONSE = "methodResponse";
- public static final String PARAMS = "params";
- public static final String PARAM = "param";
- public static final String FAULT = "fault";
- public static final String FAULTCODE = "faultCode";
- public static final String FAULTSTRING = "faultString";
-
- public static final String VALUE = "value";
- public static final String CLASS = "class";
-
- public static final String STRUCT = "struct";
- public static final String MEMBER = "member";
- public static final String NAME = "name";
-
- public static final String ARRAY = "array";
- public static final String DATA = "data";
-
- public static final String NIL = "nil";
- public static final String INT = "int";
- public static final String I4 = "i4";
- public static final String BOOLEAN = "boolean";
- public static final String STRING = "string";
- public static final String DOUBLE = "double";
- public static final String DATE = "dateTime.iso8601";
- public static final String BASE64 = "base64";
-
- public static final String TRUE = "1";
- public static final String FALSE = "0";
-
- public static final Format DATEFORMAT8601 =
- new SimpleDateFormat( "yyyyMMdd'T'HHmmss" );
-
- /**
- * Encodes an object to the specified output stream as XML.
- * @param anObject The object to be serialized to XML format.
- * @param anOutputStream The output stream to which the object
- * will be written.
- */
- public void encode( Object anObject, OutputStream anOutputStream )
- {
- try
- {
-
- //XMLWriter writer = new UTF8XMLWriter( anOutputStream );
- RPCXMLWriter writer = new RPCXMLWriter(anOutputStream,OutputFormat.createCompactFormat());
- writeValueToXMLWriter( anObject, writer );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
- }
-
- /**
- * Encodes a method request in XML-RPC format in a "methodCall" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aMethodName The method name to appear in the "methodName" tag.
- * @param aParameterArray An array of objects, each of which will be
- * encoded as values enclosed in a "param" tag, all of which will be
- * enclosed in a "params" tag.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeRequest(
- String aMethodName, Object[] aParameterArray,
- OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat());
- writer.processingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
- writer.startElement( METHODCALL );
- writer.startElement( METHODNAME );
- writer.write( aMethodName );
- writer.endElement( METHODNAME );
- writer.startElement( PARAMS );
- for ( int i = 0; i < aParameterArray.length; i++ )
- {
- writer.startElement( PARAM );
- writeValueToXMLWriter( aParameterArray[i], writer );
- writer.endElement( PARAM );
- }
- writer.endElement( PARAMS );
- writer.endElement( METHODCALL );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Encodes a method response in XML-RPC format in a "methodResponse" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aResult A object which will be
- * encoded as values enclosed in a "param" tag, all of which will be
- * enclosed in a "params" tag.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeResponse(
- Object aResult, OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat() );
- writer.processingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
- writer.startElement( METHODRESPONSE );
- writer.startElement( PARAMS );
- writer.startElement( PARAM );
- writeValueToXMLWriter( aResult, writer );
- writer.endElement( PARAM );
- writer.endElement( PARAMS );
- writer.endElement( METHODRESPONSE );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Encodes a fault response in XML-RPC format in a "methodResponse" tag,
- * and writes the XML to the specified output stream.
- * This method only writes XML: the caller is responsible for first
- * generating the appropriate header, if any, which should set
- * the content type as "text/xml" and the content length as appropriate.
- * The caller is also responsible for writing the xml version tag.
- * @param aFaultCode An application-defined error code.
- * @param aFaultString A human-readable error description.
- * @param anOutputStream The stream to which the XML will be written.
- */
- public void encodeFault(
- int aFaultCode, String aFaultString, OutputStream anOutputStream )
- {
- try
- {
- RPCXMLWriter writer = new RPCXMLWriter( anOutputStream, OutputFormat.createCompactFormat() );
- writer.processingInstruction( "xml", "version=\"1.0\"" );
- writer.startElement( METHODRESPONSE );
- writer.startElement( FAULT );
- writer.startElement( VALUE );
- writer.startElement( STRUCT );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( FAULTCODE );
- writer.endElement( NAME );
- writer.startElement( VALUE );
- writer.startElement( INT );
- writer.write( new Integer( aFaultCode ).toString() );
- writer.endElement( INT );
- writer.endElement( VALUE );
- writer.endElement( MEMBER );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( FAULTSTRING );
- writer.endElement( NAME );
- writer.startElement( VALUE );
- writer.startElement( STRING );
- writer.write( aFaultString );
- writer.endElement( STRING );
- writer.endElement( VALUE );
- writer.endElement( MEMBER );
-
- writer.endElement( STRUCT );
- writer.endElement( VALUE );
- writer.endElement( FAULT );
- writer.endElement( METHODRESPONSE );
- writer.flush();
- }
- catch ( Exception exc )
- {
- throw new WotonomyException( exc );
- }
-
- //TODO: should this return the content-length?
- }
-
- /**
- * Performs the actual writing of the file to XML.
- */
- private void writeValueToXMLWriter(
- Object anObject, RPCXMLWriter writer )
- {
- try
- {
-
-
- if ( anObject == null )
- {
- writer.startElement( VALUE );
- // write nil for null
- Element nill = new NonLazyElement(NIL);
- writer.write(nill);
- }
- else
- if ( anObject instanceof Collection )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- // write items in the order we get them from the iterator
-
- writer.startElement( ARRAY );
- writer.startElement( DATA );
- Iterator it = ((Collection)anObject).iterator();
- while ( it.hasNext() )
- {
- writeValueToXMLWriter( it.next(), writer );
- }
- writer.endElement( DATA );
- writer.endElement( ARRAY );
-
- }
- else
- if ( anObject instanceof Map )
- {
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- // write items in the order we get them from the iterator
- //FIXME: The method-based properties are being ignored!
-
- Map.Entry entry;
- writer.startElement( STRUCT );
- writer.startElement( MEMBER );
- Iterator it = ((Map)anObject).entrySet().iterator();
- while ( it.hasNext() )
- {
- entry = (Map.Entry) it.next();
- writer.startElement( NAME );
- writeValueToXMLWriter( entry.getKey(), writer );
- writer.endElement( NAME );
- writeValueToXMLWriter( entry.getValue(), writer );
- }
- writer.endElement( MEMBER );
- writer.endElement( STRUCT );
- }
- else // not a collection
- {
- // check for primitive types
- if ( anObject instanceof String )
- {
- writer.startElement( VALUE );
-
- writer.startElement( STRING );
- writer.write( anObject.toString() );
- writer.endElement( STRING );
- }
- else
- if ( anObject instanceof StringBuffer )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( STRING );
- writer.write( anObject.toString() );
- writer.endElement( STRING );
- }
- else
- if ( anObject instanceof Number )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- if ( ( anObject instanceof Double )
- || ( anObject instanceof Float ) )
- {
- writer.startElement( DOUBLE );
- writer.write( anObject.toString() );
- writer.endElement( DOUBLE );
- }
- else
- {
- writer.startElement( INT );
- writer.write( anObject.toString() );
- writer.endElement( INT );
- }
- }
- else
- if ( anObject instanceof Date )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( DATE );
- writer.write( DATEFORMAT8601.format( anObject ) );
- writer.endElement( DATE );
- }
- else
- if ( anObject instanceof Boolean )
- {
- writer.startElement( BOOLEAN );
- if ( ((Boolean)anObject).booleanValue() )
- {
- writer.write( "1" );
- }
- else
- {
- writer.write( "0" );
- }
- writer.endElement( BOOLEAN );
- }
- else
- if ( anObject.getClass().isArray() )
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- writer.startElement( ARRAY );
- writer.startElement( DATA );
-
- int length = Array.getLength( anObject );
- for ( int i = 0; i < length; i++ )
- {
- writeValueToXMLWriter( Array.get( anObject, i ), writer );
- }
-
- writer.endElement( DATA );
- writer.endElement( ARRAY );
- }
- else // not primitive or collection, treat as struct
- {
- // write class so we can restore if possible
- AttributesImpl a = new AttributesImpl();
- a.addAttribute(null, CLASS, null, null, anObject.getClass().getName() );
-
- writer.startElement( VALUE, a );
-
- List readProperties = new ArrayList();
- String[] read = Introspector.getReadPropertiesForObject( anObject );
- for ( int i = 0; i < read.length; i++ )
- {
- readProperties.add( read[i] );
- }
-
- List properties = new ArrayList();
- String[] write = Introspector.getWritePropertiesForObject( anObject );
- for ( int i = 0; i < write.length; i++ )
- {
- properties.add( write[i] );
- }
-
- // only use readable properties
- properties.retainAll( readProperties );
-
+ * An implementation of XMLEncoder that serializes objects into XMLRPC format,
+ * which is found at http://xmlrpc.com/spec. We extend that standard only in
+ * that we add a "class" attribute to the "value" tag, so that a java-based
+ * decoder can more closely reconstruct the original java data structure. The
+ * class attribute can be safely ignored by clients. This implementation is not
+ * thread-safe, so a new instances should be created to accomodate multiple
+ * threads.
+ */
+public class XMLRPCEncoder implements XMLEncoder {
+ public static final String METHODCALL = "methodCall";
+ public static final String METHODNAME = "methodName";
+ public static final String METHODRESPONSE = "methodResponse";
+ public static final String PARAMS = "params";
+ public static final String PARAM = "param";
+ public static final String FAULT = "fault";
+ public static final String FAULTCODE = "faultCode";
+ public static final String FAULTSTRING = "faultString";
+
+ public static final String VALUE = "value";
+ public static final String CLASS = "class";
+
+ public static final String STRUCT = "struct";
+ public static final String MEMBER = "member";
+ public static final String NAME = "name";
+
+ public static final String ARRAY = "array";
+ public static final String DATA = "data";
+
+ public static final String NIL = "nil";
+ public static final String INT = "int";
+ public static final String I4 = "i4";
+ public static final String BOOLEAN = "boolean";
+ public static final String STRING = "string";
+ public static final String DOUBLE = "double";
+ public static final String DATE = "dateTime.iso8601";
+ public static final String BASE64 = "base64";
+
+ public static final String TRUE = "1";
+ public static final String FALSE = "0";
+
+ public static final Format DATEFORMAT8601 = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+
+ /**
+ * Encodes an object to the specified output stream as XML.
+ *
+ * @param anObject The object to be serialized to XML format.
+ * @param anOutputStream The output stream to which the object will be written.
+ */
+ public void encode(Object anObject, OutputStream anOutputStream) {
+ try {
+
+ // XMLWriter writer = new UTF8XMLWriter( anOutputStream );
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writeValueToXMLWriter(anObject, writer);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+ }
+
+ /**
+ * Encodes a method request in XML-RPC format in a "methodCall" tag, and writes
+ * the XML to the specified output stream. This method only writes XML: the
+ * caller is responsible for generating the appropriate header, if any, which
+ * should set the content type as "text/xml" and the content length as
+ * appropriate. The caller is also responsible for writing the xml version tag.
+ *
+ * @param aMethodName The method name to appear in the "methodName" tag.
+ * @param aParameterArray An array of objects, each of which will be encoded as
+ * values enclosed in a "param" tag, all of which will be
+ * enclosed in a "params" tag.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeRequest(String aMethodName, Object[] aParameterArray, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ writer.startElement(METHODCALL);
+ writer.startElement(METHODNAME);
+ writer.write(aMethodName);
+ writer.endElement(METHODNAME);
+ writer.startElement(PARAMS);
+ for (int i = 0; i < aParameterArray.length; i++) {
+ writer.startElement(PARAM);
+ writeValueToXMLWriter(aParameterArray[i], writer);
+ writer.endElement(PARAM);
+ }
+ writer.endElement(PARAMS);
+ writer.endElement(METHODCALL);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Encodes a method response in XML-RPC format in a "methodResponse" tag, and
+ * writes the XML to the specified output stream. This method only writes XML:
+ * the caller is responsible for generating the appropriate header, if any,
+ * which should set the content type as "text/xml" and the content length as
+ * appropriate. The caller is also responsible for writing the xml version tag.
+ *
+ * @param aResult A object which will be encoded as values enclosed in a
+ * "param" tag, all of which will be enclosed in a
+ * "params" tag.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeResponse(Object aResult, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ writer.startElement(METHODRESPONSE);
+ writer.startElement(PARAMS);
+ writer.startElement(PARAM);
+ writeValueToXMLWriter(aResult, writer);
+ writer.endElement(PARAM);
+ writer.endElement(PARAMS);
+ writer.endElement(METHODRESPONSE);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Encodes a fault response in XML-RPC format in a "methodResponse" tag, and
+ * writes the XML to the specified output stream. This method only writes XML:
+ * the caller is responsible for first generating the appropriate header, if
+ * any, which should set the content type as "text/xml" and the content length
+ * as appropriate. The caller is also responsible for writing the xml version
+ * tag.
+ *
+ * @param aFaultCode An application-defined error code.
+ * @param aFaultString A human-readable error description.
+ * @param anOutputStream The stream to which the XML will be written.
+ */
+ public void encodeFault(int aFaultCode, String aFaultString, OutputStream anOutputStream) {
+ try {
+ RPCXMLWriter writer = new RPCXMLWriter(anOutputStream, OutputFormat.createCompactFormat());
+ writer.processingInstruction("xml", "version=\"1.0\"");
+ writer.startElement(METHODRESPONSE);
+ writer.startElement(FAULT);
+ writer.startElement(VALUE);
+ writer.startElement(STRUCT);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(FAULTCODE);
+ writer.endElement(NAME);
+ writer.startElement(VALUE);
+ writer.startElement(INT);
+ writer.write(new Integer(aFaultCode).toString());
+ writer.endElement(INT);
+ writer.endElement(VALUE);
+ writer.endElement(MEMBER);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(FAULTSTRING);
+ writer.endElement(NAME);
+ writer.startElement(VALUE);
+ writer.startElement(STRING);
+ writer.write(aFaultString);
+ writer.endElement(STRING);
+ writer.endElement(VALUE);
+ writer.endElement(MEMBER);
+
+ writer.endElement(STRUCT);
+ writer.endElement(VALUE);
+ writer.endElement(FAULT);
+ writer.endElement(METHODRESPONSE);
+ writer.flush();
+ } catch (Exception exc) {
+ throw new WotonomyException(exc);
+ }
+
+ // TODO: should this return the content-length?
+ }
+
+ /**
+ * Performs the actual writing of the file to XML.
+ */
+ private void writeValueToXMLWriter(Object anObject, RPCXMLWriter writer) {
+ try {
+
+ if (anObject == null) {
+ writer.startElement(VALUE);
+ // write nil for null
+ Element nill = new NonLazyElement(NIL);
+ writer.write(nill);
+ } else if (anObject instanceof Collection) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ // write items in the order we get them from the iterator
+
+ writer.startElement(ARRAY);
+ writer.startElement(DATA);
+ Iterator it = ((Collection) anObject).iterator();
+ while (it.hasNext()) {
+ writeValueToXMLWriter(it.next(), writer);
+ }
+ writer.endElement(DATA);
+ writer.endElement(ARRAY);
+
+ } else if (anObject instanceof Map) {
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ // write items in the order we get them from the iterator
+ // FIXME: The method-based properties are being ignored!
+
+ Map.Entry entry;
+ writer.startElement(STRUCT);
+ writer.startElement(MEMBER);
+ Iterator it = ((Map) anObject).entrySet().iterator();
+ while (it.hasNext()) {
+ entry = (Map.Entry) it.next();
+ writer.startElement(NAME);
+ writeValueToXMLWriter(entry.getKey(), writer);
+ writer.endElement(NAME);
+ writeValueToXMLWriter(entry.getValue(), writer);
+ }
+ writer.endElement(MEMBER);
+ writer.endElement(STRUCT);
+ } else // not a collection
+ {
+ // check for primitive types
+ if (anObject instanceof String) {
+ writer.startElement(VALUE);
+
+ writer.startElement(STRING);
+ writer.write(anObject.toString());
+ writer.endElement(STRING);
+ } else if (anObject instanceof StringBuffer) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(STRING);
+ writer.write(anObject.toString());
+ writer.endElement(STRING);
+ } else if (anObject instanceof Number) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ if ((anObject instanceof Double) || (anObject instanceof Float)) {
+ writer.startElement(DOUBLE);
+ writer.write(anObject.toString());
+ writer.endElement(DOUBLE);
+ } else {
+ writer.startElement(INT);
+ writer.write(anObject.toString());
+ writer.endElement(INT);
+ }
+ } else if (anObject instanceof Date) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(DATE);
+ writer.write(DATEFORMAT8601.format(anObject));
+ writer.endElement(DATE);
+ } else if (anObject instanceof Boolean) {
+ writer.startElement(BOOLEAN);
+ if (((Boolean) anObject).booleanValue()) {
+ writer.write("1");
+ } else {
+ writer.write("0");
+ }
+ writer.endElement(BOOLEAN);
+ } else if (anObject.getClass().isArray()) {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ writer.startElement(ARRAY);
+ writer.startElement(DATA);
+
+ int length = Array.getLength(anObject);
+ for (int i = 0; i < length; i++) {
+ writeValueToXMLWriter(Array.get(anObject, i), writer);
+ }
+
+ writer.endElement(DATA);
+ writer.endElement(ARRAY);
+ } else // not primitive or collection, treat as struct
+ {
+ // write class so we can restore if possible
+ AttributesImpl a = new AttributesImpl();
+ a.addAttribute(null, CLASS, null, null, anObject.getClass().getName());
+
+ writer.startElement(VALUE, a);
+
+ List readProperties = new ArrayList();
+ String[] read = Introspector.getReadPropertiesForObject(anObject);
+ for (int i = 0; i < read.length; i++) {
+ readProperties.add(read[i]);
+ }
+
+ List properties = new ArrayList();
+ String[] write = Introspector.getWritePropertiesForObject(anObject);
+ for (int i = 0; i < write.length; i++) {
+ properties.add(write[i]);
+ }
+
+ // only use readable properties
+ properties.retainAll(readProperties);
+
// if ( properties.size() > 0 )
// {
- String key;
- Object value;
- Iterator it = properties.iterator();
- writer.startElement( STRUCT );
- while ( it.hasNext() )
- {
- key = (String) it.next();
- value = Introspector.get( anObject, key );
-
- writer.startElement( MEMBER );
- writer.startElement( NAME );
- writer.write( key );
- writer.endElement( NAME );
- writeValueToXMLWriter( value, writer );
- writer.endElement( MEMBER );
- }
- writer.endElement( STRUCT );
-/*
- }
- else // no properties - write a converted string
- {
- writer.startElement( STRING );
- Object converted =
- ValueConverter.convertObjectToClass( anObject, String.class );
- if ( converted != null )
- {
- writer.write( converted.toString() );
- }
- else
- {
- writer.write( anObject.toString() );
- }
- writer.endElement( STRING );
- }
-*/
- }
- }
-
- writer.endElement( VALUE );
- }
- catch ( Exception exc )
- {
- System.err.println( "XMLFileSoup.writeValueToXMLWriter: " + exc );
- exc.printStackTrace();
- }
-
- }
-/*
- public static void main( String[] argv )
- {
- System.out.println( "<test>" );
- XMLRPCEncoder encoder = new XMLRPCEncoder();
- encoder.encodeRequest( "systemObject.test", new Object[] {
- new net.wotonomy.test.TestObject(),
- new net.wotonomy.test.TestObject(),
- new net.wotonomy.test.TestObject() }, System.out );
- System.out.println();
- System.out.println();
- encoder.encodeResponse( new net.wotonomy.test.TestObject(), System.out );
- System.out.println();
- System.out.println();
- encoder.encodeFault( -1, "This is a fault.", System.out );
- System.out.println();
- System.out.println();
- System.out.println( "</test>" );
- }
-*/
-
- private class RPCXMLWriter extends XMLWriter {
+ String key;
+ Object value;
+ Iterator it = properties.iterator();
+ writer.startElement(STRUCT);
+ while (it.hasNext()) {
+ key = (String) it.next();
+ value = Introspector.get(anObject, key);
+
+ writer.startElement(MEMBER);
+ writer.startElement(NAME);
+ writer.write(key);
+ writer.endElement(NAME);
+ writeValueToXMLWriter(value, writer);
+ writer.endElement(MEMBER);
+ }
+ writer.endElement(STRUCT);
+ /*
+ * } else // no properties - write a converted string { writer.startElement(
+ * STRING ); Object converted = ValueConverter.convertObjectToClass( anObject,
+ * String.class ); if ( converted != null ) { writer.write( converted.toString()
+ * ); } else { writer.write( anObject.toString() ); } writer.endElement( STRING
+ * ); }
+ */
+ }
+ }
+
+ writer.endElement(VALUE);
+ } catch (Exception exc) {
+ System.err.println("XMLFileSoup.writeValueToXMLWriter: " + exc);
+ exc.printStackTrace();
+ }
+
+ }
+ /*
+ * public static void main( String[] argv ) { System.out.println( "<test>" );
+ * XMLRPCEncoder encoder = new XMLRPCEncoder(); encoder.encodeRequest(
+ * "systemObject.test", new Object[] { new net.wotonomy.test.TestObject(), new
+ * net.wotonomy.test.TestObject(), new net.wotonomy.test.TestObject() },
+ * System.out ); System.out.println(); System.out.println();
+ * encoder.encodeResponse( new net.wotonomy.test.TestObject(), System.out );
+ * System.out.println(); System.out.println(); encoder.encodeFault( -1,
+ * "This is a fault.", System.out ); System.out.println(); System.out.println();
+ * System.out.println( "</test>" ); }
+ */
+
+ private class RPCXMLWriter extends XMLWriter {
public RPCXMLWriter(OutputStream arg0, OutputFormat arg1) throws UnsupportedEncodingException {
super(arg0, arg1);
}
- public void endElement(String localname) throws SAXException {
+ public void endElement(String localname) throws SAXException {
super.endElement(null, localname, null);
}
public void startElement(String localname) throws SAXException {
this.startElement(localname, null);
}
+
public void startElement(String localname, Attributes attributes) throws SAXException {
this.startElement(null, localname, null, attributes);
}
- }
-
+ }
+
}
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
index 48c9e41..5848cd0 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCReceiver.java
@@ -19,54 +19,51 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.web.xml;
/**
-* A call-back interface that receives an XML-RPC transaction message.
-* Used by XMLRPCDecoder to return values from a message.
-*/
-public interface XMLRPCReceiver
-{
- /**
- * Receives an XML-RPC request.
- * @param aMethodName The method name of the request.
- * @param aParameterArray The objects contained in the request, in order.
- */
- void request( String aMethodName, Object[] aParameterArray );
-
- /**
- * Receives an XML-RPC response.
- * @param aResult The object contained in the response.
- */
- void response( Object aResult );
-
- /**
- * Receives an XML-RPC fault response.
- * @param aFaultCode The fault code contained in the response.
- * @param aFaultString The fault string contained in the response.
- */
- void fault( int aFaultCode, String aFaultString );
+ * A call-back interface that receives an XML-RPC transaction message. Used by
+ * XMLRPCDecoder to return values from a message.
+ */
+public interface XMLRPCReceiver {
+ /**
+ * Receives an XML-RPC request.
+ *
+ * @param aMethodName The method name of the request.
+ * @param aParameterArray The objects contained in the request, in order.
+ */
+ void request(String aMethodName, Object[] aParameterArray);
+
+ /**
+ * Receives an XML-RPC response.
+ *
+ * @param aResult The object contained in the response.
+ */
+ void response(Object aResult);
+
+ /**
+ * Receives an XML-RPC fault response.
+ *
+ * @param aFaultCode The fault code contained in the response.
+ * @param aFaultString The fault string contained in the response.
+ */
+ void fault(int aFaultCode, String aFaultString);
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.2 2001/02/06 14:34:23 mpowers
- * Forgot to rename the package declarations.
+ * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package
+ * declarations.
*
- * Revision 1.1 2001/02/06 14:31:19 mpowers
- * Moving XML utilities from util to xml package.
+ * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to
+ * xml package.
*
- * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:52:44 mpowers Contributing wotonomy.
*
- * Revision 1.2 2000/12/20 16:25:49 michael
- * Added log to all files.
+ * Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
index 7c1f104..599481f 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCSelector.java
@@ -32,207 +32,155 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* An NSSelector customized to invoke methods with XMLRPC
-* when a URL is passed in as the object to the invoke() method.
-* The method name and parameters will be marshalled and sent
-* as an XMLRPC request to the host specified by the URL. <br><br>
-*
-* To use this class simply as an XMLRPC client, just call
-* invoke() with a URL referencing the XMLRPC server and an
-* optional array of parameters.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class XMLRPCSelector extends NSSelector
-{
- private boolean copyStream = false;
-
- /**
- * Constructor specifying a method name.
- */
- public XMLRPCSelector (String aMethodName)
- {
- super( aMethodName, EMPTY_CLASS_ARRAY );
- }
-
- /**
- * Constructor specifying a method name and an array of parameter types.
- * When accessing XMLRPC servers, invoke() does require that the
- * specified objects match the types in the parameter type array.
- */
- public XMLRPCSelector (String aMethodName, Class[] aParameterTypeArray)
- {
- super( aMethodName, aParameterTypeArray );
- }
-
- /**
- * Invokes this selector's method on the specified object
- * using the specified parameters.
- */
- public Object invoke (Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- if ( anObject instanceof URL )
- {
- Receiver receiver = new Receiver();
- byte[] copyOfResponse = null;
- try
- {
- URLConnection cn = ((URL)anObject).openConnection();
-
- // set properties
- cn.setDoOutput(true);
- cn.setDoInput(true);
- cn.setRequestProperty(
- "content-type","text/xml");
-
- // send parameters
- OutputStream out = cn.getOutputStream();
- new XMLRPCEncoder().encodeRequest(
- name(), parameters, out );
- out.flush();
- out.close();
-
- // get response: getInputStream initiates the request
- InputStream input =
- new BufferedInputStream( cn.getInputStream() );
- if ( copyStream )
- {
- ByteArrayOutputStream byteArray =
- new ByteArrayOutputStream();
- int b;
- while ( ( b = input.read() ) != -1 )
- {
- byteArray.write( b );
- }
- copyOfResponse = byteArray.toByteArray();
- input = new ByteArrayInputStream( copyOfResponse );
- }
- new XMLRPCDecoder().decode( input, receiver );
- }
- catch ( FileNotFoundException exc )
- {
- throw new WotonomyException( "Server did not return a response." );
- }
- catch ( Exception exc )
- {
- if ( copyOfResponse != null )
- {
- System.out.println( new String( copyOfResponse ) );
- exc.printStackTrace();
- }
- throw new InvocationTargetException( exc );
- }
-
- if ( receiver.faultString == null )
- {
- return receiver.result;
- }
- else
- {
- throw new InvocationTargetException(
- new WotonomyException(
- receiver.faultCode + ": " + receiver.faultString ) );
- }
- }
-
- // else: not a URL
- return super.invoke( anObject, parameters );
+ * An NSSelector customized to invoke methods with XMLRPC when a URL is passed
+ * in as the object to the invoke() method. The method name and parameters will
+ * be marshalled and sent as an XMLRPC request to the host specified by the URL.
+ * <br>
+ * <br>
+ *
+ * To use this class simply as an XMLRPC client, just call invoke() with a URL
+ * referencing the XMLRPC server and an optional array of parameters.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class XMLRPCSelector extends NSSelector {
+ private boolean copyStream = false;
+
+ /**
+ * Constructor specifying a method name.
+ */
+ public XMLRPCSelector(String aMethodName) {
+ super(aMethodName, EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Constructor specifying a method name and an array of parameter types. When
+ * accessing XMLRPC servers, invoke() does require that the specified objects
+ * match the types in the parameter type array.
+ */
+ public XMLRPCSelector(String aMethodName, Class[] aParameterTypeArray) {
+ super(aMethodName, aParameterTypeArray);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return new XMLRPCSelector( methodName, parameterTypes ).invoke( anObject, parameters );
+ /**
+ * Invokes this selector's method on the specified object using the specified
+ * parameters.
+ */
+ public Object invoke(Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ if (anObject instanceof URL) {
+ Receiver receiver = new Receiver();
+ byte[] copyOfResponse = null;
+ try {
+ URLConnection cn = ((URL) anObject).openConnection();
+
+ // set properties
+ cn.setDoOutput(true);
+ cn.setDoInput(true);
+ cn.setRequestProperty("content-type", "text/xml");
+
+ // send parameters
+ OutputStream out = cn.getOutputStream();
+ new XMLRPCEncoder().encodeRequest(name(), parameters, out);
+ out.flush();
+ out.close();
+
+ // get response: getInputStream initiates the request
+ InputStream input = new BufferedInputStream(cn.getInputStream());
+ if (copyStream) {
+ ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+ int b;
+ while ((b = input.read()) != -1) {
+ byteArray.write(b);
+ }
+ copyOfResponse = byteArray.toByteArray();
+ input = new ByteArrayInputStream(copyOfResponse);
+ }
+ new XMLRPCDecoder().decode(input, receiver);
+ } catch (FileNotFoundException exc) {
+ throw new WotonomyException("Server did not return a response.");
+ } catch (Exception exc) {
+ if (copyOfResponse != null) {
+ System.out.println(new String(copyOfResponse));
+ exc.printStackTrace();
+ }
+ throw new InvocationTargetException(exc);
+ }
+
+ if (receiver.faultString == null) {
+ return receiver.result;
+ } else {
+ throw new InvocationTargetException(
+ new WotonomyException(receiver.faultCode + ": " + receiver.faultString));
+ }
+ }
+
+ // else: not a URL
+ return super.invoke(anObject, parameters);
}
- public static Object invoke
- (String methodName, Object anObject)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY );
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object[] parameters)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return new XMLRPCSelector(methodName, parameterTypes).invoke(anObject, parameters);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object aParameter)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { aParameter } );
+ public static Object invoke(String methodName, Object anObject)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY);
}
- public static Object invoke
- (String methodName, Class[] parameterTypes,
- Object anObject, Object p1, Object p2)
- throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException, NoSuchMethodException
- {
- return XMLRPCSelector.invoke(
- methodName, parameterTypes, anObject, new Object[] { p1, p2 } );
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object aParameter)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, parameterTypes, anObject, new Object[] { aParameter });
+ }
+
+ public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object p1, Object p2)
+ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return XMLRPCSelector.invoke(methodName, parameterTypes, anObject, new Object[] { p1, p2 });
+ }
+
+ private class Receiver implements XMLRPCReceiver {
+ public Object result;
+ public int faultCode;
+ public String faultString;
+
+ public Receiver() {
+ result = null;
+ faultCode = -1;
+ faultString = null;
+ }
+
+ public void request(String aMethodName, Object[] aParameterArray) {
+ throw new WotonomyException("Invalid response: Expected response but received request.");
+ }
+
+ public void response(Object aResult) {
+ result = aResult;
+ faultCode = -1;
+ faultString = null;
+ }
+
+ public void fault(int aFaultCode, String aFaultString) {
+ result = null;
+ faultCode = aFaultCode;
+ faultString = aFaultString;
+ }
}
-
- private class Receiver implements XMLRPCReceiver
- {
- public Object result;
- public int faultCode;
- public String faultString;
-
- public Receiver()
- {
- result = null;
- faultCode = -1;
- faultString = null;
- }
-
- public void request(
- String aMethodName, Object[] aParameterArray )
- {
- throw new WotonomyException(
- "Invalid response: Expected response but received request." );
- }
-
- public void response(
- Object aResult )
- {
- result = aResult;
- faultCode = -1;
- faultString = null;
- }
-
- public void fault(
- int aFaultCode, String aFaultString)
- {
- result = null;
- faultCode = aFaultCode;
- faultString = aFaultString;
- }
- }
-
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:03 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:03 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.1 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
*
*/
-
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
index a9981a4..94b5680 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java
@@ -34,250 +34,195 @@ import net.wotonomy.foundation.NSSelector;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* A servlet that can make any java object into an XML-RPC server.
-* Simply pass in the object to the constructor and XML-RPC requests
-* to this servlet will call the appropriate methods and convert
-* the results to an XML-RPC response. <br><br>
-*
-* Depending on your servlet container, it may be necessary to
-* create a simple subclass that creates your handler object
-* in its constructor and then calls setHandler(). <br><br>
-*
-* Responses are in the specification's standard response format.<br><br>
-*
-* Faults are returned if any exception is thrown in the method,
-* or if the specified method is not found on the object.
-* The fault string is the toString value of the exception,
-* and the fault code is the hasCode value of the exception. <br><br>
-*
-* Remember that this servlet only responds to POSTs,
-* per the XML-RPC spec.
-*/
-public class XMLRPCServlet extends HttpServlet
-{
- protected Object handler;
- protected boolean synchronizing;
- private Hashtable selectorCache = new Hashtable(); // thread safe
- private boolean copyStream = false;
-
- /**
- * Default constructor initializes internal state.
- */
- public XMLRPCServlet()
- {
- handler = null;
- synchronizing = false;
- }
-
- /**
- * Constructor takes any java object and allows its methods
- * to be invoked via XMLRPC requests to this servlet.
- * Simply calls setHandler().
- */
- public XMLRPCServlet( Object aHandler )
- {
- this();
- setHandler( aHandler );
- }
-
- /**
- * Gets the object whose methods will be invoked to
- * handle incoming requests.
- */
- public Object getHandler()
- {
- return handler;
- }
-
- /**
- * Sets the object whose methods will be invoked to
- * handle incoming requests.
- */
- public void setHandler( Object aHandler )
- {
- handler = aHandler;
- }
-
- /**
- * Gets whether the servlet should synchonize on the
- * object before invoking methods on it.
- * Defaults to false.
- */
- public boolean isSynchronizing()
- {
- return synchronizing;
- }
-
- /**
- * Sets whether the servlet should synchonize on the
- * object before invoking methods on it.
- * Defaults to false.
- */
- public void setSynchronizing( boolean willSynchronize )
- {
- synchronizing = willSynchronize;
- }
-
- /**
- * Overridden to service the request.
- */
- protected void doPost(
- HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- if ( getHandler() != null )
- {
- InputStream input = req.getInputStream();
- byte[] copyOfRequest = null;
+ * A servlet that can make any java object into an XML-RPC server. Simply pass
+ * in the object to the constructor and XML-RPC requests to this servlet will
+ * call the appropriate methods and convert the results to an XML-RPC response.
+ * <br>
+ * <br>
+ *
+ * Depending on your servlet container, it may be necessary to create a simple
+ * subclass that creates your handler object in its constructor and then calls
+ * setHandler(). <br>
+ * <br>
+ *
+ * Responses are in the specification's standard response format.<br>
+ * <br>
+ *
+ * Faults are returned if any exception is thrown in the method, or if the
+ * specified method is not found on the object. The fault string is the toString
+ * value of the exception, and the fault code is the hasCode value of the
+ * exception. <br>
+ * <br>
+ *
+ * Remember that this servlet only responds to POSTs, per the XML-RPC spec.
+ */
+public class XMLRPCServlet extends HttpServlet {
+ protected Object handler;
+ protected boolean synchronizing;
+ private Hashtable selectorCache = new Hashtable(); // thread safe
+ private boolean copyStream = false;
+
+ /**
+ * Default constructor initializes internal state.
+ */
+ public XMLRPCServlet() {
+ handler = null;
+ synchronizing = false;
+ }
+
+ /**
+ * Constructor takes any java object and allows its methods to be invoked via
+ * XMLRPC requests to this servlet. Simply calls setHandler().
+ */
+ public XMLRPCServlet(Object aHandler) {
+ this();
+ setHandler(aHandler);
+ }
+
+ /**
+ * Gets the object whose methods will be invoked to handle incoming requests.
+ */
+ public Object getHandler() {
+ return handler;
+ }
+
+ /**
+ * Sets the object whose methods will be invoked to handle incoming requests.
+ */
+ public void setHandler(Object aHandler) {
+ handler = aHandler;
+ }
+
+ /**
+ * Gets whether the servlet should synchonize on the object before invoking
+ * methods on it. Defaults to false.
+ */
+ public boolean isSynchronizing() {
+ return synchronizing;
+ }
+
+ /**
+ * Sets whether the servlet should synchonize on the object before invoking
+ * methods on it. Defaults to false.
+ */
+ public void setSynchronizing(boolean willSynchronize) {
+ synchronizing = willSynchronize;
+ }
+
+ /**
+ * Overridden to service the request.
+ */
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (getHandler() != null) {
+ InputStream input = req.getInputStream();
+ byte[] copyOfRequest = null;
- if ( copyStream )
- {
- ByteArrayOutputStream byteArray =
- new ByteArrayOutputStream();
- int b;
- while ( ( b = input.read() ) != -1 )
- {
- byteArray.write( b );
- }
- copyOfRequest = byteArray.toByteArray();
- input = new ByteArrayInputStream( copyOfRequest );
- }
-
- try
- {
- new XMLRPCDecoder().decode( input,
- new Receiver( this, resp ) );
- }
- catch ( WotonomyException exc )
- {
- if ( copyOfRequest != null )
- {
- System.out.println( new String( copyOfRequest ) );
- exc.printStackTrace();
- }
- // catches io exceptions thrown in handleRequest.
- Throwable t = exc.getWrappedThrowable();
- if ( t instanceof IOException )
- {
- throw (IOException)t;
- }
- throw exc;
- }
- }
- }
-
- /**
- * Called by doPost after parsing an incoming request,
- * and is responsible for invoking the specified method
- * with the specified parameters on the handler object.
- * (This implementation calls getOutputStream() on the response.)
- * Override to customize the handling of the request.
- */
- protected void handleRequest( String aMethodName,
- Object[] aParameterArray, HttpServletResponse aResponse )
- {
- OutputStream output = null;
-
- try
- {
- output = aResponse.getOutputStream();
- aResponse.setStatus( HttpServletResponse.SC_OK ); // always 200
- aResponse.setContentType( "text/xml" );
- }
- catch ( IOException exc )
- {
- // caught in doPost
- throw new WotonomyException( exc );
- }
-
- // get the array of types
- XMLRPCEncoder encoder = new XMLRPCEncoder();
- Class[] types = new Class[ aParameterArray.length ];
- for ( int i = 0; i < aParameterArray.length; i++ )
- {
- types[i] = aParameterArray[i].getClass();
- }
-
- //TODO: selectors should be cached if possible
-
- Object handler = getHandler();
- if ( isSynchronizing() )
- {
- synchronized ( handler )
- {
- execute( encoder, handler, output,
- new NSSelector( aMethodName, types ), aParameterArray );
- }
- }
- else
- {
- execute( encoder, handler, output,
- new NSSelector( aMethodName, types ), aParameterArray );
- }
- }
-
- private void execute( XMLRPCEncoder anEncoder, Object aHandler,
- OutputStream output, NSSelector aSelector, Object[] aParameterArray )
- {
- try
- {
- Object result =
- aSelector.invoke( aHandler, aParameterArray );
- anEncoder.encodeResponse( result, output );
- }
- catch ( Exception exc )
- {
- anEncoder.encodeFault(
- exc.hashCode(), exc.toString(), output );
- }
- }
-
- private class Receiver implements XMLRPCReceiver
- {
- XMLRPCServlet controller;
- HttpServletResponse response;
-
- public Receiver(
- XMLRPCServlet aController,
- HttpServletResponse aResponse )
- {
- controller = aController;
- response = aResponse;
- }
-
- public void request(
- String aMethodName, Object[] aParameterArray )
- {
- controller.handleRequest(
- aMethodName, aParameterArray, response );
- }
-
- public void response(
- Object aResult )
- {
- // does nothing
- }
-
- public void fault(
- int aFaultCode, String aFaultString)
- {
- // does nothing
- }
- }
+ if (copyStream) {
+ ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+ int b;
+ while ((b = input.read()) != -1) {
+ byteArray.write(b);
+ }
+ copyOfRequest = byteArray.toByteArray();
+ input = new ByteArrayInputStream(copyOfRequest);
+ }
+
+ try {
+ new XMLRPCDecoder().decode(input, new Receiver(this, resp));
+ } catch (WotonomyException exc) {
+ if (copyOfRequest != null) {
+ System.out.println(new String(copyOfRequest));
+ exc.printStackTrace();
+ }
+ // catches io exceptions thrown in handleRequest.
+ Throwable t = exc.getWrappedThrowable();
+ if (t instanceof IOException) {
+ throw (IOException) t;
+ }
+ throw exc;
+ }
+ }
+ }
+
+ /**
+ * Called by doPost after parsing an incoming request, and is responsible for
+ * invoking the specified method with the specified parameters on the handler
+ * object. (This implementation calls getOutputStream() on the response.)
+ * Override to customize the handling of the request.
+ */
+ protected void handleRequest(String aMethodName, Object[] aParameterArray, HttpServletResponse aResponse) {
+ OutputStream output = null;
+
+ try {
+ output = aResponse.getOutputStream();
+ aResponse.setStatus(HttpServletResponse.SC_OK); // always 200
+ aResponse.setContentType("text/xml");
+ } catch (IOException exc) {
+ // caught in doPost
+ throw new WotonomyException(exc);
+ }
+
+ // get the array of types
+ XMLRPCEncoder encoder = new XMLRPCEncoder();
+ Class[] types = new Class[aParameterArray.length];
+ for (int i = 0; i < aParameterArray.length; i++) {
+ types[i] = aParameterArray[i].getClass();
+ }
+
+ // TODO: selectors should be cached if possible
+
+ Object handler = getHandler();
+ if (isSynchronizing()) {
+ synchronized (handler) {
+ execute(encoder, handler, output, new NSSelector(aMethodName, types), aParameterArray);
+ }
+ } else {
+ execute(encoder, handler, output, new NSSelector(aMethodName, types), aParameterArray);
+ }
+ }
+
+ private void execute(XMLRPCEncoder anEncoder, Object aHandler, OutputStream output, NSSelector aSelector,
+ Object[] aParameterArray) {
+ try {
+ Object result = aSelector.invoke(aHandler, aParameterArray);
+ anEncoder.encodeResponse(result, output);
+ } catch (Exception exc) {
+ anEncoder.encodeFault(exc.hashCode(), exc.toString(), output);
+ }
+ }
+
+ private class Receiver implements XMLRPCReceiver {
+ XMLRPCServlet controller;
+ HttpServletResponse response;
+
+ public Receiver(XMLRPCServlet aController, HttpServletResponse aResponse) {
+ controller = aController;
+ response = aResponse;
+ }
+
+ public void request(String aMethodName, Object[] aParameterArray) {
+ controller.handleRequest(aMethodName, aParameterArray, response);
+ }
+
+ public void response(Object aResult) {
+ // does nothing
+ }
+
+ public void fault(int aFaultCode, String aFaultString) {
+ // does nothing
+ }
+ }
}
/*
- * $Log$
- * Revision 1.1 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.1 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.1 2001/02/07 19:24:28 mpowers
- * Moved XML classes to separate package.
+ * Revision 1.1 2001/02/07 19:24:28 mpowers Moved XML classes to separate
+ * package.
*
*/
-
diff --git a/projects/net.wotonomy.web/src/test/java/net/wotonomy/web/xml/XMLRPCSelectorTest.java b/projects/net.wotonomy.web/src/test/java/net/wotonomy/web/xml/XMLRPCSelectorTest.java
index 989a7ff..726fcd0 100644
--- a/projects/net.wotonomy.web/src/test/java/net/wotonomy/web/xml/XMLRPCSelectorTest.java
+++ b/projects/net.wotonomy.web/src/test/java/net/wotonomy/web/xml/XMLRPCSelectorTest.java
@@ -1,6 +1,5 @@
package net.wotonomy.web.xml;
-
import java.io.Serializable;
import java.net.URL;
import java.util.Date;
@@ -21,49 +20,41 @@ public class XMLRPCSelectorTest extends TestCase {
super.tearDown();
}
- public static void testFoo( ) {
- try
- {
- // create url for server
- URL url = new URL( "http://localhost:8080/xmlrpctest" );
+ public static void testFoo() {
+ try {
+ // create url for server
+ URL url = new URL("http://localhost:8080/xmlrpctest");
- // set up selectors
- XMLRPCSelector getFullName =
- new XMLRPCSelector( "getFullName" );
- XMLRPCSelector getCreateDate =
- new XMLRPCSelector( "getCreateDate" );
- XMLRPCSelector setCreateDate =
- new XMLRPCSelector( "setCreateDate" );
- XMLRPCSelector getChildList =
- new XMLRPCSelector( "getChildList" );
- XMLRPCSelector setChildList =
- new XMLRPCSelector( "setChildList" );
+ // set up selectors
+ XMLRPCSelector getFullName = new XMLRPCSelector("getFullName");
+ XMLRPCSelector getCreateDate = new XMLRPCSelector("getCreateDate");
+ XMLRPCSelector setCreateDate = new XMLRPCSelector("setCreateDate");
+ XMLRPCSelector getChildList = new XMLRPCSelector("getChildList");
+ XMLRPCSelector setChildList = new XMLRPCSelector("setChildList");
- // fetch the full name
- System.out.println( getFullName.invoke( url ) );
+ // fetch the full name
+ System.out.println(getFullName.invoke(url));
- // fetch the create date
- System.out.println( getCreateDate.invoke( url ) );
- // set date to current time
- setCreateDate.invoke( url, new java.util.Date() );
- // re-fetch the create date
- System.out.println( getCreateDate.invoke( url ) );
+ // fetch the create date
+ System.out.println(getCreateDate.invoke(url));
+ // set date to current time
+ setCreateDate.invoke(url, new java.util.Date());
+ // re-fetch the create date
+ System.out.println(getCreateDate.invoke(url));
- // fetch the child list
- java.util.List childList = (java.util.List) getChildList.invoke( url );
- System.out.println( childList );
- // add a new child
- childList.add( new MockSerializableObject(new Long(5),"John","Doe", new Date()) );
- setChildList.invoke( url, childList );
- // re-fetch the child list
- System.out.println( getChildList.invoke( url ) );
- }
- catch (Exception exc)
- {
- //exc.printStackTrace();
+ // fetch the child list
+ java.util.List childList = (java.util.List) getChildList.invoke(url);
+ System.out.println(childList);
+ // add a new child
+ childList.add(new MockSerializableObject(new Long(5), "John", "Doe", new Date()));
+ setChildList.invoke(url, childList);
+ // re-fetch the child list
+ System.out.println(getChildList.invoke(url));
+ } catch (Exception exc) {
+ // exc.printStackTrace();
}
}
-
+
public static class MockSerializableObject implements Serializable {
public String firstname;
public String lastname;
@@ -77,7 +68,7 @@ public class XMLRPCSelectorTest extends TestCase {
this.id = id;
this.lastname = lastname;
}
-
+
}
-
+
}